Three.js 学习笔记之模型 | 几何体 - 材质
关于对象坐标系我没有找到统一的名称,threeJs中文版的意思是局部空间的坐标系,本文暂时叫对象坐标系
视频讲的是局部坐标系,但我感觉这样取名容易影响对局部坐标和世界坐标的理解。会误解为局部坐标是相对于局部坐标系的坐标,但局部坐标和世界坐标都是基于世界坐标系的坐标
模型 = 几何体 + 材质
-
模型对象的父类都是三维物体
Object3D
类 -
Three.js
的材质默认正面可见、背面不可见- 解决办法:材质配置对象中设置
side
属性
side取值 描述 THREE.FrontSide 只有正面可见 THREE.DoubleSide 两面可见 THREE.BackSide 设置只有背面可见 - 解决办法:材质配置对象中设置
-
模型
position
是指模型中心的位置,是一个三维向量。几何体attributes.position
是指几何体顶点位置信息,是一个BufferAttribute
类型
属性与方法 | 描述 |
---|---|
position : Vector3 | 设置模型中心的局部坐标位置,默认值THREE.Vector3(0.0,0.0,0.0) |
translateX/translateY/translateZ ( distance : Float ) | 沿着X轴将平移distance个单位,本质改变的position 值 |
translateOnAxis ( axis : Vector3, distance : Float ) | 沿着标准化后的向量axis(归一化后的向量表示方向)移动distance |
scale : Vector3 | 各分量按参数缩放 |
rotation:Euler(欧拉对象) 或quaternion:Quaternion(四元数) | 模型旋转的角度,单位是弧度 |
rotateX(rad : Float)、rotateY(rad : Float)、rotateZ(rad : Float) | 绕局部空间的X/Y/Z轴旋转这个物体。本质是修改模型的角度属性.rotation |
rotateOnAxis ( axis : Vector3, angle : Float ) | 绕标准化后的向量(看作轴)旋转angle个弧度 |
clone ( recursive : Boolean ) : Object3D | 参数表示是否可以克隆参数的后代,默认为true 克隆的规则暂时还不清楚,但克隆模型,其几何体和材质是共享的(克隆的地址)。 如果几何体和材质单独调用 clone 克隆出来是独立的。 |
copy ( object : Object3D, recursive : Boolean ) | 复制参数对象到这个对象中。 事件监听器和用户定义的回调函数不会被复制。 |
children:Array | 子对象数组(分组对象的子孩子),调用三维物体实例的add方法时,实际就是将参数加入到该数组中。 |
add (object: Object3D, …) | 添加参数对象到这个对象的子级children ,可以添加任意数量的对象。 当前传入的对象中的父级将在这里被移除,因为一个对象仅能有一个父级。 |
name : String | 对象的名称,可选、不必唯一。默认值是一个空字符串。 |
getObjectByName (name:String):Object3D | 从该对象开始,搜索一个对象及其子级,返回第一个带有匹配name的子对象。 |
.getWorldPosition ( target : Vector3 ) : Vector3 | 读取世界坐标,结果存储在参数里 |
const axis = new THREE.Vector3(1, 1, 1);
axis.normalize(); //向量归一化后表示方向,方向不变,大小变为单位向量
//沿着axis轴表示方向平移100
mesh.translateOnAxis(axis, 100);
模型隐藏或显示
方式1:隐藏网格模型object3D.visible : Boolean
mesh.visible =false;// 隐藏一个网格模型,visible的默认值是true
group.visible =false;// 隐藏一个包含多个模型的组对象group
方式2:隐藏材质Material.visible:Boolean
,通过该属性可以控制是否隐藏使用了该材质的模型对象。
mesh.material.visible =false;
模型
点模型Points - 用于显示点
语法:new Points( geometry : BufferGeometry, material : Material )
- geometry 几何体对象(可选),
BufferGeometry
的实例,默认值是一个新的BufferGeometry
。 - material 材质对象(可选),默认值为
PointsMaterial
。
描述:一个用于显示点的类,将几何体geometry
渲染成点。
线模型Line | LineLoop | LineSegments
语法:new Line( geometry : BufferGeometry, material : Material )
- geometry 线段的顶点,默认值是一个新的
BufferGeometry
。 - material 线的材质,默认值是一个新的且随机颜色的
LineBasicMaterial
。
线模型 | 绘制线条的规则 |
---|---|
Line | 从第一个点开始到最后一个点,依次连成线 不闭合 |
LineLoop | 从第一个点开始到最后一个点,依次连成线,并将最后一个顶点连回第一个顶点 闭合 |
LineSegments | 从第一个点开始,第一个点连接第二个点,第三个点连接第四个点…有n个点,就有n/2条线 间断 |
网格模型mesh - 三角形
本质:一个一个三角形拼接
说明:几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,用来模拟物体的表面。
三角形的正反面
三个点可以构成一个三角形,从第一个点往第三个点连接
- 正面:相机对着面,连接的顺序是逆时针
- 反面:相机对着面,连接的顺序是顺时针
网格模型独有的属性与方法
字段 | 描述 |
---|---|
isMesh : Boolean | 当前对象是否时网格模型 |
geometry : BufferGeometry | 物体的结构 |
material : Material | 物体的外观,默认值是一个MeshBasicMaterial |
const mesh = new THREE.Mesh(geometry, material);
// 获取模型的几何体
console.log('mesh.geometry',mesh.geometry);
// 获取模型的材质
console.log('mesh.material',mesh.material);
InstancedMesh 实例化网格:渲染大量具有相同几何体与材质
说明:特殊的mesh
,可以使用InstancedMesh
来渲染大量具有相同几何体与材质、但具有不同世界变换的物体,提升应用程序的整体渲染性能。
语法:new THREE.InstancedMesh( geometry : BufferGeometry, material : Material, count : Integer )
实例属性与方法 | 描述 | 备注 |
---|---|---|
instancedMesh.setMatrixAt ( index : Integer, matrix : Matrix4 ) | 设置本地变换矩阵到已定义的第几个实例 | 设置后需要执行instancedMesh.instanceMatrix.needsUpdate=true |
instancedMesh.instanceMatrix : InstancedBufferAttribute | 表示所有实例的本地变换 |
几何体BufferGeometry
常见几何体可以看成是封装后的BufferGeometry
缓冲类型几何体BufferGeometry - 基类
描述:BufferGeometry
是一个没有任何形状的空几何体,通过定义顶点数据将BufferGeometry
自定义为任何几何形状。每个几何体可以看作是由多个顶点构成的图案。
BufferGeometry实例的属性与方法
属性名/方法 | 描述 |
---|---|
index:BufferAttribute | 绑定几何体的顶点索引,每个三角形都绑定了三个顶点的索引。 允许顶点坐标在三角形中复用。 |
attributes : Object | 存储该几何体相关属性的hashmap (这里直接打印看不见里面的属性),每个value的类型都是BufferAttribute 可以通过 几何体.setAttribute 和 几何体.getAttribute 添加和访问与当前几何体相关的属性。 |
案例
1.使用 THREE.BufferGeometry
创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();
2.利用Float32Array
定义顶点数据,使用属性缓冲区对象BufferAttribute
表示threejs
几何体顶点数据。
通过javascript类型化数组Float32Array
创建一组xyz
坐标数据用来表示几何体的顶点坐标。
//类型化数组创建顶点数据
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
50, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
0, 0, 10, //顶点4坐标
0, 0, 100, //顶点5坐标
50, 0, 10, //顶点6坐标
]);
// 创建属性缓冲区对象,3个为一组,表示一个顶点的xyz坐标
const attribue = new THREE.BufferAttribute(vertices, 3);
3.设置几何体的定点.attributes.position
// 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;
4.渲染顶点
4.1使用点模型渲染顶点数据,会把几何体渲染为点,网格模型Mesh会把几何体渲染为面。
// 点渲染模式
const material = new THREE.PointsMaterial({
color: 0xffff00,
size: 10.0 //点对象像素尺寸
});
const points = new THREE.Points(geometry, material); //点模型对象
4.2使用线模型渲染顶点数据,从第一个点开始到最后一个点,依次连成线。
// 线材质对象
const material = new THREE.LineBasicMaterial({
color: 0xff0000 //线条颜色
});
// 创建线模型对象
const line = new THREE.Line(geometry, material);
4.3用网格模型渲染顶点
const material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide, //两面可见
});
创建几何体的方式
- 直接利用顶点数据,每一个点对应一个坐标
new Float32Array
构造坐标数组 | 32位的浮点数型数组THREE.BufferAttribute(坐标数组,3)
每三个坐标为一组,构建顶点坐标。顶点的个数等于组数- 赋值给
geometry.attributes.position
- 利用顶点索引,多个顶点可以利用同一个坐标
new Float32Array
构造坐标数组THREE.BufferAttribute(坐标数组,3)
每三个坐标为一组,构建顶点坐标。new Uint16Array
构造索引顶点数组,顶点的个数需要和索引的个数一样 | 16 位无符号整数geometry.index = new THREE.BufferAttribute(indexes, 1)
通过索引去坐标数组中取顶点坐标
案例: 构建一个矩形平面几何体 - 通过顶点数据
顶点坐标:一个矩形平面,可以至少通过两个三角形拼接而成。
三角形方向:两个三角形的正面需要保持一致
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);
geometry.attributes.position = attribue;
几何体顶点索引数据 - 通过顶点索引
在上述案例中,坐标4和坐标5其实是重复的坐标,重复的坐标可以复用吗?
// 删除重复的坐标
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标 | 索引0
80, 0, 0, //顶点2坐标 4坐标 | 索引1
80, 80, 0, //顶点3坐标 5坐标 | 索引2
0, 80, 0, //顶点6坐标 | 索引3
]);
// Uint16Array类型数组创建顶点索引数据
const indexs = new Uint16Array([
// 下面索引值对应顶点位置数据中的顶点坐标
0, 1, 2, 0, 2, 3,
])
// 索引数据赋值给几何体的index属性 1个为1组
geometry.index = new THREE.BufferAttribute(indexs, 1);
BufferAttribute Types
在 three.js
中一共有 9 种 BufferAttribute
,每种和 JavaScript 中的类型相对应Typed Arrays
。使用new创建BufferAttribute对象时,传入数组是什么内省,生成的BufferAttribute就是什么类型
BufferAttribute 类型 | 对应的JS数组类型 |
---|---|
THREE.Float64BufferAttribute | Float64Array |
THREE.Uint32BufferAttribute | Uint32Array |
THREE.Int32BufferAttribute | Int32Array |
THREE.Uint16BufferAttribute | Uint16Array |
THREE.Int16BufferAttribute | Int16Array |
THREE.Uint8ClampedBufferAttribute | Uint8ClampedArray |
THREE.Uint8BufferAttribute | Uint8Array |
THREE.Int8BufferAttribute | Int8Array |
定义顶点法线 geometry.attributes.normal
数学上法线的概念
一个平面,法线的就是改平面的垂线,如果是光滑曲面,一点的法线就是该点切面的法线。
Three.js中法线是通过顶点定义,默认情况下,每个顶点都有一个法线数据。
无顶点索引的使用方式
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 0, 0, //顶点4坐标
80, 80, 0, //顶点5坐标
0, 80, 0, //顶点6坐标
]);
geometry.attributes.position =new THREE.BufferAttribute(vertices, 3);
const material = new THREE.MeshLambertMaterial({
color: 0xff0000, //线条颜色
side: THREE.DoubleSide
});
// 矩形平面,无索引,两个三角形,6个顶点
// 每个顶点的法线数据和顶点位置数据一一对应
const normals = new Float32Array([
0, 0, 1, //顶点1法线( 法向量 )
0, 0, 1, //顶点2法线
0, 0, 1, //顶点3法线
0, 0, 1, //顶点4法线
0, 0, 1, //顶点5法线
0, 0, 1, //顶点6法线
]);
// 设置几何体的顶点法线属性.attributes.normal
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3);
有顶点索引的使用方式
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标 顶点4坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标 顶点5坐标
0, 80, 0, //顶点6坐标
]);
geometry.attributes.position =new THREE.BufferAttribute(vertices, 3);
// 矩形平面,有索引,两个三角形,有2个顶点重合,有4个顶点
// Uint16Array类型数组创建顶点索引数据
const indexs = new Uint16Array([
// 下面索引值对应顶点位置数据中的顶点坐标
0, 1, 2, 0, 2, 3,
])
geometry.index = new THREE.BufferAttribute(indexs, 1);
// 每个顶点的法线数据和顶点位置数据一一对应
const normals = new Float32Array([
0, 0, 1, //顶点1法线( 法向量 )
0, 0, 1, //顶点2法线
0, 0, 1, //顶点3法线
0, 0, 1, //顶点4法线
]);
// 设置几何体的顶点法线属性.attributes.normal
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3);
BufferGeometry的子类几何体
几何体的分段数 - 将一个大块分成几个小块
很多几何体构造函数提供了分段数,其默认值为1。除去必要参数之外的第一个参数表示x轴分成几段,第二个参数表示y轴分成几段。
PlaneGeometry矩形平面案例
// 把一个矩形x轴方向分为两段,每份2个三角形,一共4个三角形
const geometry = new THREE.PlaneGeometry(50,50,2,1);
SphereGeometry球体平面案例
// 参数2表示水平方向(经线方向) 参数3表示垂直方向(维度)
// 绿色框为一块,每个水平方向有4块,每一块由两个三角形组成
const geometry = new THREE.SphereGeometry( 50, 4, 16 );
SphereGeometry 球体
语法:new SphereGeometry(radius : Float,可选参数)
由于所有几何体都是由一个一个三角形组成,所以如果球体细分数比较低,表面就不会那么光滑,分段数越大越接近一个球。
可选参数 | 描述 |
---|---|
widthSegments | 水平分段数(沿着经线分段),最小值为3,默认值为32。 |
heightSegments | 垂直分段数(沿着纬线分段),最小值为2,默认值为16。 |
边缘几何体EdgesGeometry和网格几何体WireframeGeometry
网格几何体WireframeGeometry
WireframeGeometry( geometry : BufferGeometry)
:本质是使用了线框材质的几何体,创建参数geometry
几何体的一个辅助物体,该辅助物体支持以线框的形式进行查看
继承链:BufferGeometry →WireframeGeometry
LineSegments( geometry : BufferGeometry, material ?: Material )
:在若干对的顶点之间绘制的一系列的线。
geometry
表示每条线段的两个顶点。
material
线的材质,默认值是LineBasicMaterial。
// 内层粉色矩形
const sphereGeometry = new THREE.PlaneGeometry(50, 50);
const meterial = new THREE.LineBasicMaterial({
color:"pink"
})
scene.add(new THREE.Mesh(sphereGeometry,meterial))
// 外层白色边框
const sphereGeometry1 = new THREE.PlaneGeometry(100,100);
const wireframe = new THREE.WireframeGeometry( sphereGeometry1 );
const line = new THREE.LineSegments( wireframe );
scene.add( line );
边缘几何体EdgesGeometry
语法:EdgesGeometry( geometry : BufferGeometry, thresholdAngle : Integer )
作为一个辅助对象来查看geometry的边缘。
geometry
任何一个几何体对象。
thresholdAngle
仅当相邻面的法线之间的角度(单位为角度)超过这个值时,才会渲染边缘,默认值为1。
使用场景:查看模型的边缘结构
说明:
1.创建边缘几何体是利用参数geometry
几何体的顶点信息,所以如果几何体发生了不改变顶点坐标的变换,生成的边缘几何体是不会应用该变换的。
// 载入的模型,比如gitf
let building = gltf.scene.children[0];
let geometry = building.geometry;
const edges = new THREE.EdgesGeometry( geometry ); // 获取边缘几何体
const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xffffff } ) ) // 创建线段
scene.add( line );
// EdgesGeometry是根据顶点信息创建的,如果还需要应用模型变化
building.updateWorldMatrix(true,true); // 更新世界变换到building的世界变换matrixWorld
edges.matrix.copy(building.matrixWorld); //只想应用物体的平移缩放与旋转, 官方文档没有edges.matrix?这里感觉像是随便在对象中定义了一个属性matrix
edges. .decompose(edges.position, edges.applyQuaternion,edges.scale) //decompose:将矩阵分解到给定的平移position ,旋转 quaternion,缩放scale分量中。
材质 Material
材质Material
是所有材质的父类。
创建材质:new 材质(配置对象)
说明:材质描述了物体的外观,定义方式与渲染器无关
配置对象里可配置的属性其实就是返回的材质实例拥有的属性
/* 案例 */
const material = new THREE.MeshLambertMaterial({
color:0xff0000,
wireframe:true,
});
console.log("material.wireframe:",material.wireframe)
方法与属性 | 描述 |
---|---|
transparent : Boolean | 定义此材质是否透明,默认为false。对渲染有影响,透明对象需要特殊处理,并在非透明对象之后渲染。设置为true之后可以使用opacity调整透明度。 |
opacity:Float | 范围是0.0 - 1.0,表明材质的透明度。值0.0表示完全透明,1.0表示完全不透明(默认)。如果transparent属性未设置为true,则材质将保持完全不透明,此值仅影响其颜色。 |
side:Integer | 定义将要渲染哪一面,默认是正面(相机照着那面,连接的顺序是逆时针) |
点材质PointsMaterial - Points使用的默认材质
语法:new PointsMaterial( parameters : Object )
实例的属性和方法
属性/方法 | 描述 |
---|---|
size:Number | 设置点的大小,默认值为1.0。 |
color:Color | 材质的颜色,默认值为白色 (0xffffff)。 |
网格材质 Mesh
使用收光照影响的材质时,如果没有光照默认是黑色的(renderer画布设置了颜色可以看出)
材质 | 描述 | 受光照影响 | 特点 |
---|---|---|---|
MeshBasicMaterial | 基础光照模型 | × | |
MeshLambertMaterial | Lambert光照模型(漫反射) | √ | |
MeshPhongMaterial | Phong光照模型(漫反射、高光反射) | √ | |
MeshStandardMaterial | 基于物理的光照模型(PBR物理材质 ),可以提供更加真实的材质效果 | √ | 物理网格材质使用了更复杂的着色器功能,大部分的特性是默认关闭的,需要手动开启。 |
MeshPhysicalMaterial | 属于PBR物理材质 (基于物理的渲染physically-based rendering),可以提供更加真实的材质效果 | √ | MeshPhysicalMaterial 是MeshStandardMaterial 的扩展子类 |
渲染占用资源和表现能力
整体上来看,就是渲染表现能力越强,占用的计算机硬件资源更多。
- 占用渲染资源 MeshBasicMaterial < MeshLambertMaterial < MeshPhongMaterial < MeshStandardMaterial < MeshPhysicalMaterial
- 渲染表现能力 MeshBasicMaterial < MeshLambertMaterial < MeshPhongMaterial < MeshStandardMaterial < MeshPhysicalMaterial
纹理贴图
漫反射材质MeshLambertMaterial
语法:new MeshLambertMaterial( parameters : Object )
对光照的反射为漫反射
:光线向四周反射。
Lambert网格材质的属性与方法
属性和方法 | 描述 |
---|---|
wireframe : Boolean | 将几何体渲染为线框,默认值为false,渲染为平面多边形。 |
高光网格材质 MeshPhongMaterial
语法:new MeshPhongMaterial( parameters : Object )
参数对象的属性 = 自有属性 + Material基类继承的属性
对光照的反射为镜面反射
:想象一面镜子的反射,如果刚好反射光对眼睛,会非常刺眼(某个局部区域高亮,像擦了高光)
注意:AmbientLight环境光没有方向,整体改变场景的光照。所以只有环境光的,高光效果会失效。
MeshPhongMaterial高光网格材质配置参数的自有属性
属性名 | 属性描述 |
---|---|
color : Color | 材质的颜色,默认值为白色(0xffffff) |
shininess | 高亮的程度,越高的值越闪亮,默认30 |
specular | 高光颜色,默认为0x111111 灰色 |
标准网格材质 MeshStandardMaterial
PBR材质金属渲染效果 - 金属度metalness和粗糙度roughness
属性名 | 属性值 | 描述 |
---|---|---|
.metalness : Float | 材质与金属的相似度。非金属材质,如木材或石材,使用0.0,金属使用1.0,通常没有中间值。 0.0到1.0之间的值可用于生锈金属的外观(默认0.0)。如果还提供了metalnessMap,则两个值相乘。 | |
.roughness : Float | 材质的粗糙程度。0.0表示平滑的镜面反射,1.0表示完全漫反射(默认1.0)。如果还提供roughnessMap,则两个值相乘。 | 生活中不同物体表面的粗糙程度不同,比如地面比较粗糙,比如镜子表面就非常非常光滑。 越光滑镜面反射能力越强,越粗糙,表面镜面反射能力越弱 |
物理网格材质 MeshPhysicalMaterial
清漆层Clearcoat
Clearcoat
类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。
属性名 | 属性值 | 描述 |
---|---|---|
清漆层属性clearcoat:Float | 0(默认值)-1 | 表示clear coat层的强度(图层厚度),模拟物体表面一层透明图层,就好比你在物体表面刷了一层透明清漆。 |
清漆层粗糙度clearcoatRoughness : Float | 由0.0(默认)到1.0。 默认为0.0 | clear coat层的粗糙度 |
更多推荐
所有评论(0)