I’m using react
and three.js
.
I want to load the downloaded glb
file and paste the image on top of it using Decal
.
For some glb
files, this was possible with a simple manipulation of z.
However, this is not possible with the current file.
If you move the position of the decal, the decal will be inside the mesh in the center of the top of the umbrella.
When scaled using the wheel, it is on top.
I don’t know what the problem is.
Below I attach my code.
import React, { useState, useRef } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
import { useGLTF, useTexture, AccumulativeShadows, RandomizedLight, Decal, Environment, Center } from '@react-three/drei'
import { easing } from 'maath'
import { useSnapshot } from 'valtio'
import { state } from './store'
export const App = ({ position = [0, 0, 2.5], fov = 25 }) => (
<Canvas shadows camera={{ position, fov }} gl={{ preserveDrawingBuffer: true }} eventSource={document.getElementById('root')} eventPrefix="client">
<ambientLight intensity={0.5} />
<Environment files="https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/potsdamer_platz_1k.hdr" />
<CameraRig>
<Backdrop />
<Center>
<Umbrella />
</Center>
</CameraRig>
</Canvas>
)
function Backdrop() {
const shadows = useRef()
useFrame((state, delta) => easing.dampC(shadows.current.getMesh().material.color, state.color, 0.25, delta))
return (
<AccumulativeShadows ref={shadows} temporal frames={60} alphaTest={0.85} scale={10} rotation={[Math.PI / 2, 0, 0]} position={[0, 0, -0.14]}>
<RandomizedLight amount={4} radius={9} intensity={0.55} ambient={0.25} position={[5, 5, -10]} />
<RandomizedLight amount={4} radius={5} intensity={0.25} ambient={0.55} position={[-5, 5, -9]} />
</AccumulativeShadows>
)
}
function CameraRig({ children }) {
const group = useRef()
const snap = useSnapshot(state)
useFrame((state, delta) => {
easing.damp3(state.camera.position, [snap.intro ? -state.viewport.width / 4 : 0, 0, 2], 0.25, delta)
easing.dampE(group.current.rotation, [state.pointer.y, -state.pointer.x / 5, 0], 0.25, delta)
})
return <group ref={group}>{children}</group>
}
function Umbrella(props) {
const snap = useSnapshot(state)
const texture = useTexture(`/${snap.decal}.png`)
const { nodes, materials } = useGLTF('/umbrella.glb')
console.log(nodes)
useFrame((state, delta) => easing.dampC(materials.initialShadingGroup.color, snap.color, 0.25, delta))
// 데칼 크기 상태
const [decalScale, setDecalScale] = useState(1.35)
// 마우스 휠 이벤트 핸들러
const handleWheel = (event) => {
// 휠 이벤트로 데칼 크기 조절
const newScale = Math.max(0.1, Math.min(3, decalScale + event.deltaY * 0.01))
setDecalScale(newScale)
}
// Decal position state
const [decalPosition, setDecalPosition] = useState([-1, -2, 8])
// Decal rotation state
const [decalRotation, setDecalRotation] = useState([0, 0, 0])
// Keyboard input handler
const handleKeyboardInput = (event) => {
const { key } = event
// Decal movement amount
const moveAmount = 0.05
switch (key) {
case 'ArrowLeft':
setDecalPosition([decalPosition[0] - moveAmount, decalPosition[1], decalPosition[2]])
setDecalRotation([0, 0, 0]) // Reset rotation when moving horizontally
break
case 'ArrowRight':
setDecalPosition([decalPosition[0] + moveAmount, decalPosition[1], decalPosition[2]])
setDecalRotation([0, 0, 0]) // Reset rotation when moving horizontally
break
case 'ArrowUp':
setDecalPosition([decalPosition[0], decalPosition[1] + moveAmount, decalPosition[2]])
setDecalRotation([0, 0, 0]) // Reset rotation when moving vertically
break
case 'ArrowDown':
setDecalPosition([decalPosition[0], decalPosition[1] - moveAmount, decalPosition[2]])
setDecalRotation([0, 0, 0]) // Reset rotation when moving vertically
break
default:
break
}
}
// Keyboard event listener
window.addEventListener('keydown', handleKeyboardInput)
return (
<group>
{/* Mesh */}
<mesh
castShadow
geometry={nodes.Object_2.geometry}
material={materials.initialShadingGroup}
material-roughness={1}
{...props}
dispose={null}
onWheel={handleWheel}
scale={0.2}>
{/* Decal */}
<Decal
mesh={nodes.Object_2} // Specify the parent mesh
position={decalPosition}
rotation={decalRotation}
scale={decalScale}
map={texture}
map-anisotropy={16}
renderOrder={1}
/>
</mesh>
</group>
)
}
useGLTF.preload('/umbrella.glb')
;['/react.png', '/three2.png', '/pmndrs.png'].forEach(useTexture.preload)
I’m writing this in case you need an umbrella file.
https://sketchfab.com/3d-models/umbrella-4754f1bc1d6341d19b313ad6a51417de#download
This code is based on another project, please let me know if you need more information or if there is something I should include.