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

目录

  • 说在前面
  • 移动
    • World Space
    • Local Space
  • 旋转
    • World Space
    • Local Space
  • 代码

说在前面

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

移动

World Space

  • 在世界坐标系中移动时,直接对position进行运算即可
    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方法:

    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 );
    }
    

    所以我们可以这样写:

    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中,旋转提供了方法供我们使用:
    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
    注意公式里变化量在前
    故而,世界坐标系下的旋转代码如下:
    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中,旋转提供了方法供我们局部坐标轴旋转:

    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
    注意公式里变化量在后
    因此,局部坐标系下的旋转代码可以是:

    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旋转
    在这里插入图片描述

代码

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);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/590075.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot 接收appsflyer 参数

1、官网登陆&#xff1a;hq1.appsflyer.com a、配置接收请求的地址和需要的事件 配置详情 2、Controller配置接收 RequestMapping(value "/req", method POST)ResponseBodypublic ResData req(RequestBody Map<String, String> map) {String jsonObject J…

一文搞懂什么是缓存穿透、缓存雪崩、缓存击穿三个概念,以及解决方案

先理解概念&#xff1a;【注&#xff1a;我们这里说的是分布式、高并发环境】 一、缓存穿透是什么&#xff1f; 缓存穿透是指&#xff1a;请求【可以有很多】的数据在缓存、关系型数据库中都不存在&#xff0c;每次来查询都会查询到关系型数据库中。 解决方案&#xff1a; 1、将…

CUMT--Java复习--核心类

目录 一、装箱与拆箱 二、“”与equals 三、字符串类 1、String、StringBuffer、StringBuilder的区别 2、String类 3、StringBuffer类 4、StringBuilder类 四、类与类之间关系 一、装箱与拆箱 基本类型与对应封装类之间能够自动进行转换&#xff0c;本质就是Java的自…

强烈推荐 25个 前端开源中后台管理系统

作为程序员&#xff0c;构建一套个人专属的后台管理系统非常重要。这不仅是为了打造自己独有的开发生态&#xff0c;更是因为我们正处于个人开发和AI模型泛滥的时代。利用AI增强自己的系统变得尤为关键。然而&#xff0c;在UI界面设计方面&#xff0c;我们可能需要参考开源项目…

mysql原理--Explain详解

1.概述 一条查询语句在经过 MySQL 查询优化器的各种基于成本和规则的优化会后生成一个所谓的 执行计划 &#xff0c;这个执行计划展示了接下来具体执行查询的方式&#xff0c;比如多表连接的顺序是什么&#xff0c;对于每个表采用什么访问方法来具体执行查询等等。设计 MySQL 的…

实时交通标志检测和分类(代码)

交通标志检测和分类技术是一种基于计算机视觉和深度学习的先进技术&#xff0c;能够识别道路上的各种交通标志&#xff0c;并对其进行分类和识别。这项技术在智能交通系统、自动驾驶汽车和交通安全管理领域具有重要的应用前景。下面我将结合实时交通标志检测和分类的重要性、技…

第9章 继承和派生习题(详解)

一、选择题 1&#xff0e;下列表示引用的方法中&#xff0c; &#xff08;&#xff09; 是正确的。已知&#xff1a;int m10&#xff1a; A&#xff0e;int &xm&#xff1b; B&#xff0e;int &y10&#xff1b; C&#xff0e;int &z&#xff1b; D&#xff0e;fl…

Java中利用Redis,ZooKeeper,数据库等实现分布式锁(遥遥领先)

1. 分布式锁 1.1 什么是分布式锁 在我们进行单机应用开发涉及并发同步的时候&#xff0c;我们往往采用synchronized或者ReentrantLock的方式来解决多线程间的代码同步问题。但是当我们的应用是在分布式集群工作的情况下&#xff0c;那么就需要一种更加高级的锁机制&#xff0…

合伙企业法关于合伙企业的要求

合伙协议可以载明合伙企业的经营期限和合伙人争议的解决方式。 合伙协议经全体合伙人签名、盖章后生效。合伙人依照合伙协议享有权利&#xff0c;承担责任。 经全体合伙人协商一致&#xff0c;可以修改或者补充合伙协议。 申请合伙企业设立登记&#xff0c;应当向企业登记机关提…

git rebase应用场景三

