Three.js开发必备:模型对象和材质详解
介绍
在ThreeJS
中,模型对象和材质(Material
)是创建3D场景的基本组成部分,一个3D
模型通常由几何体(Geometry
)和材质(material
)组合而成,并通过mesh
对象标识。three
支持多种类型的集合体如BoxGeometry
立方体、SphereGeometry
球体、PlaneGeometry
平面、CylinderGeometry
圆柱体、TorusGeometry
环面等。
三维向量Vector3
三维向量Vector3
有xyz
三个分量,threeJS
中会用三维向量Vector3
表示很多种数据,比如位置.position
和缩放.Scale
属性等,Vector3对象具有.x
,.y
,.z
,还具有.set
等方法。
定义三维向量Vector3
typescript
// 创建一个三维向量
const v3 = new THREE.Vector3(100,100,100)
scale缩放属性
typescript
mesh.scale.set(2,2,2)

position 属性
typescript
mesh.position.set(100,100,100)
mesh.position.x = 100
mesh.position.y = 100
mesh.position.z = 100

translateX平移
typescript
mesh.translateX(100);
mesh.translateY(100);
mesh.translateZ(100);

typescript
// 创建一个三维向量
const v3 = new THREE.Vector3(1,1,1)
v3.normalize() // 转化为单位向量
mesh.translateOnAxis(v3,100)

欧拉Euler与角度属性
模型的角度属性.rotation
和四元数属性.quaternion
都是表示模型的角度状态,指标是方法不同,.rotation
属性值是欧拉对象Euler
,.quaternion
属性值是四元数对象Quaternion
。
javascript
// 创建一个欧拉对象
const eu = new THREE.Euler(0,Math.PI,0)
eu.x = Math.PI
console.log("eu:",eu)

改变角度属性
角度属性.rotation
的值是欧拉对象Euler,意味着你想改变属性.rotation
。
javascript
const mesh = new THREE.Mesh(geometry,material)
mesh.rotation.y += Math.PI/8;
mesh.rotation.y += Math.PI/8;

旋转方法rotateX()...
模型执行.rotateX()
,.rotateY()
,等旋转方法,该面模型的角度属性.rotation
。
javascript
const mesh = new THREE.Mesh(geometry,material)
mesh.rotateX(Math.PI/4)
mesh.rotateY(Math.PI/4)
mesh.rotateZ(Math.PI/4)

旋转动画
javascript
function render() {
mesh.rotateY(0.01)
mesh.rotateY(0.01)
mesh.rotateZ(0.02)
renderer.render(scene, camera);
requestAnimationFrame(render);
}

模型材质颜色Color对象
如果想修改材质的颜色属性.color
,颜色对象有三个属性分别是.r
,.g
,.b
,表示颜色RGB的三个分量。
基本设置
javascript
// 创建一个颜色对象
const color = new THREE.Color(); // 默认是纯白色
color.r = 0;
color.g = 255;
color.b = 0;
material.color = color
const mesh = new THREE.Mesh(geometry,material)

基本方法
javascript
const color = new THREE.Color(); // 默认是纯白色
color.setRGB(0,1,1)
material.color = color

javascript
// 创建一个颜色对象
const color = new THREE.Color(); // 默认是纯白色
color.setStyle('#00ff00')
// color.set('#00ff00')
material.color = color
const mesh = new THREE.Mesh(geometry,material)

模型材质父类Material
父类Material
threeJS
官网中,基础网格材质MeshBasicMaterial
,漫反射网格材质MeshLambertMaterial
,高光网格材质MeshPhongMaterial
等网络材质都有一个共同的父类Material
。
网格材质继承父类属性
在JS
中,子类都会继承父类的属性和方法,threeJS
中的材质同样也是这样,MeshBasicMaterial
,MeshLambertMaterial
,MeshPhongMaterial
等子类网格材质都会从父类Material
继承一些属性和方法,如透明度属性.opcity
,面属性.side
,是否透明属性.transparent
。
材质半透明设置
javascript
import * as THREE from 'three'
const geometry = new THREE.BoxGeometry(50,50,50)
const material = new THREE.MeshLambertMaterial({
color:0xffff00
})
material.transparent = true;//开启透明
material.opacity = 0.5;//设置透明度
const mesh = new THREE.Mesh(geometry,material)
export default mesh;

