three 层级模型

group.remove(mesh1,mesh2);

Vector3与模型位置、缩放属性

Group层级模型(树结构)

创建了两个网格模型mesh1、mesh2,通过THREE.Group类创建一个组对象group,然后通过add方法把网格模型mesh1、mesh2作为设置为组对象group的子对象,然后在通过执行scene.add(group)把组对象group作为场景对象的scene的子对象。也就是说场景对象是scene是group的父对象,group是mesh1、mesh2的父对象。

//创建两个网格模型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);

查看子对象.children

hreejs场景对象Scene、组对象Group都有一个子对象属性.children通过该属性可以访问父对象的子对象,子对象属性.children的值是数组,所有子对象是数组的值,父对象执行.add()方法的本质就是把参数中的子对象添加到自身的子对象属性.children中。

console.log('查看group的子对象',group.children);

场景对象结构

场景对象Scene的子对象,除了组对象Group之外,还可以看到环境光AmbientLight、平行光DirectionalLight、辅助坐标对象AxesHelper

console.log('查看Scene的子对象',scene.children);

场景对象对象scene构成的层级模型本身是一个树结构,场景对象层级模型的第一层,也就是树结构的根节点,一般来说网格模型Mesh、点模型Points、线模型Line是树结构的最外层叶子结点。构建层级模型的中间层一般都是通过Threejs的Group类来完成,Group类实例化的对象可以称为组对象。 

.add()方法总结

场景对象Scene、组对象Group.add()方法都是继承自它们共同的基类(父类)Object3D

group.add(mesh1);
group.add(mesh2);// 或group.add(mesh1,mesh2);

父对象旋转缩放平移变换,子对象跟着变化

格模型mesh1、mesh2作为设置为父对象group的子对象,如果父对象group进行旋转、缩放、平移变换,子对象同样跟着变换。

//沿着Y轴平移mesh1和mesh2的父对象,mesh1和mesh2跟着平移
group.translateY(100);//父对象缩放,子对象跟着缩放
group.scale.set(4,4,4);//父对象旋转,子对象跟着旋转
group.rotateY(Math.PI/6)

Object3D表示模型对象节点

受threejs历史影响,你会在很多别的代码中看到Object3D作为Group来使用,某种程度上,你可把两者画等号,只是Group更加语义化,Object3D本身就是表示模型节点的意思。

const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);
const obj = new THREE.Object3D();//作为mesh1和mesh2的父对象
obj.add(mesh1,mesh2);

mesh也能添加mesh子对象

threejs默认mesh也可以添加子对象,其实原因很简单,mesh和Group父类都是Object3D,本质上也可以认为都是Object3D。

//threejs默认mesh也可以添加子对象,mesh基类也是Object3D
mesh1.add(mesh2);

遍历模型树结构、查询模型节点

模型命名(.name属性)

在层级模型中可以给一些模型对象通过.name属性命名进行标记

const group = new THREE.Group();
group.name='小区';
const mesh = new THREE.Mesh(geometry, material);
mesh.name='五号楼';

树结构层级模型设置.name属性

下面是通过代码创建了一个层级模型,一般实际开发的时候,会加载外部的模型,然后从模型对象通过节点的名称.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);

 递归遍历方法.traverse()

Threejs层级模型就是一个树结构,可以通过递归遍历的算法去遍历Threejs一个模型对象包含的所有后代。

// 递归遍历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);}
});

查找某个具体的模型.getObjectByName()

Threejs和前端DOM一样,可以通过一个方法查找树结构父元素的某个后代对象,对于普通前端而言可以通过name或id等方式查找一个或多个DOM元素,Threejs同样可以通过一些方法查找一个模型树中的某个节点。

// 返回名.name为"4号楼"对应的对象
const nameNode = scene.getObjectByName ("4号楼");
nameNode.material.color.set(0xff0000);

 本地坐标和世界坐标

本地(局部)坐标和世界坐标

mesh的世界坐标就是mesh.position与group.position的累加

const mesh = new THREE.Mesh(geometry, material); 
mesh.position.set(10, 20, 0);
const group = new THREE.Group();
group.add(mesh);
group.position.set(50, 30, 0);
  1. 改变子对象的.position,子对象在3D空间中的坐标会发生改变。

  2. 改变父对象的.position,子对象在3D空间中的位置也会跟着变化,也就是说父对象.position和子对象.position叠加才是才是子对象的.position

任何一个模型的本地坐标(局部坐标)就是模型的.position属性。

一个模型的世界坐标,说的是,模型自身.position和所有父对象.position累加的坐标。

.getWorldPosition()获取世界坐标

mesh.getWorldPosition(Vector3)读取一个模型的世界坐标,并把读取结果存储到参数Vector3中。

