当前位置: 首页 > 知识库问答 >
问题:

我怎么能拖动一个物体在x和z约束在y反应三/光纤与正交相机,可以通过轨道控制移动?

竺勇
2023-03-14

我希望能够在画布上拖动一个物体穿过平面(想象象棋棋盘上的一个棋子),使用反应三光纤和正交相机。

下面是一个使用固定摄像机位置的示例(不是我的):https://codepen.io/kaolay/pen/bqKjVz

但是我也希望能够移动相机-所以我添加了当对象被拖动时禁用的轨道控件。

我这里有一个代码沙盒,我的尝试基于许多其他的例子:https://codesandbox.io/s/inspiring-franklin-2r3ri?file=/src/Obj.jsx

主代码在两个文件中,即App。带有画布、摄影机和轨道控件的jsx。和Obj。jsx中包含被拖动的网格以及use手势useDrag函数中的拖动逻辑。

应用程序。jsx

import React, { useState } from "react";
import { Canvas } from "@react-three/fiber";
import Obj from "./Obj.jsx";
import { OrthographicCamera, OrbitControls } from "@react-three/drei";
import * as THREE from "three";

export default function App() {
  const [isDragging, setIsDragging] = useState(false);

  return (
    <Canvas style={{ background: "white" }} shadows dpr={[1, 2]}>
      <ambientLight intensity={0.5} />
      <directionalLight
        intensity={0.5}
        castShadow
        shadow-mapSize-height={512}
        shadow-mapSize-width={512}
      />

      <mesh rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
        <planeBufferGeometry attach="geometry" args={[10, 10]} receiveShadow />
        <meshPhongMaterial
          attach="material"
          color="#ccc"
          side={THREE.DoubleSide}
          receiveShadow
        />
      </mesh>

      <Obj setIsDragging={setIsDragging} />

      <OrthographicCamera makeDefault zoom={50} position={[0, 40, 200]} />

      <OrbitControls minZoom={10} maxZoom={50} enabled={!isDragging} />
    </Canvas>
  );
}

Obj。jsx(使用拖拽函数时包含有问题的代码)

import React, { useState } from "react";
import { useDrag } from "@use-gesture/react";
import { animated, useSpring } from "@react-spring/three";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";

function Obj({ setIsDragging }) {
  const { camera } = useThree();
  const [pos, setPos] = useState([0, 1, 0]);
  const { size, viewport } = useThree();
  const aspect = size.width / viewport.width;
  const [spring, api] = useSpring(() => ({
    // position: [0, 0, 0],
    position: pos,
    scale: 1,
    rotation: [0, 0, 0],
    config: { friction: 10 }
  }));
  const bind = useDrag(
    ({ active, delta, movement: [x, y], velocity, timeStamp, memo = 0 }) => {
      if (active) {

 //// THIS IS THE CODE THAT I KNOW IS NOT WORKING /////

        let vDir = new THREE.Vector3();
        let vPos = new THREE.Vector3(
          (x / window.innerWidth) * 2 - 1,
          -(y / window.innerHeight) * 2 + 1,
          0.5
        ).unproject(camera);

        vDir.copy(vPos).sub(camera.position).normalize();
        let flDistance = -camera.position.z / vDir.z;
        vPos = vPos.copy(camera.position).add(vDir.multiplyScalar(flDistance));
        const arbitraryFactor = 1; // I suspect this has to reflect the distance from camera in all dims...
        setPos([vPos.x * arbitraryFactor, 1.5, -vPos.y * arbitraryFactor]);

 //// END /////
      }

      setIsDragging(active);

      api.start({
        // position: active ? [x / aspect, -y / aspect, 0] : [0, 0, 0],
        position: pos,
        scale: active ? 1.2 : 1,
        rotation: [y / aspect, x / aspect, 0]
      });
      return timeStamp;
    }
  );

  return (
    <animated.mesh {...spring} {...bind()} castShadow>
      <dodecahedronBufferGeometry
        castShadow
        attach="geometry"
        args={[1.4, 0]}
      />
      <meshNormalMaterial attach="material" />
    </animated.mesh>
  );
}

export default Obj;

一些有帮助的参考资料,但还没有让我达到目的!鼠标/画布X、Y到三。js世界X,Y,Z

https://codesandbox.io/s/react-three-fiber-gestures-forked-lpfv3?file=/src/App.js: 1160-1247

https://codesandbox.io/embed/react-three-fiber-gestures-08d22?codemirror=1

https://codesandbox.io/s/r3f-lines-capture-1gkvp

https://github.com/pmndrs/react-three-fiber/discussions/641

最后再次链接到我的代码沙盒示例:https://codesandbox.io/s/inspiring-franklin-2r3ri?file=/src/Obj.jsx:0-1848

共有1个答案

谭刚毅
2023-03-14

当我意识到React Three Fiber将事件信息传递到useDrag(其中包含我所需的坐标和光线信息)后,我采取了一种不同的方法。

https://codesandbox.io/s/musing-night-wso9v?file=/src/App.jsx

应用程序。jsx

