Three开关门

一. 我们在使用Three想要达成开关门动作时,如何避坑?

 

图一为我们理想例子

图二图三为非理想例子

二. Three开关门如何点击获取该模型?

1. 我们以双击触发该事件,通过鼠标xy轴在屏幕创建three向量位置;

2. 将创建屏幕坐标转换为Three场景中的坐标;

3. 通过THREE.Raycaster发射光线获取到点击模型;

4. 通过TWEEN动画旋转该模型父级场景(重点为旋转父级场景,自身旋转可就如图二喽)rotationY角度;

document.addEventListener('dblclick', onDocumentMouseDown, false);
// 获取与射线相交的对象数组
  const onDocumentMouseDown = (event) => {
    event.preventDefault();
    //1、先基于我们在屏幕上点击的位置创建一个向量
    var vector = new THREE.Vector3(
      (event.clientX / window.innerWidth) * 2 - 1,
      -(event.clientY / window.innerHeight) * 2 + 1,
      0.5
    );
    //2、然后用unproject函数将点击位置转换成Thres.js场景中的坐标
    vector = vector.unproject(Three.camera);
    //3、用THREE.Raycaster对象向点击位置发射光线
    var raycaster = new THREE.Raycaster(Three.camera.position, vector.sub(Three.camera.position).normalize());
    var intersects = raycaster.intersectObjects(Three.scene.children, true);

    var currObj = intersects[0].object; //currObj为点击到的第一个对象
    if (currObj.parent.rotation.y == 0) {
      new TWEEN.Tween(currObj.parent.rotation)
        .to(
          {
            y: 1.5,
          },
          1500
        )
        .start();
    } else {
      new TWEEN.Tween(currObj.parent.rotation)
        .to(
          {
            y: 0,
          },
          300
        )
        .start();
    }
  };

 三. 模型核心场景代码

1. 重点在于mesh与menGroup;mesh为门模型,menGroup为mesh父级场景;

  1.  门宽为40,模型默认在中心轴上那么中心轴的位置在门20的位置;
  2. 我们建立父级场景menGroup将门mesh包裹;
  3. 父级menGroup向右平移20,此时menGroup中心轴在门右侧门框上,随着父级平移,mesh作为子级也会平移,此时我们将mesh门本身向左平移-20,门又回到了原始位置,但是父级menGroup的中心轴还停留在右侧门框;
  4. 此时参考上边currObj.parent.rotation代码,我们获取到门之后旋转父级,大功告成;
  5. 注意事项:不平移自转为图二,平移计算不对为图三;
// 立方体
  const cube = () => {
    const cubeSize = 40;
    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, 1);
    const cubeMat = new THREE.MeshPhongMaterial({ color: '#8AC' });
    const mesh = new THREE.Mesh(cubeGeo, cubeMat); // 创景门模型
    mesh.position.set(-cubeSize / 2, 0, 0);

    const menGroup = new THREE.Group();
    menGroup.position.set(cubeSize, 0, 0);
    menGroup.add(mesh);
    
    Three.scene.add(menGroup);
  };

 四. react版全部代码

import React, { useRef, useEffect, useMemo } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import TWEEN from 'tween/tween.js';