材质面属性.side
材质面属性side默认值是THREE.FrontSide,表示i网格模型正面可以看到,THREE.BackSide表示背面可以看到,THREE.DoubleSide表示双面可以看到。
javascript
material.side = THREE.FrontSide // 背面不可见

javascript
material.side = THREE.BackSide;//背面可以看到

javascript
material.side = THREE.DoubleSide;//双面可见

模型对象的材质和几何体属性
打印msh,geometrys,materials查看属性
javascript
// 创建平面
const geometrys = new THREE.BoxGeometry(1, 1, 1);
const materials = new THREE.MeshLambertMaterial({
color: 0xffffff,
metalness: 0.1,
roughness: 0.5,
});
const mesh = new THREE.Mesh(geometrys, materials);
mesh.receiveShadow = true;
mesh.rotation.x = -0.5 * Math.PI;
mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = 0;
this.scene.add(mesh);
console.log("mesh", mesh);
console.log("mesh.geometry", mesh.geometry);
console.log("mesh.materials", mesh.material);

访问改变模型材质属性
javascript
// 创建平面
const geometrys = new THREE.BoxGeometry(1, 1, 1);
const materials = new THREE.MeshLambertMaterial({
color: 0xffffff,
metalness: 0.1,
roughness: 0.5,
});
const mesh = new THREE.Mesh(geometrys, materials);
mesh.receiveShadow = true;
mesh.rotation.x = -0.5 * Math.PI;
mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = 0;
this.scene.add(mesh);
mesh.material.color.set(0xffff00);

访问改变模型几何体属性
javascript
// 创建平面
const geometrys = new THREE.BoxGeometry(1, 1, 1);
const materials = new THREE.MeshLambertMaterial({
color: 0xffffff,
metalness: 0.1,
roughness: 0.5,
});
const mesh = new THREE.Mesh(geometrys, materials);
mesh.receiveShadow = true;
mesh.rotation.x = -0.5 * Math.PI;
mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = 0;
this.scene.add(mesh);
mesh.geometry.translate(0, 1, 0);

材质或几何体共享
javascript
const mesh = new THREE.Mesh(geometrys, materials);
const mesh2 = new THREE.Mesh(geometrys, materials);
mesh.receiveShadow = true;
this.scene.add(mesh);
this.scene.add(mesh2);
mesh2.position.x = 2;
// 访问模型材质,并设置材质的颜色属性
mesh.material.color.set(0xff00ff);
mesh.geometry.translate(0, 10, 0);

克隆.clone()和复制.copy()
Threejs大多数对象都有克隆.clone()
和复制.copy()
两个方法,点模型Points
、线模型Line
、网格网格模型Mesh
一样具有这两个方法。
克隆方法.clone()
A.copy(B)
表示B
属性的值赋值给A对应属性,是创建一个新对象,它是原对象的深拷贝。
javascript
// 创建平面
const geometrys = new THREE.BoxGeometry(1, 1, 1);
const materials = new THREE.MeshLambertMaterial({
color: 0xffffff,
metalness: 0.1,
roughness: 0.5,
});
const mesh = new THREE.Mesh(geometrys, materials);
const mesh2 = mesh.clone();
// 为了确保材质也是独立的,我们需要单独克隆材质
mesh2.material = mesh.material.clone();
// 现在,对mesh2的材质所做的任何更改都不会影响到原始的mesh
mesh.material.color.set(0xff00ff);
mesh2.material.color.set(0xff0000); // 改变mesh2的颜色为红色
this.scene.add(mesh);
this.scene.add(mesh2);

