【瞎折腾/3D】无父物体下物体的旋转与移动

目录

说在前面

  • 测试环境:Microsoft Edge 120.0.2210.91
  • three.js版本:0.160.0
  • 其他:本篇文章中只探讨了无父对象下的移动与旋转,有父对象的情况将在下篇文章中讨论
  • 新年快乐!

移动

World Space

  • 在世界坐标系中移动时,直接对position进行运算即可

    javascript 复制代码
    const translationSpeed = new THREE.Vector3(0.5, 0, 0);
    // delta 为时间间隔
    cubeB.position.x += translationSpeed.x*delta;
    cubeB.position.y += translationSpeed.y*delta;
    cubeB.position.z += translationSpeed.z*delta;

    在three.js中,position为局部坐标(local position)。当物体没有父物体时,局部坐标与世界坐标相等,所以此时可以直接操作position,达到在世界坐标系中移动的效果。

  • 在下面的例子中,我们让物体先让Z轴旋转60°,再沿着世界坐标轴X移动

Local Space

  • 在局部坐标系中移动时,由于物体本身可能会旋转,所以需要进行一定的转换,在three.js中,我们可以使用translateX方法:

    javascript 复制代码
    translateOnAxis( axis, distance ) {
    	// translate object by distance along axis in object space
    	// axis is assumed to be normalized
    	// 也就是应用了物体本身的旋转角度(local space)
    	_v1.copy( axis ).applyQuaternion( this.quaternion );
    	this.position.add( _v1.multiplyScalar( distance ) );
    	return this;
    }
    
    translateX( distance ) {
    	return this.translateOnAxis( _xAxis, distance );
    }

    所以我们可以这样写:

    javascript 复制代码
    const translationSpeed = new THREE.Vector3(0.5, 0, 0);
    
    cubeB.translateX(translationSpeed.x*delta);
    cubeB.translateY(translationSpeed.y*delta);
    cubeB.translateZ(translationSpeed.z*delta);
  • 在下面的例子中,我们让物体先让Z轴旋转60°,再沿着局部坐标轴X移动

旋转

World Space

  • 在three.js中,旋转提供了方法供我们使用:

    js 复制代码
    rotateOnWorldAxis( axis, angle ) {
    	// rotate object on axis in world space
    	// axis is assumed to be normalized
    	// method assumes no rotated parent
    	_q1.setFromAxisAngle( axis, angle );
    	this.quaternion.premultiply( _q1 );
    	return this;
    }

    我们可以使用四元数来表示旋转,那么世界坐标系中的旋转公式为:
    Q n e w = Q d e l t a Q o l d Q_{new}=Q_{delta}Q_{old} Qnew=QdeltaQold
    注意公式里变化量在前
    故而,世界坐标系下的旋转代码如下:

    js 复制代码
    const rotationSpeed = new THREE.Vector3(0, Math.PI/3, 0);
    
    cubeB.rotateOnWorldAxis(_xAxis, rotationSpeed.x*delta);
    cubeB.rotateOnWorldAxis(_yAxis, rotationSpeed.y*delta);
    cubeB.rotateOnWorldAxis(_zAxis, rotationSpeed.z*delta);
  • 在下面的例子中,我们让物体先让Z轴旋转60°,再绕着世界坐标轴Y旋转

Local Space

  • 在three.js中,旋转提供了方法供我们局部坐标轴旋转:

    js 复制代码
    rotateOnAxis( axis, angle ) {
    	// rotate object on axis in object space
    	// axis is assumed to be normalized
    	_q1.setFromAxisAngle( axis, angle );
    	this.quaternion.multiply( _q1 );
    	return this;
    }

    同样,我们可以使用四元数来表示旋转,局部坐标系中的旋转公式为:
    Q n e w = Q o l d Q d e l t a Q_{new}=Q_{old}Q_{delta} Qnew=QoldQdelta
    注意公式里变化量在后

    因此,局部坐标系下的旋转代码可以是:

    js 复制代码
    const rotationSpeed = new THREE.Vector3(0, Math.PI/3, 0);
    
    cubeB.rotateX(rotationSpeed.x*delta);
    cubeB.rotateY(rotationSpeed.y*delta);
    cubeB.rotateZ(rotationSpeed.z*delta);
  • 在下面的例子中,我们让物体先让Z轴旋转60°,再绕着局部坐标轴Y旋转

代码

js 复制代码
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

