目录
一、模型
1.1、组对象Group和层级模型(树结构)
1.2、递归遍历模型树结构、查询具体模型节点(楼房案例)
1.3、本地(局部)坐标和世界坐标
1.4、改变模型相对局部坐标原点位置
1.5、移除对象.remove()
1.6、模型隐藏与显示
二、纹理
2.1、创建纹理贴图(TextureLoader)
2.2、自定义顶点UV坐标(geometry.attributes.uv)
2.3、圆形平面(CircleGeometry)设置纹理贴图
2.4、纹理对象texture的阵列(铺瓷砖)
2.5、矩形Mesh+背景透明png贴图(场景标注)
2.6、偏移属性.offset(UV动画--跑步机)
一、模型
1.1、组对象Group和层级模型(树结构)
const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.x = 100;
// 创建一个组对象,将mesh1和mesh2作为它的子对象
const group=new THREE.Group()
group.add(mesh1)
group.add(mesh2)
// 等价于 group.add(mesh1,mesh2)
// 以上等价于 const obj=new THREE.Object3D();
// obj.add(mesh1,mesh2);
console.log(group.children,'group.children');//查看所有子对象
mesh1.translateY(50)
mesh2.translateY(50)
// 等价于 group.translateY(50)
export default group;
有时候:Object3D(模型节点)可以和Group画等号。
1.2、递归遍历模型树结构、查询具体模型节点(楼房案例)
模型命名:.name
递归遍历:traverse()函数
查询具体模型节点:xx.getObjectByName()
import * as THREE from "three";
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.MeshBasicMaterial({
color: 0x00ffff,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.name = i + 1 + "号楼";
mesh.position.x = i * 30;
group1.add(mesh);
}
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.MeshBasicMaterial({
color: 0xffff00,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.name = i + 6 + "号楼";
mesh.position.x = i * 30;
group2.add(mesh);
}
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.traverse(function (obj) {
if (obj.isMesh) {
// obj.material.color.set(0xffff00);//批量修改颜色
// obj是所有被命名的集合,isMesh是所有的mesh
console.log("obj==>", obj.name);
}
});
const nodeName = model.getObjectByName("4号楼"); //查找某个具体模型
nodeName.material.color.set(0xff0000);
export default model;
1.3、本地(局部)坐标和世界坐标
本地坐标:任何一个模型的.position属性就是本地坐标
世界坐标:模型自身.position和所有父对象.position累加的坐标,其中getWorldPosition()获取并存储世界坐标。
import * as THREE from "three";
const geometry = new THREE.BoxGeometry(20, 20, 20);
const material = new THREE.MeshBasicMaterial({
color: 0x00ffff,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x=50
const group = new THREE.Group();
group.add(mesh);
group.position.x = 50;
// 创建一个三维向量表示坐标
const v3=new THREE.Vector3()
mesh.getWorldPosition(v3);//getWorldPosition()获取世界坐标
console.log(v3,'世界坐标',mesh.position,'本地坐标');
const meshAx=new THREE.AxesHelper(50)
mesh.add(meshAx);//给子对象添加一个局部坐标系,跟随位置移动
mesh.position.y=50
export default group;
1.4、改变模型相对局部坐标原点位置
// 几何中心默认与本地坐标原点重合
const geometry = new THREE.BoxGeometry(50, 50, 50);
//平移几何体的顶点坐标,改变几何体自身相对局部坐标原点的位置
geometry.translate(50 / 2, 0, 0);
1.5、移除对象.remove()
举个例子:scene.remove(model);
一次移除多个子对象:group.remove(mesh1,mesh2);
1.6、模型隐藏与显示
举个例子:group.visible=false
材质隐藏:mesh.material.visible=false,这里当多个模型共享材质时发生同时消失问题,可以考虑mesh.material=material.clone()克隆后就不会互相影响。
二、纹理
2.1、创建纹理贴图(TextureLoader)
就是把外部图片渲染在相应的几何体上,比如将地图平面.png渲染在球体上,形成了地球仪。
import * as THREE from "three";
const geometry = new THREE.SphereGeometry(50);
// 纹理贴图加载器TextureLoader
const texLoader=new THREE.TextureLoader()
// .load()加载图像,返回一个纹理对象
const texture=texLoader.load('./ditu.jpg')
const material = new THREE.MeshBasicMaterial({
map:texture//map表示材质的颜色贴图属性
});
// material.map=texture;//这样也可以设置
const mesh = new THREE.Mesh(geometry, material);
export default mesh;
2.2、自定义顶点UV坐标(geometry.attributes.uv)
顶点UV坐标作用:
从纹理贴图上提取像素映射到网络模型Mesh的几何体表面上。
import * as THREE from "three";
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([0, 0, 0, 100, 0, 0, 100, 60, 0, 0, 60, 0]);
const attribute = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attribute;
const indexes = new Uint16Array([0, 1, 2, 0, 2, 3]);
geometry.index = new THREE.BufferAttribute(indexes, 1);
// const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);//全图映射
const uvs = new Float32Array([0, 0, 0.5, 0, 0.5, 0.5, 0, 0.5]);//映射左下角的1/4
geometry.attributes.uv = new THREE.BufferAttribute(uvs, 2);
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load("./ditu.jpg");
const material = new THREE.MeshBasicMaterial({
map: texture,
});
const mesh = new THREE.Mesh(geometry, material);
export default mesh;
2.3、圆形平面(CircleGeometry)设置纹理贴图
原理:CircleGeometry的uv坐标会对颜色纹理贴图.map进行提取,默认是一个圆形轮廓,可以将任何形状的图片转为圆形。
// CircleGeometry的顶点uv坐标是按照圆形来采样纹理贴图
const geometry = new THREE.CircleGeometry(60,100);
2.4、纹理对象texture的阵列(铺瓷砖)
通过PlaneGeometry和texture的相关属性实现瓷砖铺满地面效果(一张图多方向重复排列)
const texture = texLoader.load("./zhuan.png");
// 允许阵列模式
texture.wrapS=THREE.RepeatWrapping
texture.wrapT=THREE.RepeatWrapping
// uv两个方向纹理重复数量,越大越密集
texture.repeat.set(12,12)
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI/2)//沿X轴平铺
2.5、矩形Mesh+背景透明png贴图(场景标注)
(1)、ps自制透明背景PNG:
选择“魔术棒工具”或“套索工具”,用于选取保留区域。点击背景区域,然后按下“删除”键,将背景色删除,再存储为.png格式即可!
(2)、标注思路:
将背景透明的.png图像作为矩形平面的颜色贴图,同时材质设置为transparent:true,这样png图片背景完全透明的部分不显示。
//==========================index.js==================
// 创建一个辅助网格地图【参数:尺寸、细分次数、中线色、网格线色】
const gridHelper=new THREE.GridHelper(600,50,0x00ffff,0x004444);
scene.add(gridHelper)
//=========================touming.js===================
import * as THREE from "three";
const geometry = new THREE.PlaneGeometry(100,100);
const texLoader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
map: texLoader.load("./jiantou.png"),
side:THREE.DoubleSide,
transparent:true
});
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI/2)//沿X轴平铺 ,因为默认是XOY面放置
mesh.position.y=1;//往上移一下,避免图标被污染
export default mesh;
2.6、偏移属性.offset(UV动画--跑步机)
偏移的本质就是修改UV顶点坐标。
【.wrapS对应offset.x偏移; .wrapT对应offset.y偏移】
texture.offset.x = 0.5; //UV--U方向偏移
// 实现“首尾相接 ”
texture.wrapS = THREE.RepeatWrapping; //改变包裹(映射方式)
texture.repeat.x=50;//针对小像素偏移时添加,大图可忽略
export { mesh, texture };
//====================index.js核心代码===========================
import { mesh, texture } from "./offset.js";
function render() {
texture.offset.x += 0.005; //每次累加偏移
renderer.render(scene, camera); //一定要更新内容
requestAnimationFrame(render); //请求动画帧==实现周期性循环
}
render();