更新于 

GLTF Material 与 Skeleton

修改GLTF的材质

threejs中支持通过object的名字获取到模型子类:

  • getObjectByName

通过这种方式就可以单独对导入模型的材质进行修改,
通过将模型导入threejs官方的editor平台,
可以更加方便的获知模型的相关信息:

使用gui对模型子类进行实时操作,
可以实现一个捏驴的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const gui = new dat.GUI()
const options = {
Main: 0x787A79,
Main_Light: 0xb9b9b9,
Main_Dark: 0x383838,
Hooves: 0x46423c,
Hair: 0x383838,
Muzzle: 0x3d3426,
Eye_Dark: 0x181818,
Eye_White: 0xe0e0e0
}
const gltfLoader = new GLTFLoader()
const donkeyUrl = new URL('../asserts/Donkey.gltf', import.meta.url)
gltfLoader.load(donkeyUrl.href, gltf => {
const model = gltf.scene;
scene.add(model)
gui.addColor(options, 'Main').onChange(newVal => {
model.getObjectByName('Cube').material.color.set(newVal)
})
gui.addColor(options, 'Main_Light').onChange(newVal => {
model.getObjectByName('Cube_1').material.color.set(newVal)
})
gui.addColor(options, 'Main_Dark').onChange(newVal => {
model.getObjectByName('Cube_2').material.color.set(newVal)
})
gui.addColor(options, 'Hooves').onChange(newVal => {
model.getObjectByName('Cube_3').material.color.set(newVal)
})
gui.addColor(options, 'Hair').onChange(newVal => {
model.getObjectByName('Cube_4').material.color.set(newVal)
})
gui.addColor(options, 'Muzzle').onChange(newVal => {
model.getObjectByName('Cube_5').material.color.set(newVal)
})
gui.addColor(options, 'Eye_Dark').onChange(newVal => {
model.getObjectByName('Cube_6').material.color.set(newVal)
})
gui.addColor(options, 'Eye_White').onChange(newVal => {
model.getObjectByName('Cube_7').material.color.set(newVal)
})
}, undefined, err => {
console.error(err)
})
赛博限定款驴
赛博限定款驴

修改GLTF的骨骼

gltf模型由许多骨架组成,
类似children中包含的子实体,
也需要通过 getObjectByName 选中单个骨架。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const params = {
Neptune_01: 0, // 海王星
Uranus_02: 0, // 天王星
Saturn_03: 0, // 土星
Jupiter_04: 0, // 木星
Mars_05:0 , // 火星
Earth_06:0 , // 地球
Venus_07:0 , // 金星
Mercury_08:0 , // 水星
Sun_09:0 , // 太阳
}
const loader = new GLTFLoader()
let model
loader.load('assets/solar_system_model_orrery.glb',gltf=>{
model = gltf.scene
model.traverse(obj=>{
if(obj.isMesh){
obj.castShadow = true
}
})
model.position.set(0, 0.732,0)
model.scale.set(3,3,3)
scene.add(model)
Object.entries(params).forEach(([key,value])=>{
gui.add(params,key,0,2*Math.PI).onChange(v=>{
// 通过名称值获取骨架进行旋转
model.getObjectByName(key).rotation.y = v
check()
})
})
})

控制Bone实现视线跟随鼠标效果

实现视线追踪鼠标,实际就是修改头部/眼部的焦点(lookAt)

从模型中抽取出头部/眼部模型
使用光线追踪器获取鼠标的3D坐标,
参考 鼠标点击创建物体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
let knightModel
let knightHead
// 加载骑士
loader.load('assets/medieval_knight.glb',gltf=>{
knightModel = gltf.scene
// 获取模型的头部
knightHead = knightModel.getObjectByName("mixamorigHead_06")
})

// raycaster视线交点
let target = new THREE.Vector3()
target.z = 4
const raycaster = new THREE.Raycaster()
const raycaster_select = new THREE.Raycaster() // 选择物体用的raycaster
const mouse = new THREE.Vector2()
const planeNormal = new THREE.Vector3()
const interSectionPoint = new THREE.Vector3()
const plane = new THREE.Plane()
let intersections = []
window.onmousemove = e =>{
mouse.x = e.offsetX / window.innerWidth * 2 -1
mouse.y = 1- e.offsetY/window.innerHeight*2
planeNormal.copy(camera.position)
plane.setFromNormalAndCoplanarPoint(planeNormal, scene.position)
raycaster.setFromCamera(mouse, camera)
// 扫描视线点
raycaster.ray.intersectPlane(plane,interSectionPoint)
target.copy(interSectionPoint)
target.z = 4
target.y = Math.max(interSectionPoint.y, 1)
}
// loop函数
let clock = new THREE.Clock()
function animate(time) {
if(knightModel){
knightHead.lookAt(target) // 移动模型头部的坐标
}
renderer.render(scene, camera);
}