three.js 几何体、材质和网格模型

场景Scene、相机Camera、渲染器Renderer初始化完成之后,可以向场景中添加一个简单的模型进行展示。在此之前需要了解三个概念:几何体、材质、网格模型

  • 几何体:表示物体的几何形状。
  • 材质:表示物体的外观效果。
  • 网格模型:将几何体和材质组合起来,作为three.js的一个基本物体单位,可以添加进场景中。

几何体相关

几何体是指由点、线、面所构成的空间实体。其中,点、线、面是几何体的基本元素,几何体包括球体、立方体、圆柱体、矩形、圆形等。这些几何体都有自己的特定形状和特征,可以应用于各种数学、物理和工程领域。

常见的几何体

在这里插入图片描述

// BoxGeometry:长方体
const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry:圆柱
const geometry = new THREE.CylinderGeometry(50,50,100);
// PlaneGeometry:矩形平面
const geometry = new THREE.PlaneGeometry(100,50);
// CircleGeometry:圆形平面
const geometry = new THREE.CircleGeometry(50);

缓冲类型几何体BufferGeometry

threejs提供的长方体BoxGeometry、球体SphereGeometry等各种形状的几何体都是基于BufferGeometry类构建的,BufferGeometry是一个没有任何形状的空几何体,你可以通过BufferGeometry自定义任何几何形状,具体一点说就是定义顶点数据。

// 创建一个空的几何体对象
const geometry = new THREE.BufferGeometry(); 

缓冲区对象BufferAttribute

BufferAttribute类用于存储与BufferGeometry相关联的 attribute(例如顶点位置向量,面片索引,法向量,颜色值,UV坐标以及任何自定义 attribute )。

BufferAttribute( array, itemSize, normalized )

  • array:与BufferGeometry相关联的数组。必须是TypedArray类型。
  • itemSize:与顶点相关的数据值的大小。如果 attribute 存储的是三元组(例如顶点空间坐标、法向量或颜色值)则itemSize的值应该是3。
  • normalized:指示数据如何与GLSL代码中的数据进行对应。
// 类型化数组创建顶点数据
const vertices = new Float32Array([
    0, 0, 0, // 顶点1坐标
    80, 0, 0, // 顶点2坐标
    80, 80, 0, // 顶点3坐标
    0, 0, 0, // 顶点4坐标   和顶点1位置相同
    80, 80, 0, // 顶点5坐标  和顶点3位置相同
    0, 80, 0, // 顶点6坐标
]);
// 创建属性缓冲区对象
const attribue = new THREE.BufferAttribute(vertices, 3); 

使用BufferGeometry定义一个矩形几何体

一个矩形平面,可以至少通过两个三角形拼接而成。而且两个三角形有两个顶点的坐标是重合的。
注意三角形的正反面问题:保证矩形平面两个三角形的正面是一样的,也就是从一个方向观察,两个三角形都是逆时针或顺时针。

  1. 通过javascript类型化数组Float32Array创建一组xyz坐标数据用来表示几何体的顶点坐标。
// 类型化数组创建顶点数据
const vertices = new Float32Array([
    0, 0, 0, // 顶点1坐标
    80, 0, 0, // 顶点2坐标
    80, 80, 0, // 顶点3坐标
    0, 0, 0, // 顶点4坐标   和顶点1位置相同
    80, 80, 0, // 顶点5坐标  和顶点3位置相同
    0, 80, 0, // 顶点6坐标
]);
  1. 通过threejs的属性缓冲区对象BufferAttribute表示threejs几何体顶点数据。
// 创建属性缓冲区对象
// 3个为一组,表示一个顶点的xyz坐标
const attribue = new THREE.BufferAttribute(vertices, 3); 
  1. 设置几何体的顶点
// 设置几何体attribue属性的位置属性
// geometry.setAttribute( 'position', attribue); 
geometry.attributes.position = attribue;

网格模型Mesh对应的几何体BufferGeometry,拆分为多个三角后,很多三角形重合的顶点位置坐标是相同的,这时候如果你想减少顶点坐标数据量,可以借助几何体顶点索引geometry.index来实现。
在这里插入图片描述
在上面的讲述中可以看出,每个三角形3个顶点坐标,矩形平面可以拆分为两个三角形,也就是6个顶点坐标。如果几何体有顶点索引geometry.index,你就可以把三角形重复的顶点位置坐标删除。

