threejs 组-层级模型 | 本地坐标和世界坐标 | 局部坐标系和世界坐标系 | 本地矩阵.materix和世界矩阵.matrixWorld

文章目录

    • 组- THREE.Group
      • 递归遍历模型树结构object3D.traverse()
      • object3D.add (object.Object3D..) 添加对象 和 object3D.remove(object.Object3D..) 移除对象
    • 局部坐标系和世界坐标系
      • 辅助坐标器 AxesHelper
    • 本地坐标和世界坐标 - 基于世界坐标系的位置
      • 本地坐标与世界坐标的理解
    • 几何体与三维物体的三种变换:旋转,平移,缩放
      • 移动几何体和移动物体
      • 几何体旋转与三维物体旋转(缩放同理)
    • 本地矩阵.materix和世界矩阵.matrixWorld

组- THREE.Group

语法:new THREE.Group()
继承链:Object3D → Group
说明:基本和三维物体Object3D一致,可以看作一个只用于分组没有实体的模型,可以分组操作模型
作用:可以看作将模型进行分组,原来是直接将一个一个模型add进场景scene,现在是将所有模型先进行分组,然后将分组后的分组模型group添加进场景scene

受threejs历史原因,有些时候代码中也会直接用Object3D甚至Mesh作为Group使用,可以但不推荐,语义化不够强。

group可以看作mesh1mesh2的父对象,父对象旋转缩放平移变换,子对象跟着变化(父对象变换子对象也会变换)。
在这里插入图片描述

//创建两个网格模型mesh1、mesh2
const geometry = new THREE.BoxGeometry(20, 20, 20);
const material = new THREE.MeshLambertMaterial({color: 0x00ffff});
// 创建一个组
const group = new THREE.Group();
const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);
mesh2.translateX(25);
//把mesh1型插入到组group中,mesh1作为group的子对象
group.add(mesh1);
//把mesh2型插入到组group中,mesh2作为group的子对象
group.add(mesh2);
//把group插入到场景中作为场景子对象
scene.add(group);

递归遍历模型树结构object3D.traverse()

语法:object3D.traverse ( callback : Function ) : undefined
本质:遍历object3D实例的children属性

每个模型可以通过object3D.name属性命名,命名之后可以通过遍历模型树搭配object3D.getObjectByName(name) ,找到具体的模型。

案例:假设有一个小区房子
初始化状态小区房子都是蓝色的,需要将所有楼变成黄色
在这里插入图片描述

// 批量创建多个长方体表示高层楼
const group1 = new THREE.Group(); //所有高层楼的父对象
group1.name = "高层";
for (let i = 0; i < 5; i++) {const geometry = new THREE.BoxGeometry(20, 60, 10);const material = new THREE.MeshLambertMaterial({color: 0x00ffff});const mesh = new THREE.Mesh(geometry, material);mesh.position.x = i * 30; // 网格模型mesh沿着x轴方向阵列group1.add(mesh); //添加到组对象group1mesh.name = i + 1 + '号楼';// console.log('mesh.name',mesh.name);
}
group1.position.y = 30;const group2 = new THREE.Group();
group2.name = "洋房";
// 批量创建多个长方体表示洋房
for (let i = 0; i < 5; i++) {const geometry = new THREE.BoxGeometry(20, 30, 10);const material = new THREE.MeshLambertMaterial({color: 0x00ffff});const mesh = new THREE.Mesh(geometry, material);mesh.position.x = i * 30;group2.add(mesh); //添加到组对象group2mesh.name = i + 6 + '号楼';
}
group2.position.z = 50;
group2.position.y = 15;const model = new THREE.Group();
model.name='小区房子';
model.add(group1, group2);
model.position.set(-50,0,-25);// 递归遍历model包含所有的模型节点
model.traverse(function(obj) {console.log('所有模型节点的名称',obj.name);// obj.isMesh:if判断模型对象obj是不是网格模型'Mesh'if (obj.isMesh) {//判断条件也可以是obj.type === 'Mesh'obj.material.color.set(0xffff00);}
});

object3D.add (object.Object3D…) 添加对象 和 object3D.remove(object.Object3D…) 移除对象

object3D.add(object : Object3D, ...) :将参数添加到对象的children中,可以添加任意数量的对象。传入的对象如果本身有父级的话,会从原父级中删除该对象。因为一个对象仅能有一个父级
object3D.remove(object : Object3D, ... ):从当前对象的children中移除对象,可以移除任意数量的对象。

局部坐标系和世界坐标系