let camera, scene, renderer;

scene = new THREE.Scene();

renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(15, 20, 30);
scene.add(camera);

// controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 20;
controls.maxDistance = 50;
controls.maxPolarAngle = Math.PI / 2;

// ambient light
scene.add(new THREE.AmbientLight(0x666666));

// point light
const light = new THREE.PointLight(0xffffff, 3, 0, 0);
camera.add(light);

// helper
scene.add(new THREE.AxesHelper(20));

// textures
const loader = new THREE.TextureLoader();
const texture = loader.load('textures/sprites/disc.png');
texture.colorSpace = THREE.SRGBColorSpace;

// CubeA
const meshA = new THREE.BoxGeometry(1, 1, 1);
const mateA = new THREE.MeshNormalMaterial();
const cubeA = new THREE.Mesh(meshA, mateA);
scene.add(cubeA);

// CubeB
const meshB = new THREE.BoxGeometry(1, 1, 1);
const mateB = new THREE.MeshNormalMaterial();
const cubeB = new THREE.Mesh(meshA, mateA);
scene.add(cubeB);

cubeB.position.x = 2;
cubeB.rotateZ(Math.PI/3);
cubeB.add(new THREE.AxesHelper(4));

window.addEventListener('resize', onWindowResize);

const translationSpeed = new THREE.Vector3(0.5, 0, 0);
const rotationSpeed = new THREE.Vector3(0, Math.PI/3, 0);

let preTime = Date.now();
let curTime = preTime;
let delta;

const _xAxis = /*@__PURE__*/ new THREE.Vector3( 1, 0, 0 );
const _yAxis = /*@__PURE__*/ new THREE.Vector3( 0, 1, 0 );
const _zAxis = /*@__PURE__*/ new THREE.Vector3( 0, 0, 1 );

animate();

function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);

}

function animate() {

    requestAnimationFrame(animate);

    curTime = Date.now();
    delta = (curTime - preTime)/1000;
    preTime = curTime;

    // cubeB.position.x += translationSpeed.x*delta;
    // cubeB.position.y += translationSpeed.y*delta;
    // cubeB.position.z += translationSpeed.z*delta;

    cubeB.translateX(translationSpeed.x*delta);
    cubeB.translateY(translationSpeed.y*delta);
    cubeB.translateZ(translationSpeed.z*delta);

    // cubeB.rotateX(rotationSpeed.x*delta);
    // cubeB.rotateY(rotationSpeed.y*delta);
    // cubeB.rotateZ(rotationSpeed.z*delta);

    cubeB.rotateOnWorldAxis(_xAxis, rotationSpeed.x*delta);
    cubeB.rotateOnWorldAxis(_yAxis, rotationSpeed.y*delta);
    cubeB.rotateOnWorldAxis(_zAxis, rotationSpeed.z*delta);

    render();

}

function render() {

    renderer.render(scene, camera);

}
相关推荐
足球中国5 小时前
3D STEP文件编程
3d
时空节拍AI数字人5 小时前
数字文旅补贴来了,景区申报要注意什么?
大数据·人工智能·百度·3d·ai·架构·aigc
Martina_03215 小时前
AI生成3D模型导入后只剩一个大网格?用6步完成微缩场景拆分与优化
人工智能·游戏·数学建模·3d·ai·自然语言处理·aigc
数字新视界6 小时前
国产信创动环监控系统的未来趋势分析
物联网·3d·数字孪生·三维可视化·数据可视化
成都渲染101云渲染666611 小时前
云渲染怎么用?从项目准备到提交出图,3ds Max、VRay、UE5 实用教程
3d·ue5
我才是银古1 天前
大坐标、镜像与弦高:.NET CSG 库的工程笔记
3d·cad·csg
创世虚拟世界1 天前
我做了一个 3D 虚拟世界基底,基于这个再做 3D 虚拟世界或者元宇宙,会事半功倍
javascript·人工智能·3d·gitee·虚拟现实
西红柿炖牛腩3541 天前
数字孪生大屏场景模型几个 G,Draco 3D 模型压缩和减面该怎么排顺序
3d·大屏端
3D可视化大侠1 天前
DPE 工程怎么交付到自有系统:GLB 导出与 SDK 集成实践
3d
总要学点什么1 天前
第47篇:三维特效-雷达波效果——波纹一圈圈往外推,一半却埋在地下
3d·前端框架·gis·webgl·cesium