const vertices = new Float32Array([
    0, 0, 0, // 顶点1坐标
    80, 0, 0, // 顶点2坐标
    80, 80, 0, // 顶点3坐标
    0, 80, 0, // 顶点4坐标
]);
  1. 通过javascript类型化数组Uint16Array创建顶点索引.index数据。
// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([
    // 下面索引值对应顶点位置数据中的顶点坐标
    0, 1, 2, 0, 2, 3,
])
  1. 通过threejs的属性缓冲区对象BufferAttribute表示几何体顶点索引.index数据。
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); // 1个为一组

完整代码

// 创建一个空的几何体对象
const geometry = new THREE.BufferGeometry(); 
// 类型化数组创建顶点数据
const vertices = new Float32Array([
	0, 0, 0, // 顶点1坐标
	80, 0, 0, // 顶点2坐标
	80, 80, 0, // 顶点3坐标
	0, 80, 0, // 顶点4坐标
] );
// 创建属性缓冲区对象 itemSize = 3 因为每个顶点都是一个三元组。 
const attribue = new THREE.BufferAttribute(vertices, 3);
// 设置几何体attribue属性的位置属性
geometry.attributes.position = attribue;
// 创建索引 
const indexes = new Uint16Array([0, 1, 2, 2, 3, 0])
// 索引数据,1个为一组
const index = THREE.BufferAttribute(indexes, 1);
// 索引数据赋值给几何体的index属性
geometry.index = index;

const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); 
const mesh = new THREE.Mesh( geometry, material );

几何体方法

BufferGeometry通过.scale().translate().rotateX().rotateY()等方法可以对几何体本身进行缩放、平移、旋转,这些方法本质上都是改变几何体的顶点数据。
在这里插入图片描述

缩放.scale()
// 几何体xyz三个方向都放大2倍
geometry.scale(2, 2, 2);
平移.translate()
// 几何体沿着x轴平移50
geometry.translate(50, 0, 0);
旋转.rotateX().rotateY().rotateZ()
// 几何体绕着x轴旋转45度
geometry.rotateX(Math.PI / 4);
居中.center()
geometry.translate(50, 0, 0);//偏移
// 居中:已经偏移的几何体居中,执行.center(),你可以看到几何体重新与坐标原点重合
geometry.center();

材质Material

在Three.js中,‌Material是所有材质的基类,‌它包含了一系列属性和方法,‌用于控制材质的透明度、‌深度测试、‌颜色、‌渲染面(‌正面、‌背面或双面)‌、‌透明度设置等。
在这里插入图片描述
MeshBasicMaterial、MeshLambertMaterial、MeshPhongMaterial等子类网格材质会从父类Material继承一些属性和方法,比如透明度属性.opacity、面属性.side、是否透明属性.transparent等等。

