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); //添加到组对象group1
    mesh.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); //添加到组对象group2
    mesh.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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

常用的深度学习自动标注软件

0. 简介 自动标注软件是一个非常节省人力资源的操作&#xff0c;而随着深度学习的发展&#xff0c;这些自动化标定软件也越来越多。本文章将会着重介绍其中比较经典的自动标注软件 1. AutoLabelImg AutoLabelImg 除了labelimg的初始功能外&#xff0c;额外包含十多种辅助标注…

机器人码垛机:科技创新推动物流行业飞跃发展

在数字化、智能化浪潮的推动下&#xff0c;机器人技术已成为推动各行各业转型升级的重要力量。特别是在物流行业&#xff0c;机器人码垛机的应用正逐渐普及&#xff0c;以其高效、精准、节省人力的特点&#xff0c;助力物流行业实现跨越式发展。星派将介绍机器人码垛机如何助力…

nacos分布式程序开发实例

1.通过windows docker desktop 完成 nacos 的安装/启动/配置 &#xff08;1&#xff09;先安装docker desktop docker-toolbox-windows-docker-for-windows-stable安装包下载_开源镜像站-阿里云 &#xff08;2&#xff09;配置docker 国内镜像源 Docker 镜像加速 | 菜鸟教程…

C++ list链表模拟实现

目录 前言&#xff1a; 模拟实现&#xff1a; 迭代器的实现&#xff1a; list类功能函数实现&#xff1a; 初始化成空函数&#xff08;empty_init&#xff09;&#xff1a; 构造函数&#xff1a; 拷贝构造函数&#xff1a; 尾插&#xff08;push_back&#xff09;: 插入…

【触想智能】工业一体机和普通电脑的区别是什么?

工业一体机和普通电脑的区别是什么&#xff0c;工业一体机可以当普通电脑一样使用吗? 要想了解工业一体机和普通电脑的区别是什么?我们首先来看看工业一体机是什么&#xff0c;它跟普通电脑有哪些相似的地方?下面小编就为大家来详细介绍一下。 在工作原理上&#xff0c;工业…

GFS分布式 文件系统

一、GFS的概念 文件存储分为nfs、lvm、raid 对象存储分为GFS、CEPH、fastDFS&#xff08;分布式文件存储&#xff09;NAS OSS S3 switch OSS 属于阿里云 通过URL 链接 S3属于亚马逊通过URL链接 1.1 GFS简介 开源的分布式文件系统&#xff0c;由存储服务器、客户端…

Pillow教程11:九宫格切图的实现方法(安排!!!)

---------------Pillow教程集合--------------- Python项目18&#xff1a;使用Pillow模块&#xff0c;随机生成4位数的图片验证码 Python教程93&#xff1a;初识Pillow模块&#xff08;创建Image对象查看属性图片的保存与缩放&#xff09; Pillow教程02&#xff1a;图片的裁…

xv6源码分析 003

xv6源码分析 003 在开始今晚的内容之前我先纠正以下昨天的一个错误 struct cmd {int type; };代表的是在sh.c开头就定义的宏常量&#xff0c;系统调用号是通过汇编代码来传入的。修改之后的内容如下&#xff1a; 好啦&#xff0c;我们继续昨晚的内容吧。 在sh.c 的 main函数中…

大屏可视化展示平台解决方案(word原件获取)

1.系统概述 1.1.需求分析 1.2.重难点分析 1.3.重难点解决措施 2.系统架构设计 2.1.系统架构图 2.2.关键技术 2.3.接口及要求 3.系统功能设计 3.1.功能清单列表 3.2.数据源管理 3.3.数据集管理 3.4.视图管理 3.5.仪表盘管理 3.6.移动端设计 3.1.系统权限设计 3.2.数据查询过程设…

如何使用vscode启动Flask并实现无公网IP远程访问内网服务