文章目录 git rebase应用场景三 git rebase应用场景三 在我们的开发分支中 假设我们修改一个文件 提交一个版本 再回到master分支 同时也去修改1.txt文件&#xff0c;提交一个版本 这样相当于master分支提交了一次&#xff0c;dev也提交了一次 然后回到dev分支 此时会报错…

事务失效的十种常见场景

学习事务失效场景 1 概述 事务的传播类型isolationTransactionnal注解属性 事务方法未被Spring管理方法使用final类型修饰非public修饰的方法同一个类中的方法相互调用方法的事务传播类型不支持事务异常被内部catch&#xff0c;程序生吞异常数据库不支持事务未配置开启事务错…

【ChatGPT 默认强化学习策略】PPO 近端策略优化算法

PPO 近端策略优化算法 PPO 概率比率裁剪 演员-评论家算法演员-评论家算法&#xff1a;多智能体强化学习核心框架概率比率裁剪&#xff1a;逐步进行变化的方法PPO 目标函数的设计重要性采样KL散度 PPO 概率比率裁剪 演员-评论家算法 论文链接&#xff1a;https://arxiv.org…

Oracle-深入了解cache buffer chain

文章目录 1.Cache buffer chain介绍2.Buffer cache的工作原理3 Buffer chains4.Multi-versioning of Buffers5.Latches6.诊断CBC latch等待7.解决 CBC Latch等待 1.Cache buffer chain介绍 经常看到会话等待事件“latch&#xff1a;cache buffers chain”。 如果想知道意味着什…

FA对接FC流程

2、FA进行对接 &#xff08;1&#xff09;首先安装好AD域控服务器DHCPDNS&#xff08;注意&#xff0c;不要忘记了做DNS正反向解析&#xff0c;就是把已经安装了ITA的主机做解析&#xff09;&#xff0c;在里面创建域用户 &#xff08;2&#xff09;安装ITA和VAG/VLB&#xf…

2024孙多勇®跨年演讲,重塑医美增长力,开启璀璨华章!

不谋万事者&#xff0c;不足谋一时&#xff1b;不谋全局者&#xff0c;不足谋一域。明者因时而变&#xff0c;智者随时而制。 12月31日-1月3日由汇成医美集团主办的&#xff0c;以“重塑医美增长力”为主题的第七届孙多勇跨年演讲暨「英雄2024」年度战略规划案&#xff0c;在中…

权威Scrum敏捷开发企业培训分享

课程简介 Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架。 这是一个两天的实训课程&#xff0c;面向研发管理者、项目经理、产品经理、研发团队等&#xff0c;旨在帮助学员全面系统地学习Scrum和敏捷开发, 帮助企业快速启动敏…

Excel模板填充:从minio上获取模板使用easyExcel填充

最近工作中有个excel导出的功能&#xff0c;要求导出的模板和客户提供的模板一致&#xff0c;而客户提供的模板有着复杂的表头和独特列表风格&#xff0c;像以往使用poi去画是非常耗时间的&#xff0c;比如需要考虑字体大小&#xff0c;单元格合并&#xff0c;单元格的格式等问…

Maya-UE xgen-UE 毛发导入UE流程整理

首先声明&#xff1a;maya建议用2022版本及一下&#xff0c;因为要用到Python 2 ,Maya2023以后默认是Python3不再支持Python2; 第一步&#xff1a;Xgen做好的毛发转成交互式Groom 第二步&#xff1a;导出刚生成的交互式Groom缓存&#xff0c;需要设置一下当前帧&#xff0c;和…

大数据与人工智能|全面数字化战略与企业数字化转型(第1节 )

要点一&#xff1a;培养跨学科思维 在分析时&#xff0c;需要采用多学科的思维方式 结果不重要&#xff0c;重要的是如何提炼现象、分析问题和得出结论的过程。 1. 介绍了锤子精神和多学科思维方式的重要性。指出了只从自身学科出发解决问题的局限性。 2. 提倡跨学科思维方式&a…

2023下半年的总结

我从八月下旬开始写的&#xff0c;到现在差不多有半年了&#xff0c;总结一下吧&#xff01; 1.计算机视觉 在计算机视觉方面&#xff0c;想必两个有名的深度学习框架&#xff08;TensorFlow和PyTorch&#xff09;大家都很清楚吧&#xff0c;以及OpenCV库。对于人脸识别&…