主要的材质属性:

  • color:基本颜色,通常是一个THREE.Color对象,表示材质的漫反射颜色。
  • map:纹理贴图,是一个THREE.Texture对象,用于为材质添加纹理。
  • opacity:透明度,表示材质的不透明程度,取值范围为 0(完全透明)到 1(完全不透明)。
  • transparent:指示材质是否透明。如果设置为true,则材质将考虑透明度(opacity)的影响。
  • alphaMap:透明度贴图,是一个THREE.Texture对象,用于根据纹理图像的灰度值控制材质的透明度。
  • side:渲染面的方向,可以是THREE.FrontSideTHREE.BackSideTHREE.DoubleSide。默认值是THREE.FrontSide,只渲染正面。
  • emissive:自发光颜色,通常是一个THREE.Color对象,表示材质的自发光颜色。
  • emissiveMap:自发光贴图,是一个THREE.Texture对象,用于为材质添加自发光效果。
  • specular:镜面反射颜色,通常是一个THREE.Color对象,表示材质的镜面反射颜色。这个属性主要应用于具有镜面反射效果的材质,如THREE.MeshPhongMaterial
  • shininess:光泽度,表示材质的光泽程度。这个属性主要应用于具有镜面反射效果的材质,如THREE.MeshPhongMaterial
  • wireframe:布尔值,指示是否以线框模式渲染物体。如果设置为 true,则物体将以线框模式显示。
  • bumpMap:凹凸贴图,是一个THREE.Texture对象,用于为材质添加凹凸效果,以模拟表面的细微凹凸。
  • normalMap:法线贴图,是一个THREE.Texture对象,用于为材质添加法线贴图效果,以模拟表面的细节。
  • displacementMap:位移贴图,是一个THREE.Texture对象,用于根据纹理图像的灰度值改变物体表面的高度。
  • roughness:粗糙度,表示材质表面的粗糙程度。这个属性主要应用于基于物理的渲染(PBR)材质,如THREE.MeshStandardMaterialTHREE.MeshPhysicalMaterial
  • metalness:金属度,表示材质表面的金属质感。这个属性主要应用于基于物理的渲染(PBR)材质,如THREE.MeshStandardMaterialTHREE.MeshPhysicalMaterial
  • roughnessMap:粗糙度贴图,是一个THREE.Texture对象,用于根据纹理图像的灰度值控制材质的粗糙度。这个属性主要应用于基于物理的渲染(PBR)材质。
  • metalnessMap:金属度贴图,是一个THREE.Texture对象,用于根据纹理图像的灰度值控制材质的金属度。这个属性主要应用于基于物理的渲染(PBR)材质。
  • envMap:环境贴图,是一个THREE.Texture对象,用于为材质添加反射和折射效果。
  • refractionRatio:折射率,表示材质的折射程度。这个属性主要应用于具有折射效果的材质,如 THREE.MeshPhysicalMaterial
material.color.set(0x00ffff);
material.transparent = true; // 开启透明
material.opacity = 0.5; // 设置透明度
material.side = THREE.DoubleSide; // 双面可见

受光照影响材质

threejs提供的网格材质,有的受光照影响,有的不受光照影响。Three.js会提供一些的光照模型来模拟物体表面的光照,光照模型就一种模拟光照的计算方法。MeshPhysicalMaterialMeshLambertMaterial一样都是渲染网格模型的材质,但是他们用的光照模型不同,具体点说就是材质模拟Mesh反射光照的代码算法不同,算法不同,自然模拟光照的真实程度也不同。
在这里插入图片描述

  • MeshLambertMaterial:Lambert光照模型(漫反射)光线向四周反射。
  • MeshPhongMaterial:Phong光照模型(漫反射、高光反射),可以提供一个镜面反射效果。
  • MeshStandardMaterial 和 MeshPhysicalMaterial:基于物理的光照模型(微平面理论、能量守恒、菲涅尔反射…)
// 模拟镜面反射,产生一个高光效果
const material = new THREE.MeshPhongMaterial({
    color: 0xff0000,
    shininess: 20, // 高光部分的亮度,默认30
    specular: 0x444444, // 高光部分的颜色
});

网格模型Mesh

网格模型Mesh其实就一个一个三角形(面)拼接构成。使用网格模型Mesh渲染几何体geometry,就是几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,就可以用来模拟表示物体的表面。在这里插入图片描述
三个点可以构成一个三角形,从第一个点往第三个点连接。空间中一个三角形有正反两面,你的眼睛(相机)对着三角形的一个面,如果三个顶点的顺序是逆时针方向,该面视为正面,如果三个顶点的顺序是顺时针方向,该面视为反面

Mesh(geometry, material)

  • geometry:物体的结构。BufferGeometry的实例,默认值是一个新的BufferGeometry
  • material:物体的外观。一个Material,或是一个包含有Material的数组,默认是一个新的MeshBasicMaterial
  • isMesh:当前对象是否是网格模型。
const mesh = new THREE.Mesh(geometry, material);
// 获取模型的几何体
console.log('mesh.geometry', mesh.geometry);
// 获取模型的材质
console.log('mesh.material', mesh.material);

访问改变模型材质属性

// 访问模型材质,并设置材质的颜色属性
mesh.material.color.set(0xffff00);

访问改变模型几何体属性

// 访问模型几何体,并平移几何体顶点数据
mesh.geometry.translate(0, 100, 0);

材质或几何体共享

如果两个mesh使用同一个材质material,改变其中一个mesh另一个也会随之改变。

