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

}
相关推荐
晚霞的不甘11 小时前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
哈__16 小时前
CANN加速3D目标检测推理:点云处理与特征金字塔优化
目标检测·3d·目标跟踪
心疼你的一切1 天前
三维创世:CANN加速的实时3D内容生成
数据仓库·深度学习·3d·aigc·cann
3DVisionary1 天前
掌控发动机“心脏”精度:蓝光3D扫描在凸轮轴全尺寸检测中的应用
3d·图形渲染·汽车发动机·精密测量·蓝光3d扫描·凸轮轴检测·形位公差
coder攻城狮2 天前
VTK系列1:在屏幕绘制多边形
c++·3d
PHOSKEY2 天前
3D工业相机如何“读透”每一个字符?快速识别、高精度3D测量
数码相机·3d
XX風2 天前
7.2 harris 3d
3d
多恩Stone2 天前
【3D-AICG 系列-3】Trellis 2 的O-voxel (下) Material: Volumetric Surface Attributes
人工智能·3d·aigc
多恩Stone2 天前
【3D-AICG 系列-1】Trellis v1 和 Trellis v2 的区别和改进
人工智能·pytorch·python·算法·3d·aigc
三年模拟五年烧烤2 天前
easy-threesdk快速一键搭建threejs3d可视化场景
3d·threejs