复制方法.copy()
N = M.clone()
表示返回一个和M相同的对象赋值给N
,是将一个对象的数据复制到另一个已存在的对象中,而不是创建新对象。
javascript
// 创建平面
const geometrys = new THREE.BoxGeometry(1, 1, 1);
const materials = new THREE.MeshLambertMaterial({
color: 0xffffff,
metalness: 0.1,
roughness: 0.5,
});
const mesh = new THREE.Mesh(geometrys, materials);
mesh.material.color.set(0xff00ff);
this.scene.add(mesh);
const mesh2 = new THREE.Mesh(); // 创建一个新的空网格对象
mesh2.copy(mesh);
// 然后,为了确保mesh2拥有独立的几何体和材质,我们需要手动克隆它们
mesh2.geometry = mesh.geometry.clone(); // 克隆几何体
mesh2.material = mesh.material.clone(); // 克隆材质
// 现在,你可以自由地修改mesh2的材质或几何体,而不会影响到mesh1。
// 例如,改变mesh2的材质颜色
mesh2.material.color.set(0xff0000); // 改变颜色为红色
mesh2.position.x = 2;
this.scene.add(mesh2);

使用copy方法同时共享一个炫转角度

javascript
<template>
<div id="container"></div>
</template>
<script>
import * as THREE from "three";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
export default {
name: "three15material",
components: {},
mounted() {
window.addEventListener("resize", () => {
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
});
this.init();
},
data() {
return {
camera: null,
scene: null,
renderer: null,
mesh: null,
controls: null,
gui: null,
cameraHelper: null,
cameraParams: {
fov: 75,
aspect: window.innerWidth / window.innerHeight,
near: 0.1,
far: 700,
zoom: 1,
},
pointLightPosition: { x: 2, y: 1, z: 2 }, // 初始化点光源的位置
sphereLight: null, // 球体光源对象
};
},
methods: {
allView() {
this.renderer.domElement.requestFullscreen();
},
backAllView() {
this.renderer.domElement.exitFullscreen();
},
init() {
this.gui = new GUI();
const container = document.body;
// 场景初始化
this.scene = new THREE.Scene();
// 相机初始化
this.camera = new THREE.PerspectiveCamera(
this.cameraParams.fov,
this.cameraParams.aspect,
this.cameraParams.near,
this.cameraParams.far
);
this.camera.position.set(2, 2, 5);
this.camera.lookAt(0, 0, 0);
// 渲染器初始化
this.renderer = new THREE.WebGLRenderer({
width: window.innerWidth,
height: window.innerHeight,
scale: 1,
antialias: true,
tonemapping: THREE.FilmicOperator,
brightness: 2.5,
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
container.appendChild(this.renderer.domElement);
this.scene.background = new THREE.Color(0x1f1f1f);
// 创建平面
const geometrys = new THREE.BoxGeometry(1, 1, 1);
const materials = new THREE.MeshLambertMaterial({
color: 0xffffff,
metalness: 0.1,
roughness: 0.5,
});
this.mesh = new THREE.Mesh(geometrys, materials);
this.mesh.material.color.set(0xff00ff);
this.scene.add(this.mesh);
this.mesh2 = new THREE.Mesh(); // 创建一个新的空网格对象
this.mesh2.copy(this.mesh);
this.mesh2.position.x = 2;
this.scene.add(this.mesh2);
// 访问模型材质,并设置材质的颜色属性
const ambientLight = new THREE.AmbientLight({
color: 0xffffff,
intensity: 0.5,
});
this.scene.add(ambientLight);
// 创建一个AxesHelper实例,参数为长度,这里设置为5个单位长度
const axesHelper = new THREE.AxesHelper(5);
// 将AxesHelper添加到场景中
this.scene.add(axesHelper);
// 创建轨道控制器
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.05;
// 动画循环
this.animate();
},
animate() {
this.mesh.rotateY(0.02); // mesh旋转动画
this.mesh2.rotation.copy(this.mesh.rotation);
requestAnimationFrame(this.animate);
this.controls.update();
this.renderer.render(this.scene, this.camera);
},
},
};
</script>
<style scoped></style>