const mesh = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.x = 100;
// 两个mesh共享一个材质,改变一个mesh的颜色,另一个mesh2的颜色也会跟着改变
// mesh.material和mesh2.material都指向同一个material
// 三者等价:mesh.material、mesh2.material、material
mesh.material.color.set(0xffff00);
// 三者等价:mesh.geometry、mesh2.geometry、geometry
mesh.geometry.translate(0,100,0);

克隆.clone()

通过克隆.clone()获得的新模型和原来的模型共享材质和几何体。改变mesh2的颜色mesh不会被改变。克隆.clone()简单说就是复制一个和原对象一样的新对象。

const mesh2 = mesh.clone();
// 克隆几何体和材质,重新设置mesh2的材质和几何体属性
mesh2.geometry = mesh.geometry.clone();
mesh2.material = mesh.material.clone();
// 改变mesh2颜色,不会改变mesh的颜色
mesh2.material.color.set(0xff0000);

复制.copy()

通过复制.copy()简单说就是把一个对象属性的属性值赋值给另一个对象。也不会随之改变另一个mesh

// 改变mesh的位置,使之位于mesh2的正上方(y),距离100。
mesh.position.copy(mesh2.position); // 复制mesh2的位置属性给mesh
mesh.position.y += 100;// mesh在原来y的基础上增加100

也可使用.copy()让两个模型的姿态角度始终保持一样。

// 渲染循环
function render() {
    mesh.rotateY(0.01);// mesh旋转动画
    // 同步mesh2和mesh的姿态角度一样,不管mesh姿态角度怎么变化,mesh2始终保持同步
    mesh2.rotation.copy(mesh.rotation);
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

点模型Points

点模型Points用于显示点的类。

Points(geometry, material)

  • geometry:物体的结构。BufferGeometry的实例,默认值是一个新的BufferGeometry
  • material:点的材质。默认是PointMaterial
  • isPoints:当前对象是否是点模型。
// 点渲染模式
const material = new THREE.PointsMaterial({
    color: 0xffff00,
    size: 10.0 // 点对象像素尺寸
}); 
// 点模型对象
const points = new THREE.Points(geometry, material);

线模型Line

线模型Line一条连续的线。

Line(geometry, material)

  • geometry:表示线段的顶点,默认值是一个新的BufferGeometry
  • material:线的材质。默认是LineBasicMaterial
  • isLine:当前对象是否是线模型。
// 线材质对象
const material = new THREE.LineBasicMaterial({
    color: 0xff0000 // 线条颜色
}); 
// 创建线模型对象
const line = new THREE.Line(geometry, material);

threejs线模型除了Line,还提供了LineLoopLineSegments,区别在于绘制线条的规则不同。

// 闭合线条
const lineLoop = new THREE.LineLoop(geometry, material); 
// 非连续的线条
const lineSegments = new THREE.LineSegments(geometry, material);

基础案例使用

创建一个立方体,使其围绕Y轴旋转。

// 创建场景
const scene = new THREE.Scene();
let width = window.innerWidth; // 窗体宽度
let height = window.innerHeight; // 窗体高度
// 创建透视投影相机,视角45度,画幅比例 宽比高,近平面距离0.1,远平面1000
const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 渲染器canvas宽高设为与窗口一致
renderer.setSize(width, height);
renderer.setClearColor(0xffffff, 1) // 设置背景颜色
// 将渲染器对应的dom元素添加到body中
document.body.appendChild(renderer.domElement);
// 定义一个几何体
const geometry = new THREE.BoxGeometry(30, 30, 30);
// 定义一种材质,显示为线框
const material = new THREE.MeshBasicMaterial({ color: 0x000000, wireframe: true });
// 网孔(Mesh)是用来承载几何模型的一个对象,可以把材料应用到它上面
const mesh = new THREE.Mesh(geometry, material);
// 把几何模型添加到场景中,对象被添加到原点(0,0,0)坐标。
scene.add(mesh);
camera.position.set(0, 200, 300); // 设置相机位置
camera.lookAt(scene.position); // 设置相机方向(指向的场景对象)
function render() {
    // 渲染循环,以每秒60次的频率来绘制场景
    requestAnimationFrame(render);
    // 设置立方体绕y轴旋转
    mesh.rotation.y += 0.005;
    renderer.render(scene, camera);
}
render();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值