坐标系描述辅助坐标系器添加位置
世界坐标系只有一个,所处的公共场景添加在场景上
局部坐标系/本地坐标系物体自身的坐标系 (跟随物体)添加在三维物体上

辅助坐标器 AxesHelper

语法:new THREE.AxesHelper( size : Number )
参数:size (可选) 表示代表轴的线段长度.,默认为 1。
说明:红色®代表 X 轴. 绿色(G)代表 Y 轴. 蓝色(B)代表 Z 轴。
继承链:Object3D → Line → LineSegments

const geometry = new THREE.BoxGeometry(50,50,50)
const material = new THREE.MeshBasicMaterial({ color: 'pink' });
const axesHelper = new THREE.AxesHelper(100); 
const mesh = new THREE.Mesh(geometry, material);
mesh.add(axesHelper)  // 本地坐标系添加在三维物体上
mesh.position.set(25,25,25); // 为了方便观察,将三维物体的位置移动
scene.add(mesh);
const worldAxesHelper = new THREE.AxesHelper(150);
scene.add(worldAxesHelper);// 世界坐标系添加在场景上

在这里插入图片描述

本地坐标和世界坐标 - 基于世界坐标系的位置

这里的本地坐标和世界坐标是相对于有无父元素来说,坐标都是基于世界坐标系的位置

打印上述案例的世界坐标与本地坐标,有以下两个发现:
1.可以看见本地坐标变了,但本地坐标系位置是没有变化的。 => 基于世界坐标的位置
2.打印世界坐标与本地坐标,可以发现都是一样的。 => 不一样的情况只是针对有无父元素

const geometry = new THREE.BoxGeometry(50,50,50)
const material = new THREE.MeshBasicMaterial({ color: 'pink' });
const axesHelper = new THREE.AxesHelper(100); 
const mesh = new THREE.Mesh(geometry, material);
mesh.add(axesHelper)  // 本地坐标系
mesh.position.set(25,25,25)
scene.add(mesh);
const worldAxesHelper = new THREE.AxesHelper(150);
scene.add(worldAxesHelper);// 世界坐标系
console.log("世界坐标",mesh.getWorldPosition(new THREE.Vector3()));
console.log("本地坐标",mesh.position);

在这里插入图片描述

获取世界坐标的语法
object.getWorldPosition(Vector3) 获取世界坐标
语法:object.getWorldPosition(Vector3)
描述:读取一个模型的世界坐标,并把读取结果存储到参数Vector3中

本地坐标与世界坐标的理解

同一个三维物体拥有本地坐标与世界坐标两个坐标,在页面看见的位置是世界坐标的位置。

-定义
本地坐标三维物体的.position属性
世界坐标三维物体自身.position和所有父对象.position累加的坐标
  • 改变子对象的.position,子对象在3D空间中的坐标会发生改变。
  • 改变父对象的.position,子对象在3D空间中的位置也会跟着变化,也就是说父对象.position和子对象.position叠加才是才是子对象的世界坐标。
const geometry = new THREE.BoxGeometry(50,50,50)
const material = new THREE.MeshBasicMaterial({ color: 'pink' });
const axesHelper = new THREE.AxesHelper(60); 
const mesh = new THREE.Mesh(geometry, material);
mesh.add(axesHelper);
mesh.position.set(25,0,0) // 改变子元素的本地坐标
const group = new THREE.Group();
group.add(mesh);
scene.add(group);
group.position.set(0,25,0) // 改变父元素的本地坐标
const axesHelper1 = new THREE.AxesHelper(150);
scene.add(axesHelper1);
console.log("世界坐标",mesh.getWorldPosition(new THREE.Vector3()));
console.log("本地坐标",mesh.position);

在这里插入图片描述

几何体与三维物体的三种变换:旋转,平移,缩放

BufferGeometry重写了Object3D的同名方法,几何变换的本质是改变几何体的顶点数据

几何变换描述
bufferGeometry.scale ( x : Float, y : Float, z : Float )从几何体原始位置开始缩放几何体
bufferGeometry.translate ( x : Float, y : Float, z : Float )从几何体原始位置开始移动几何体,本质改变的是顶点坐标
bufferGeometry.rotateX/rotateY/rotateZ( radians : Float )沿着局部坐标系的主轴旋转几何体,参数是弧度

移动几何体和移动物体

一般情况下选择移动物体。当顶点本身就偏离需要将几何体中心移动到原点时,选择移动几何体(消除中心点偏移)。
几何体的变换由于直接将最终计算结果设置为顶点坐标,所以很难追逐到是否发生了变换