const ThreeRoom = () => {
  const createDom = useRef(null);
  const ThreeModel = useRef({
    scene: null,
    camera: null,
    renderer: null,
    controller: null,
  });
  const Three = ThreeModel.current;

  // 相机加载
  const cameraInit = () => {
    Three.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
    Three.camera.position.set(0, 50, 50);
    // Three.camera.lookAt(0, 0, 0);
  };

  // 渲染器实例
  const renderer = () => {
    Three.renderer = new THREE.WebGL1Renderer();
    Three.renderer.setSize(createDom.current.clientWidth,         createDom.current.clientHeight);
    Three.renderer.setPixelRatio(window.devicePixelRatio);
    Three.renderer.setClearAlpha(0);
    Three.renderer.setClearColor('rgb(135,206,250)', 1.0);
    Three.renderer.setClearColor(0xffffff, 1.0);
    Three.renderer.setClearColor('#428bca', 1.0);
    Three.renderer.setClearColor('rgba(135,206,250,0.5)', 1.0);
    createDom.current.appendChild(Three.renderer.domElement);
  };

  // 加载场景
  const animate = () => {
    requestAnimationFrame(animate);
    // if (resizeRendererToDisplaySize(Three.renderer)) {
    //   Three.camera.aspect = window.innerWidth / window.innerHeight;
    //   Three.camera.updateProjectionMatrix();
    // }
    TWEEN.update();
    Three.renderer.render(Three.scene, Three.camera);
  };

  // 立方体
  const cube = () => {
    const cubeSize = 40;
    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, 1);
    const cubeMat = new THREE.MeshPhongMaterial({ color: '#8AC' });

    const mesh = new THREE.Mesh(cubeGeo, cubeMat); // 创景门模型
    mesh.position.set(-cubeSize / 2, 0, 0);
    const menGroup = new THREE.Group();
    menGroup.position.set(cubeSize, 0, 0);
    menGroup.add(mesh);

    Three.scene.add(menGroup);
  };

  // 加载控制器
  const controls = () => {
    Three.controller = new OrbitControls(Three.camera, Three.renderer.domElement);
    Three.controller.maxDistance = 2000;
  };

  useEffect(() => {
    Three.scene = new THREE.Scene();
    cameraInit();
    cube();
    renderer();
    controls();
    const light = new THREE.AmbientLight(0xffffff, 1);
    Three.scene.add(light);
    animate();
    document.addEventListener('dblclick', onDocumentMouseDown, false);
  }, []);

  // 获取与射线相交的对象数组
  const onDocumentMouseDown = (event) => {
    event.preventDefault();
    //1、先基于我们在屏幕上点击的位置创建一个向量
    var vector = new THREE.Vector3(
      (event.clientX / window.innerWidth) * 2 - 1,
      -(event.clientY / window.innerHeight) * 2 + 1,
      0.5
    );
    //2、然后用unproject函数将点击位置转换成Thres.js场景中的坐标
    vector = vector.unproject(Three.camera);
    //3、用THREE.Raycaster对象向点击位置发射光线
    var raycaster = new THREE.Raycaster(Three.camera.position, vector.sub(Three.camera.position).normalize());
    var intersects = raycaster.intersectObjects(Three.scene.children, true);

    var currObj = intersects[0].object; //currObj为点击到的第一个对象
    if (currObj.parent.rotation.y == 0) {
      new TWEEN.Tween(currObj.parent.rotation)
        .to(
          {
            y: 1.5,
          },
          1500
        )
        .start();
    } else {
      new TWEEN.Tween(currObj.parent.rotation)
        .to(
          {
            y: 0,
          },
          300
        )
        .start();
    }
  };

  return <div style={{ width: '100%', height: '100%' }} id="scene" ref={createDom} />;
};

export default ThreeRoom;

 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用 Three.js 创建一个门的动画效果。首先,你需要创建一个门的模型,可以通过 Three.js 中的 BoxGeometry 来创建。然后,你可以创建两个门的模型,一个是静止的门,另一个是动态的门。 接下来,你需要为动态的门创建一个动画序列,当门打开时播放该序列。你可以使用 Three.js 中的 AnimationMixer 类来创建动画序列。你需要定义门的动画序列,例如门打开时旋转或平移的开始和结束位置。 最后,你需要将动态门模型添加到场景中,并在需要时播放动画序列。你可以通过 Three.js 中的 Object3D 类来控制门的位置和旋转。 以下是一个简单的 Three.js 开关门的示例代码: ```javascript var scene, camera, renderer; var door, doorOpen, mixer; function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); camera.position.set(0, 0, 5); var geometry = new THREE.BoxGeometry(2, 3, 0.1); var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); door = new THREE.Mesh(geometry, material); scene.add(door); var geometry2 = new THREE.BoxGeometry(2, 3, 0.1); var material2 = new THREE.MeshBasicMaterial({ color: 0xff0000 }); doorOpen = new THREE.Mesh(geometry2, material2); scene.add(doorOpen); doorOpen.visible = false; var animateDoor = new THREE.AnimationClip("door", 2, [ new THREE.VectorKeyframeTrack( ".position", [0, 1, 2], [ 0, 0, 0, 0, 2, 0, 0, 2, -2 ] ), new THREE.QuaternionKeyframeTrack( ".quaternion", [0, 1, 2], [ 0, 0, 0, 1, 0, 0.707, 0, 0.707, 0.707, 0, 0, 0.707 ] ) ]); mixer = new THREE.AnimationMixer(doorOpen); mixer.clipAction(animateDoor).setDuration(2).play(); renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); animate(); } function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); mixer.update(0.01); } function openDoor() { door.visible = false; doorOpen.visible = true; } function closeDoor() { door.visible = true; doorOpen.visible = false; } ``` 在这个例子中,我们创建了两个门模型,door 和 doorOpen。door 是静态的门,doorOpen 是动态的门。我们为 doorOpen 创建了一个动画序列 animateDoor,使其在 2 秒内从开始位置旋转到结束位置。 在 animate 函数中,我们更新动画序列 mixer 并渲染场景。在 openDoor 和 closeDoor 函数中,我们切换门的可见性,以显示或隐藏门。 你可以使用以下代码调用 openDoor 和 closeDoor 函数来打开或关闭门: ```javascript openDoor(); // 打开门 closeDoor(); // 关闭门 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值