文章目录 1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 本篇文章主要讲解如何在本地安装Flask&#xff0c;以及如何将其web界面发布到公网进行远程访问。 Flask是目前十分流行的web框架&#xff0c;采用Python编程语…

linux网络服务学习(5):iscsi

1.什么是iscsi 1.1 scsi SCSI是一种I/O技术&#xff0c;规范了一种并行的I/O总线和相关协议&#xff08;scsi协议&#xff09;。 SCSI总线通过SCSI控制器&#xff08;target&#xff09;来和硬盘之类的设备&#xff08;scsi设备&#xff09;进行通信&#xff0c;访问的客户端…

图形学物体拾取:CPU VS GPU

一、CPU – raycaster 射线包围盒是一种常用的方法&#xff0c;在 CPU 中进行拾取&#xff0c;性能较好&#xff0c;但是精度较差。当拾取频率不高时&#xff0c;可以考虑使用像素级精度的帧缓冲拾取Framebuffer Picker.射线投射涉及将射线投射到场景中并检查对象和射线之间的…

K8s技术全景:架构、应用与优化

一、介绍 Kubernetes的历史和演进 Kubernetes&#xff08;简称K8s&#xff09;是一个开源的容器编排系统&#xff0c;用于自动化应用程序的部署、扩展和管理。它最初是由Google内部的Borg系统启发并设计的&#xff0c;于2014年作为开源项目首次亮相。 初始阶段 Kubernetes的诞生…

网站想使用https安全协议,必须要安装ssl证书吗?

ssl证书作为保护网站数据传输安全的重要工具&#xff0c;被广泛应用于网站的安全加密通信中。很多人在初次接触ssl证书时&#xff0c;有一个常见的疑问&#xff1a;网站使用https协议必须要ssl证书吗&#xff1f; 答案是肯定的。   HTTPS是一种通过计算机网络进行安全通信的…

计算机网络 网络命令的使用

一、实验内容 1.PING网络命令的实验 ping 127.0.0.1(内部回环测试)ping 本主机的IP地址ping 默认网关地址ping远端目的地的IP地址ping localhostping域名 2.其他网络命令实验 命令用途ipconfig/all 显示当前系统网络配置&#xff0c;包括IP地址、子网掩码、默认网关等trace…

Unity MySql安装部署与Unity连接

1.前言 最近项目用到MySql&#xff0c;记录一下安装部署过程。 数据量过大或者需要管理用户数据的时候用mysql的话数据结构比较清晰明了&#xff0c;便于管理。 2.安装MySql Unity版本&#xff1a;2019.4.16 MySql版本&#xff1a;8.2.0 下载地址&#xff1a;MySql 下载…

LLM - 大语言模型(LLM) 的 应用技术

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/137503579 大语言模型(LLM) 的应用技术范围非常广泛,即: LangChain:开发框架,专为大型语言模型设计,以提高开发人工智能应用的效率,允许开发者将语言模…

Day17_学点JavaEE_转发、重定向、Get、POST、乱码问题总结

1 转发 转发&#xff1a;一般查询了数据之后&#xff0c;转发到一个jsp页面进行展示 req.setAttribute("list", list); req.getRequestDispatcher("student_list.jsp").forward(req, resp);2 重定向 重定向&#xff1a;一般添加、删除、修改之后重定向到…

整理的微信小程序日历(单选/多选/筛选)

一、日历横向多选&#xff0c;支持单日、双日、三日、工作日等选择 效果图 wxml文件 <view class"calendar"><view class"section"><view class"title flex-box"><button bindtap"past">上一页</button&…

AWS入门实践-在EC2上部署Wordpress网站

在AWS EC2上部署WordPress涉及到几个步骤&#xff0c;包括启动EC2实例、配置数据库、安装WordPress等。以下是详细的步骤和相应的命令脚本 第一步: 启动 EC2 实例 登录 AWS 控制台,进入 EC2 服务启动一个新的 EC2 实例,选择 Amazon Linux 2 AMI选择合适的实例类型(例如 t2.mi…