-使用描述特点
移动几何体bufferGeometry.translate (x: Float, y: Float, z: Float)改变几何体,geometry.attributes.position属性顶点改变,局部位置不变
移动物体object3D.position: Vector3
object3D.translateX ( distance : Float )
移动对象的局部位置局部位置改变,局部坐标系跟随

移动几何体
1.几何体顶点变化
2.局部坐标不变,局部坐标系不变。

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-50, 50, 0, 50, 50, 0, -50, -50, 0,50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial();
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
bufferGeometry.translate(50,0,0)  // 移动几何体:x轴加50
scene.add(bufferPlane);const axesHelper = new THREE.AxesHelper(100); 
bufferPlane.add(axesHelper)  
const worldAxesHelper = new THREE.AxesHelper(150);
scene.add(worldAxesHelper);
// 物体的局部坐标仍然在(0,0,0),局部坐标系也没变化(与世界坐标重叠)  几何体的顶点坐标x轴都加了50
console.log(bufferPlane.position,bufferGeometry.attributes.position.array)

在这里插入图片描述

移动三维物体
1.几何体顶点不变
2.局部坐标变化,局部坐标系跟随。

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-50, 50, 0, 50, 50, 0, -50, -50, 0,50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial();
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
bufferPlane.translateX (50); // 移动物,沿世界坐标系的x轴移动50个单位
scene.add(bufferPlane);
const axesHelper = new THREE.AxesHelper(100); 
bufferPlane.add(axesHelper)  
const worldAxesHelper = new THREE.AxesHelper(150);
scene.add(worldAxesHelper);
console.log(bufferPlane.position,bufferGeometry.attributes.position.array)

在这里插入图片描述

几何体旋转与三维物体旋转(缩放同理)

-方法本质修改特点
几何体旋转bufferGeometry.rotateX( rad : Float)顶点坐标1.局部坐标系不变。
2.object3D.rotation 不变。
3.几何体的顶点位置改变。
物体旋转object3D.rotateX/.rotateY /.rotateZ ( rad : Float)
设置该属性值:object3D.rotation : Euler
绕空间坐标系的轴旋转
局部坐标系会一起旋转
修改object3D.rotation: Euler属性1.局部坐标系跟随三维物体一起旋转。
2.object3D.rotation 改变。
3.几何体的顶点位置不变。

几何体旋转
1.局部坐标系不变。
2.object3D.rotation 不变。
3.几何体的顶点位置改变。

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-50, 50, 0, 50, 50, 0, -50, -50, 0,50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial({side:THREE.DoubleSide,
});
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
bufferPlane.position.set(25,0,0); //为了方便观察局部坐标系,这里移动三维物体
bufferGeometry.rotateX(Math.PI / 2);// 几何体旋转
scene.add(bufferPlane);const axesHelper = new THREE.AxesHelper(100); 
bufferPlane.add(axesHelper)  
const worldAxesHelper = new THREE.AxesHelper(150);
scene.add(worldAxesHelper);
console.log(bufferPlane.position,bufferPlane.rotation,bufferGeometry.attributes.position.array)

在这里插入图片描述

三维物体的旋转
1.局部坐标系跟随三维物体一起旋转。
2.object3D.rotation 改变。
3.几何体的顶点位置不变。

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-50, 50, 0, 50, 50, 0, -50, -50, 0,50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial({side:THREE.DoubleSide,
});
const bufferPlane = new THREE.Mesh(bufferGeometry, material);bufferPlane.position.set(25,0,0); //为了方便观察局部坐标系,这里移动三维物体
bufferPlane.rotateX(Math.PI / 2) // 物体旋转
scene.add(bufferPlane);const axesHelper = new THREE.AxesHelper(100); 
bufferPlane.add(axesHelper)  
const worldAxesHelper = new THREE.AxesHelper(150);
scene.add(worldAxesHelper);
console.log(bufferPlane.position,bufferPlane.rotation,bufferGeometry.attributes.position.array)

在这里插入图片描述

本地矩阵.materix和世界矩阵.matrixWorld

可以类比本地坐标与世界坐标,物体的运动参考坐标系永远是世界坐标系。

-定义属性
本地矩阵三维物体的旋转、平移和缩放变换,本地矩阵materix是平移矩阵、缩放矩阵和旋转矩阵的乘积。object3D.matrix: Matrix4 默认是4*4的单位矩阵
世界坐标三维物体自身本地矩阵及其所有所有祖宗对象本地矩阵的乘积,或者每一个对象的世界矩阵是对象本地矩阵和父对象的世界矩阵的乘积。object3D.matrixWorld : Matrix4

