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

本文主要是介绍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)

这篇关于threejs 组-层级模型 | 本地坐标和世界坐标 | 局部坐标系和世界坐标系 | 本地矩阵.materix和世界矩阵.matrixWorld的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/887484

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

揭秘世界上那些同时横跨两大洲的国家

我们在《世界人口过亿的一级行政区分布》盘点全球是那些人口过亿的一级行政区。 现在我们介绍五个横跨两州的国家,并整理七大洲和这些国家的KML矢量数据分析分享给大家,如果你需要这些数据,请在文末查看领取方式。 世界上横跨两大洲的国家 地球被分为七个大洲分别是亚洲、欧洲、北美洲、南美洲、非洲、大洋洲和南极洲。 七大洲示意图 其中,南极洲是无人居住的大陆,而其他六个大洲则孕育了众多国家和

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

AI Toolkit + H100 GPU,一小时内微调最新热门文生图模型 FLUX

上个月,FLUX 席卷了互联网,这并非没有原因。他们声称优于 DALLE 3、Ideogram 和 Stable Diffusion 3 等模型,而这一点已被证明是有依据的。随着越来越多的流行图像生成工具(如 Stable Diffusion Web UI Forge 和 ComyUI)开始支持这些模型,FLUX 在 Stable Diffusion 领域的扩展将会持续下去。 自 FLU

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者