import React, { useState } from "react";
import { Canvas } from "@react-three/fiber";
import Obj from "./Obj.jsx";
import { OrthographicCamera, OrbitControls } from "@react-three/drei";
import * as THREE from "three";

export default function App() {
  const [isDragging, setIsDragging] = useState(false);
  const floorPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);

  return (
    <Canvas style={{ background: "white" }} shadows dpr={[1, 2]}>
      <ambientLight intensity={0.5} />
      <directionalLight
        intensity={0.5}
        castShadow
        shadow-mapSize-height={512}
        shadow-mapSize-width={512}
      />

      <mesh
        rotation={[-Math.PI / 2, 0, 0]}
        position={[0, -0.1, 0]}
        receiveShadow
      >
        <planeBufferGeometry attach="geometry" args={[10, 10]} receiveShadow />
        <meshPhongMaterial
          attach="material"
          color="#ccc"
          side={THREE.DoubleSide}
          receiveShadow
        />
      </mesh>

      <planeHelper args={[floorPlane, 5, "red"]} />

      <gridHelper args={[100, 100]} />

      <Obj setIsDragging={setIsDragging} floorPlane={floorPlane} />

      <OrthographicCamera makeDefault zoom={50} position={[0, 40, 200]} />

      <OrbitControls minZoom={10} maxZoom={50} enabled={!isDragging} />
    </Canvas>
  );
}

Obj。jsx

import React, { useState, useRef } from "react";
import { useDrag } from "@use-gesture/react";
import { animated, useSpring } from "@react-spring/three";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";

function Obj({ setIsDragging, floorPlane }) {
  const [pos, setPos] = useState([0, 1, 0]);
  const { size, viewport } = useThree();
  const aspect = size.width / viewport.width;

  let planeIntersectPoint = new THREE.Vector3();

  const dragObjectRef = useRef();

  const [spring, api] = useSpring(() => ({
    // position: [0, 0, 0],
    position: pos,
    scale: 1,
    rotation: [0, 0, 0],
    config: { friction: 10 }
  }));

  const bind = useDrag(
    ({ active, movement: [x, y], timeStamp, event }) => {
      if (active) {
        event.ray.intersectPlane(floorPlane, planeIntersectPoint);
        setPos([planeIntersectPoint.x, 1.5, planeIntersectPoint.z]);
      }

      setIsDragging(active);

      api.start({
        // position: active ? [x / aspect, -y / aspect, 0] : [0, 0, 0],
        position: pos,
        scale: active ? 1.2 : 1,
        rotation: [y / aspect, x / aspect, 0]
      });
      return timeStamp;
    },
    { delay: true }
  );

  return (
    <animated.mesh {...spring} {...bind()} castShadow>
      <dodecahedronBufferGeometry
        ref={dragObjectRef}
        attach="geometry"
        args={[1.4, 0]}
      />
      <meshNormalMaterial attach="material" />
    </animated.mesh>
  );
}

export default Obj;

这不应该花我这么长时间,我希望这对别人有帮助!

 类似资料:
  • 问题内容: 我将如何在SELECT查询中反转此路径: 为了 其中/是定界符,并且在一行中可以有许多定界符 问题答案: 最简单的方法可能是编写一个存储的pl / sql函数,但是可以单独使用SQL(Oracle)来完成。 这将分解子路径中的路径: 然后,我们使用来重构反向路径:

  • 我从一个网站下载了一组文件,并在blender中导出了glb、gltf和mtl文件。我可以让glb或gltf文件显示在反应三纤维场景,但我不知道如何让纹理显示正确。我遇到了几个演示,但它们看起来很旧,什么不起作用。 下面是我如何加载文件。

  • 我正在尝试使用GLTFJSX将指针事件添加到react three fiber中加载的GLTF文件中。然而,指针事件不会触发,我也不知道为什么。 我已经尝试过将相同的事件添加到其他类似的代码沙盒中,它是有效的——那么,如果我做的基本上是相同的事情,为什么在本例中它不起作用呢? https://codesandbox.io/s/hopeful-brook-h8rhs?file=/src/App.js

  • 这部分是学术性的,就我的目的而言,我只需要四舍五入到小数点后两位;但我很想知道发生了什么会产生两种略有不同的结果。 这是我编写的测试,将其缩小到最简单的实现: 但它失败了,输出如下: 有谁能详细解释一下是什么原因导致 我在一个答案中寻找的一些要点是:精度损失在哪里?哪种方法是首选的,为什么?哪一个实际上是正确的?(在纯数学中,不可能两者都是对的。也许两者都是错的?)对于这些算术运算,有没有更好的解

  • 我设置了一个动画,以在打开另一个开关/标签时隐藏一个开关/标签。同时,刚刚打开的开关向上移动。这里的简单解释非常有效。 但是,当我在开关/标签关闭后尝试向下移动时,它不会移动。另一个开关会很好地重新出现,但不会触发顶部约束更改。 我对这种类型的设置和动画都是以编程方式进行的相对较新,在花了一个小时之后,我被难住了。是因为我正在制作相对于另一个顶部约束的动画吗?如果它第一次工作,这有什么关系?即使隐

  • 我有以下功能: 此代码给出了