更新本地矩阵属性object3D.updateMatrix():提取位置.positon、缩放.scale、四元数.quaternion转化为变换矩阵,然后矩阵的乘积设置为本地矩阵。
更新世界矩阵属性object3D.updateMatrixWorld ( force : Boolean ),①会更新该三维物体的本地矩阵属性,②本地矩阵与父对象的世界矩阵做乘积,③依次更新该三维物体后代的世界矩阵(迭代①②③)。

执行渲染器的render()方法时,会自动更新场景对象scene所有子孙对象的世界矩阵与本地矩阵

三维物体的变换
由基本变换的属性和改变属性的方法组成

变换方法本地矩阵
平移object3D.position: Vector3
object3D.translateX ( distance : Float )
object3D.translateY ( distance : Float )
object3D.translateZ ( distance : Float )
平移矩阵:下列矩阵的转置在这里插入图片描述
缩放object3D.scale : Vector3在这里插入图片描述
旋转角度属性object3D.rotation : Euler等价于 四元数属性object3D.quaternion: Quaternion
封装了一些改变属性的方法:
object3D.rotateX (rad : Float)
object3D.rotateY (rad : Float)
object3D.rotateZ (rad : Float)

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

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

相关文章

Redis7(二)数据类型及其用法

一、概述 命令不区分大小写&#xff0c;key区分大小写 数据类型针对value String List Set Hash ZSet bitmap GEO HyperLogLog Stream bitfield 二、String <K,V> 1、设值/取值 getrange key index1 index2 getrange key 0 -1//获取所有的值 SETRANGE KEY_N…

XC7A35T-2FGG484 嵌入式FPGA现场可编程门阵列 Xilinx

XC7A35T-2FGG484 是一款由Xilinx&#xff08;赛灵思&#xff09;制造的FPGA&#xff08;现场可编程门阵列&#xff09;芯片 以下是XC7A35T-2FGG484 的主要参数&#xff1a; 1. 系列&#xff1a;Artix-7 2. 逻辑单元数量&#xff1a;33280个 3. 工艺技术&#xff1a;28nm 4. …

Linux 5.10 Pstore 功能测试

目录 简介环境配置内核配置参考备注 简介 Pstore(Persistent store support)是用于系统发生oops或panic时&#xff0c;自动保存内核log buffer中的日志。随着功能不断完善&#xff0c;Duo S使用Linux 5.10已经支持保存console日志、ftrace消息和用户空间日志的收集&#xff0c…

STC89C52学习笔记(三)

STC89C52学习笔记&#xff08;三&#xff09; 综述&#xff1a;本文讲述了通过51单片机控制LED闪烁、流水灯、按键控制LED亮灭、按键控制LED实现二进制、按键控制LED左右移。 一、LED 1.LED闪烁 1&#xff09;LED电路原理 LED采用共阳极&#xff0c;当LED另一端为低电平时…

前端二维码工具小程序产品使用说明书

一、产品概述 前端二维码工具小程序是一款便捷实用的二维码生成与识别工具&#xff0c;通过本小程序&#xff0c;用户可以轻松根据文本或链接生成二维码&#xff0c;并支持扫一扫功能识别二维码内容&#xff0c;同时提供复制识别内容的功能。此外&#xff0c;本小程序还具备美…

登录信息失效后多次请求提示合并成一次

在通常的业务场景中经常会出现进入页面之后一次性发送好多个请求,如果登录信息失效,那就会出现很多提示 类似这种多个提示的,看起来不美观,希望改成可以把在短时间内出现相同的错误信息,只提示一次,其他的就不提示了 实现思路 通常业务中每一个请求的code都是有具体的意思,可以…

网络安全 | 什么是区块链?

关注WX&#xff1a;CodingTechWork 概述 定义 区块链是一个共享的、不可篡改的账本&#xff0c;旨在促进业务网络中的交易记录和资产跟踪流程。资产可以是有形的&#xff08;如房屋、汽车、现金、土地&#xff09;&#xff0c;也可以是无形的&#xff08;如知识产权、专利、…

【记录】LangChain|llama 2速通版

官方教程非常长&#xff0c;我看了很认可&#xff0c;但是看完了之后呢就需要一些整理得当的笔记让我自己能更快地找到需求。所以有了这篇文章。【写给自己看的&#xff0c;里面半句废话的解释都没有&#xff0c;如果看不懂的话直接看官方教程再看我的】 我是不打算一开始就用…

