Three.js 在 x 和 z 轴上拖动一个模型。React three fiber

huangapple go评论50阅读模式
英文:

Three.js drag a model on x and z axis. React three fiber

问题

我正在尝试在three.js中使模型可拖动。我希望当我移动鼠标时,我的模型能跟随鼠标移动。这就是我想要实现的效果。我正在使用react-three-fiber和@use-gesture/react。

我想要实现的效果

这是我的程序的外观

我的程序

区别是相当明显的。在良好的示例中,模型会随着鼠标的移动而移动。在我的程序中,情况并非如此。

这是我的立方体的代码

const BasicOrangeBox = ({setControlsDisabled, startPosition} : BasicOrangeBoxType) => {
    const { camera } = useThree();
    const [boxPosition, setBoxPosition] = useState(startPosition)    

    const bind = useGesture({
        onDrag: ({movement: [x, y]}) => {
            setControlsDisabled(true);
            setBoxPosition( (prev) => {
                const newObj = {...prev};
                newObj.x = newObj.x0 + (x/100);
                newObj.z = newObj.z0 + (y/100);
                return newObj;
            } )
        },
        onDragEnd: () => {
            setControlsDisabled(false);
            setBoxPosition( (prev) => {
                const newObj = {...prev};
                newObj.x0 = newObj.x;
                newObj.z0 = newObj.z;
                return newObj;
            } )
        }
    })

    return (
        <mesh 
            {...bind() }
            position={[boxPosition.x, boxPosition.y, boxPosition.z]}
        >
            <boxGeometry />
            <meshBasicMaterial color={"orange"} />
        </mesh>
    )
}
英文:

I am trying to make models draggable in three.js. I want my model to follow my mouse when I move it. This is what I am trying to accomplish. I am using react-three-fiber and @use-gesture/react

What I am trying to accomplish

Here is how my program looks

My program

The difference is quite noticeable. On the good example, the model follows the mouse wherever it goes. On my program, that is not the case.

Here is my code for the cube

<!-- begin snippet: js hide: false console: false babel: false -->

<!-- language: lang-js -->

const BasicOrangeBox = ({setControlsDisabled, startPosition} : BasicOrangeBoxType) =&gt; {
    const { camera } = useThree();
    const [boxPosition, setBoxPosition] = useState(startPosition)    

    const bind = useGesture({
        onDrag: ({movement: [x, y]}) =&gt; {
            setControlsDisabled(true);
            setBoxPosition( (prev) =&gt; {
                const newObj = {...prev};
                newObj.x = newObj.x0 + (x/100);
                newObj.z = newObj.z0 + (y/100);
                return newObj;
            } )
        },
        onDragEnd: () =&gt; {
            setControlsDisabled(false);
            setBoxPosition( (prev) =&gt; {
                const newObj = {...prev};
                newObj.x0 = newObj.x;
                newObj.z0 = newObj.z;
                return newObj;
            } )
        }
    })

    return (
        &lt;mesh 
            {...bind() }
            position={[boxPosition.x, boxPosition.y, boxPosition.z]}
        &gt;
            &lt;boxGeometry /&gt;
            &lt;meshBasicMaterial color={&quot;orange&quot;} /&gt;
        &lt;/mesh&gt;
    )
}

<!-- end snippet -->

答案1

得分: 0

以下是您要翻译的内容:

Here is how I made a mesh cube draggable only on x and z axis like in a video.

Needed packages:
- three
- react-three/fiber
- use-gesture/react

First, I created a plane that spanned across my whole viewport and assigned it to a useRef

    <mesh rotation={[MathUtils.degToRad(90), 0, 0]} ref={planeRef} position={[0, -0.01, 0]}>
                <planeGeometry args={[innerWidth, innerHeight]} />
                <meshBasicMaterial color={0xfffffff} side={DoubleSide} />
    </mesh>

Then I added that ref to a useContext so I can use it in different components.

Next, I imported raycaster from useThree hook and planeRef from aforementioned useContext. 

Then I used useGesture onDrag and onDragEnd to enable and disable my OrbitControls

Inside the onDrag, I used raycaster's intersectsObject method and added an array of only one element, my plane, as a parameter. This gave me x, y, z coordinates where my mouse intersects with the plane. (Y is always 0)

Then I updated my box position.

Here is the full code snippet

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

    const BasicOrangeBox = ({setControlsDisabled, startPosition} : BasicRedBoxType) => {
        const { raycaster } = useThree();
        const [boxPosition, setBoxPosition] = useState(startPosition);
        const planeRef = useContext(PlaneContext);    

        const bind = useGesture({
            onDrag: () => {
                const intersects = raycaster.intersectObjects([planeRef]);
                if (intersects.length > 0){
                    const intersection = intersects[0];
                    console.log(intersection.point.x);
                    setBoxPosition({
                        x: intersection.point.x,
                        y: intersection.point.y,
                        z: intersection.point.z,
                    })
                }
                setControlsDisabled(true);
            },
            onDragEnd: () => {
                setControlsDisabled(false);
            }
        })

        return ( //@ts-ignore Ignores type error on next line 
            <mesh 
                {...bind() }
                position={[boxPosition.x, boxPosition.y, boxPosition.z]}
            >
                <boxGeometry />
                <meshBasicMaterial color={"orange"} />
            </mesh>
        )
    }

<!-- end snippet -->

请注意,我只提供了代码部分的翻译,不包括问题部分。如果您需要更多帮助,请随时告诉我。

英文:

Here is how I made a mesh cube draggable only on x and z axis like in a video.

Needed packages:

  • three
  • react-three/fiber
  • use-gesture/react

First, I created a plane that spanned across my whole viewport and assigned it to a useRef

&lt;mesh rotation={[MathUtils.degToRad(90), 0, 0]} ref={planeRef} position={[0, -0.01, 0]}&gt;
&lt;planeGeometry args={[innerWidth, innerHeight]} /&gt;
&lt;meshBasicMaterial color={0xfffffff} side={DoubleSide} /&gt;
&lt;/mesh&gt;

Then I added that ref to a useContext so I can use it in different components.

Next, I imported raycaster from useThree hook and planeRef from aforementioned useContext.

Then I used useGesture onDrag and onDragEnd to enable and disable my OrbitControls

Inside the onDrag, I used raycaster's intersectsObject method and added an array of only one element, my plane, as a parameter. This gave me x, y, z coordinates where my mouse intersects with the plane. (Y is always 0)

Then I updated my box position.

Here is the full code snippet

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const BasicOrangeBox = ({setControlsDisabled, startPosition} : BasicRedBoxType) =&gt; {
const { raycaster } = useThree();
const [boxPosition, setBoxPosition] = useState(startPosition);
const planeRef = useContext(PlaneContext);    
const bind = useGesture({
onDrag: () =&gt; {
const intersects = raycaster.intersectObjects([planeRef]);
if (intersects.length &gt; 0){
const intersection = intersects[0];
console.log(intersection.point.x);
setBoxPosition({
x: intersection.point.x,
y: intersection.point.y,
z: intersection.point.z,
})
}
setControlsDisabled(true);
},
onDragEnd: () =&gt; {
setControlsDisabled(false);
}
})
return ( //@ts-ignore Ignores type error on next line 
&lt;mesh 
{...bind() }
position={[boxPosition.x, boxPosition.y, boxPosition.z]}
&gt;
&lt;boxGeometry /&gt;
&lt;meshBasicMaterial color={&quot;orange&quot;} /&gt;
&lt;/mesh&gt;
)
}

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月16日 07:11:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75466281.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定