【瞎折腾/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);

}
相关推荐
fanged6 小时前
Cesium4--地形(OSGB到3DTiles)
3d·gis·web
桃花键神11 小时前
从传统到智能:3D 建模流程的演进与 AI 趋势 —— 以 Blender 为例
人工智能·3d·blender
东风西巷14 小时前
全能的3D创作平台,Blender(免费开源3D建模工具)
学习·3d·开源·blender·软件需求
查里王19 小时前
AI 3D 生成工具知识库:当前产品格局与测评总结
人工智能·3d
Hello123网站1 天前
Champ-基于3D的人物图像到动画视频生成框架
3d·ai工具
Magnum Lehar1 天前
3d wpf游戏引擎的导入文件功能c++的.h实现
3d·游戏引擎·wpf
博图光电1 天前
Motioncam Color S + 蓝激光:3D 视觉革新,重塑工业与科研应用新格局
3d
新启航光学频率梳1 天前
[新启航]深孔加工尺寸精度检测方法 - 激光频率梳 3D 轮廓测量
科技·3d·制造
eqwaak01 天前
Matplotlib 动画显示进阶:交互式控制、3D 动画与未来趋势
python·tcp/ip·3d·语言模型·matplotlib
LabVIEW开发1 天前
LabVIEW加载 STL 模型至 3D 场景 源码见附件
3d·labview·labview知识·labview功能·labview程序