// 声明一个三维向量用来表示某个坐标
const worldPosition = new THREE.Vector3();
// 获取mesh的世界坐标,你会发现mesh的世界坐标受到父对象group的.position影响
mesh.getWorldPosition(worldPosition);
console.log('世界坐标',worldPosition);
console.log('本地坐标',mesh.position);

给子对象添加一个局部坐标系

mesh.add(坐标系)给mesh添加一个局部坐标系。

//可视化mesh的局部坐标系
const meshAxesHelper = new THREE.AxesHelper(50);
mesh.add(meshAxesHelper);

改变模型相对局部坐标原点位置

通过改变几何体顶点坐标,可以改变模型自身相对坐标原点的位置。

//长方体的几何中心默认与本地坐标原点重合
const geometry = new THREE.BoxGeometry(50, 50, 50);// 平移几何体的顶点坐标,改变几何体自身相对局部坐标原点的位置
geometry.translate(50/2,0,0,);;

旋转测试

局部坐标相对模型发生改变,旋转轴自然也会发生变化。

// .rotateY()默认绕几何体中心旋转,经过上面几何体平移变化,你会发现.rotateY()是绕长方体面上一条线旋转
mesh.rotateY(Math.PI/3);//
function render() {model.rotateY(0.01);//旋转动画requestAnimationFrame(render);
}
render();

移除对象.remove()

.remove()方法和.add()方法是相反的,是把子对象从父对象的.children()属性中删除。

查看父类Object3D的移除方法.remove()

场景对象Scene、组对象Group、网格模型对象Mesh.remove()方法都是继承自它们共同的基类(父类)Object3D

.remove()方法使用

.add()方法是给父对象添加一个子对象,.remove()方法是删除父对象中的一个子对象。

// 删除父对象group的子对象网格模型mesh1
group.remove(mesh1);scene.remove(ambient);//移除场景中环境光
scene.remove(model);//移除场景中模型对象

一次移除多个子对象

group.remove(mesh1,mesh2);

模型隐藏或显示

开发web3d项目,有时候需要临时隐藏一个模型,或者一个模型处于隐藏状态,需要重新恢复显示。

模型属性.visible

模型对象的父类Object3D封装了一个属性.visible,通过该属性可以隐藏或显示一个模型。

mesh.visible =false;// 隐藏一个网格模型,visible的默认值是true
group.visible =false;// 隐藏一个包含多个模型的组对象groupmesh.visible =true;// 使网格模型mesh处于显示状态

 材质属性.visible

材质对象的父类Material封装了一个.visible属性,通过该属性可以控制是否隐藏该材质对应的模型对象。

// 隐藏网格模型mesh,visible的默认值是true
mesh.material.visible =false;
// 注意如果mesh2和mesh的.material属性指向同一个材质,mesh2也会跟着mesh隐藏

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

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

相关文章

jenkins部署maven项目

流程&#xff1a; jenkins从代码仓库读取代码&#xff0c;将代码文件放入jenkins的工作空间&#xff0c;将jenkins工作空间的代码进行打包&#xff0c;将jar包远程发送给服务器。 一&#xff1a;所需插件二&#xff1a;Tools 三&#xff1a;System&#xff1a; 配置ssh连接的…

python63-Python的循环之循环使用else

Python的循环都可以定义else代码块&#xff0c;当循环条件为False 时&#xff0c;程序会执行else代码块。如下代码示范了为while循环定义else代码块。 # !/usr/bin/env python# -*- coding: utf-8 -*-# Time : 2024/01# Author : Laopicount_i 0while count_i < 5:print(c…

Java集合相关面试题(2024大厂高频面试题系列)

1、说一说Java提供的常见集合&#xff1f;&#xff08;画一下集合结构图&#xff09; 在java中提供了量大类的集合框架&#xff0c;主要分为两类&#xff1a; 第一个是Collection 属于单列集合&#xff0c;第二个是Map 属于双列集合 在Collection中有两个子接口List和Set。…

【力扣hot100】刷题笔记Day14

前言 又是新的一周&#xff0c;快乐的周一&#xff0c;快乐地刷题&#xff0c;今天把链表搞完再干活&#xff01; 114. 二叉树展开为链表 - 力扣&#xff08;LeetCode&#xff09; 前序遍历 class Solution:def flatten(self, root: Optional[TreeNode]) -> None:if not r…

【IC前端虚拟项目】inst_buffer子模块DS与RTL编码

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 需要说明一下的是,在我所提供的文档体系里,并没有模块的DS文档哈,因为实际项目里我也不怎么写DS毕竟不是每个公司都和HISI一样对文档要求这么严格的。不过作为一个培训的虚拟项目,还是建议在时间充裕…

Docker技术概论(3):Docker 中的基本概念

Docker技术概论&#xff08;3&#xff09; Docker 中的基本概念 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://…

基于java+springboot女士电商平台系统源码+文档设计