RabbitMQ基本使用及企业开发中注意事项

目录 一、基本使用 二、使用注意事项 1. 生产者重连机制 - 保证mq服务是通的 2. 生产者确认机制 - 回调机制 3. MQ的可靠性 4. Lazy Queue模式 5. 消费者确认机制 一、基本使用 部署完RabbitMQ有两种使用方式&#xff1a; 网页客户端Java代码 MQ组成部分&#xff1a;…

Verilog语法——按位取反“~“和位宽扩展的优先级

前言 先说结论&#xff0c;如下图所示&#xff0c;在Verilog中“~ ”按位取反的优先级是最高的&#xff0c;但是在等式计算时&#xff0c;有时候会遇到位宽扩展&#xff0c;此时需要注意的是位宽扩展的优先级高于“~”。 验证 仿真代码&#xff0c;下面代码验证的是“~”按位取…

ChernoCPP 2

视频链接&#xff1a;【62】【Cherno C】【中字】C的线程_哔哩哔哩_bilibili 参考文章&#xff1a;TheChernoCppTutorial_the cherno-CSDN博客 Cherno的C教学视频笔记&#xff08;已完结&#xff09; - 知乎 (zhihu.com) C 的线程 #include<iostream> #include<th…

【攻防世界】catcat-new

首先进入环境&#xff0c;这是一个介绍猫的网站&#xff1a; 网站的URL没有发现问题&#xff0c;使用dirsearch对网站进行扫描&#xff0c;看是否有可以访问的窗口&#xff1a; 发现 /admin 可以访问&#xff0c;我们尝试访问&#xff1a; /admin中没有flag。我们返回初始界面&…

Redis数据库的简介、部署及常用命令

关系数据库与非关系型数据 关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。sQL语句&#xff08;标准数据查询语言&#xff09;就是一种基于关系型数据库的语言&#xff0c…

LangChain - OpenGPTs

文章目录 MessageGraph 消息图认知架构AssistantsRAGChatBot 持久化配置新模型新工具astream_events总结 关键链接&#xff1a; OpenGPT GitHub 存储库YouTube 上的 OpenGPT 演练LangGraph&#xff1a;Python、JS 两个多月前&#xff0c;在 OpenAI 开发日之后&#xff0c;我们…

项目管理中的估算活动资源

在项目管理中&#xff0c;资源估算是一项至关重要的任务。正确地估算活动资源可以确保项目的顺利进行&#xff0c;避免资源浪费和不必要的延误。以下是对项目管理中常见的活动资源类型的详细分析。 一、人力资源 人力资源是项目管理中最基本的资源之一。它包括项目团队成员的…

Linux gcc day5粘滞位

粘滞位 背景&#xff1a;一定时在一个公共目录&#xff08;root创建&#xff09;下。进行临时文件的操作 Linux系统中有很多人&#xff0c;我们需要在一个公共目录下&#xff0c;进行临时文件的操作&#xff08;增删查改&#xff09; 创建一个根目录下的dir&#xff08;mytmp…

指针的深入理解(六)

指针的深入理解&#xff08;六&#xff09; 个人主页&#xff1a;大白的编程日记 感谢遇见&#xff0c;我们一起学习进步&#xff01; 文章目录 指针的深入理解&#xff08;六&#xff09;前言一. sizeof和strlen1.1sizeof1.2strlen1.3sizeof和strlen对比 二.数组名和指针加减…

Java变量详解

​ 这里写目录标题 第一章、Java中的变量分类1.1&#xff09;变量分类1.2&#xff09;成员变量分类1.3&#xff09;成员变量和局部变量的区别 第二章、成员变量详解2.1&#xff09;成员变量作用域/权限修饰符2.2&#xff09;成员变量和成员属性的区别2.3&#xff09;成员变量初…

是否有替代U盘,可安全交换的医院文件摆渡方案?

医院内部网络存储着大量的敏感医疗数据&#xff0c;包括患者的个人信息、病历记录、诊断结果等。网络隔离可以有效防止未经授权的访问和数据泄露&#xff0c;确保这些敏感信息的安全。随着法律法规的不断完善&#xff0c;如《网络安全法》、《个人信息保护法》等&#xff0c;医…

spring事务那些事

实际工作中还会面临千奇百怪的问题&#xff0c;看下面返个例子&#xff08;注意MySql数据库测试&#xff09;&#xff1a; //1.hello1Service 调用 hello2Service Transactional(propagation Propagation.REQUIRED,rollbackFor Exception.class) public void doUpdate() {//…