基于javaspringboot女士电商平台系统源码文档设计 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源…

C语言----动态内存管理(2)

1.这里总结动态内存管理里面的错误 &#xff08;1&#xff09;使用malloc开辟空间以后直接赋值 这个就是malloc开辟失败返回空指针&#xff0c;直接给空指针赋值就是错误的&#xff0c; tip1:使用malloc开辟空间以后一定要判断是否为空 &#xff08;2&#xff09; 越界访问…

Python批量提取文件夹中图片的名称及路径到指定的.txt文件中

目录 一、代码二、提取效果 一、代码 import os# 定义要保存的文件名 file_name "TestImage/Image_Visible_Gray.txt"# 读取文件夹路径 folder_path "TestImage/Image_Visible_Gray"# 遍历文件夹中的所有文件 with open(file_name, "w") as f…

可移植性(兼容性)测试指南

可移植性是指应用程序能够安装到不同的环境中&#xff0c;在不同的环境中使用&#xff0c;甚至可以移动到不同的环境中。当然&#xff0c;前两者对所有系统都很重要。就PC软件而言&#xff0c;鉴于操作系统、共存和互操作应用程序、硬件、带宽可用性等方面的快速变化&#xff0…

Stable Diffusion中的Clip模型

基础介绍 Stable Diffusion 是一个文本到图像的生成模型&#xff0c;它能够根据用户输入的文本提示&#xff08;prompt&#xff09;生成相应的图像。在这个模型中&#xff0c;CLIP&#xff08;Contrastive Language-Image Pre-training&#xff09;模型扮演了一个关键的角色&a…

Biotin aniline,生物素苯胺,用于研究蛋白质结构和功能

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;769933-15-5&#xff0c;Biotin aniline&#xff0c;生物素苯胺&#xff0c;Biotin-aniline&#xff0c;生物素-苯胺 一、基本信息 【产品简介】&#xff1a;Biotin aniline is composed of three parts: biotin, w…

个人或者小团队选择C语言还是c++?

个人或者小团队选择C语言还是c? 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff0…

使用Python语言实现一个基于动态数组的序列队列

一、动态数组的实现 首先&#xff0c;我们需要创建一个DynamicArray类&#xff0c;该类将管理我们的动态数组。 动态数组能够动态地调整其大小&#xff0c;以容纳更多的元素。 目录 一、动态数组的实现 代码示例&#xff1a; 二、序列队列的实现 接下来&#xff0c;我…

代码随想录算法训练营第五天

● 自己看到题目的第一想法 242. 有效的字母异位词 方法&#xff1a; 方法一&#xff1a; 暴力法 1. 分别对s, t排序 2. 遍历s与t 判断s[i]!t[i] 返回 false 否则 返回true思路&#xff1a; 注意&#xff1a; 代码&#xff1a; bool cmp(char a, char b){return a<b;…

网站搭建的基本流程是什么?

网站搭建的基本流程是什么? 我们选择了白嫖雨云的二级域名 浏览器输入https://www.rainyun.com/z22_ 创建账号然后选择一个你喜欢的子域名我建议后缀选择ates.top的 选择自定义地址&#xff0c;类型选择cname 现在要选择记录值了&#xff0c;有a&#xff0c;aa&#xff0c;txt…

【Logback】Logback 的配置文件

目录 一、初始化配置文件 1、logback 配置文件的初始化顺序 2、logback 内部状态信息 二、配置文件的结构 1、logger 元素 2、root 元素 3、appender 元素 三、配置文件中的变量引用 1、如何定义一个变量 2、为变量设置默认值 3、变量的嵌套 In symbols one observe…

如何压缩word文档中的图片大小?一键批量压缩~

在日常工作和学习中&#xff0c;我们经常需要创建和编辑Word文档&#xff0c;并在其中插入图片来丰富内容。然而&#xff0c;随着图片的增加&#xff0c;Word文档的大小可能会急剧增加&#xff0c;导致文件变得庞大&#xff0c;不便于传输和共享。针对这个问题&#xff0c;本文…

67-箭头函数,new.target,模版字符串

1.箭头函数 ES6新增语法&#xff0c;用来简化函数的书写()>{} <script>//箭头函数的基本使用let a (a,b)>{return ab;}let c a(1,2);console.log(c);//输出3</script> 2.简写形式&#xff1a; 2.1参数&#xff1a;只有一个参数时可以省略小括号a>{}&…

面试经典 150 题 ---- 轮转数组

面试经典 150 题 ---- 轮转数组 轮转数组方法一&#xff1a;使用额外的数组方法二&#xff1a;数组翻转 轮转数组 方法一&#xff1a;使用额外的数组 我们可以使用额外的数组来将每个元素放至正确的位置。用 n 表示数组的长度&#xff0c;我们遍历原数组&#xff0c;将原数组…