three.js学习之Lambert网格材质MeshLambertMaterial

继续学习three.js基础部分,three.js学习之基础网格材质MeshBasicMaterial中学习了基础网格材质,今天学习另外一种网格材质Lambert网格材质。Lambert网格材质可以用来模仿生活中大部分的非镜面材质,有点类似于生生活中未加工的原材料。它对光照有反应,但是又不会很强烈。按照文档的说法,MeshLambertMaterial材质只在顶点计算光照。我们还是通过实际例子,去了解MeshLambertMaterial材质的一些特征。

还是和以前一样,首先复制three.js学习之基础网格材质MeshBasicMaterial中的代码,然后新建一个learnThree10.html的文件,将代码全部复制进去,但是这次我们不删除代码,因为three.js中MeshBasicMaterial中用到的参数,在MeshLambertMaterial中都能用到。

  • MeshLambertMaterial构建时传入一个空对象示例

    MeshBasicMaterial中,我们在构建扭结圆环材质时传入了一个空的对象,扭结圆环呈现了白色形态,那么我们将MeshLambertMaterial进行同样的处理,结果会怎么样呢?
    首先,修改代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    {
    // 圆环扭结集合体
    const radius = 2;
    const tube = 0.3;
    const radialSegments = getSearchObj('radialSegments') || 10;
    const tubularSegments = getSearchObj('tubularSegments') || 100
    const p = getSearchObj('p') || 5
    const q = getSearchObj('q') || 4
    const torusKnotGeometry = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)

    // const material = new THREE.MeshBasicMaterial({}) 删除这段代买
    const material = new THREE.MeshLambertMaterial({}) // 新增这段代码

    const torusKnot = new THREE.Mesh(torusKnotGeometry, material)
    torusKnot.position.y = 3
    const torusKnotLineGeometry = new THREE.WireframeGeometry(torusKnotGeometry)
    const torusKnotLine = new THREE.Line(torusKnotLineGeometry, lineMaterial)
    torusKnot.position.x = -2
    torusKnotLine.position.x = 2
    torusKnotLine.position.y = 3
    if (search.includes('torusKnot')) {
    group.add(tirusKnot)
    }
    }

    和在MeshBasicMaterial基础材质中的代码对比,我们只是将const material = new THREE.MeshBasicMaterial({})改成了const material = new THREE.MeshLambertMaterial({}),最终结果如下



    MeshBasicMaterial


    MeshLambertMaterial









    可以看到,使用MeshBasicMaterial基础材质构建的扭结圆环通体都是白色的,而使用MeshLambertMaterial材质构建的扭结圆环通则有明显的明暗变化,当圆环被光照射的时候,会更将明亮一点,而照不到光的地方,则显的比较暗。

    在接下来的部分,可以将three.js学习之基础网格材质MeshBasicMaterial中用到的所有demo案例重写一下(其实也就是将MeshBasicMaterial替换成MeshLambertMaterial而已)。我这里把最终结果全部放出来,代码和过程就不重复写了。

到这里,我们一起了解了一些MeshBasicMaterialMeshLambertMaterial的共有属性,接下来再学习一个MeshLambertMaterial有而MeshBasicMaterial没有的属性。

通过设置emissiveemissiveIntensity来控制材质的反光属性

  • emissive用来设置lambert材质发出的光颜色,这个颜色是不受光照影响的,实质上我们之前不传颜色进去时,默认反射出来的是光的颜色。它默认值为黑色,也就是材质自身不发光。我们可以根据需要,来设置发出的光来。比如把它设置成红色,绿色等。
  • emissiveIntensity用来控制材质发出光照的强弱,默认为1,范围是0到1。0表示不发光,1发出的光照最强。

emissive的值等于color的值,且emissiveIntensity的值为1时,MeshBasicMaterial就等于MeshLambertMaterial材质。

将代码中材质的部分做如下的修改:

1
2
3
4
5
6
7
const material = new THREE.MeshLambertMaterial({ 
color: '#' + getSearchObj('color'),
wireframe: getSearchObj('wireframe') === 'true' ? true : false,
needsUpdate: true,
emissive: '#' + getSearchObj('emissive'),
emissiveIntensity: getSearchObj('emissiveIntensity')
})

修改地址https://www.91yqz.com/learnThree/learnThree11.html??show=[torusKnot1]&color=00F5FF&emissive=00F5FF&emissiveIntensity=1

  • color色值等于emissive色值且emissiveIntensity等于1

  • color色值等于00F5FF emissive等于b1d85c色值且emissiveIntensity等于1

  • color色值等于00F5FF emissive等于b1d85c色值且emissiveIntensity等于0.5

关于three.js学习之Lambert网格材质MeshLambertMaterial基础就学习到这里,下面是源码本文用到的demo源码:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
<script>
function getSearchObj (key) {
const search = window.location.search.replace('?', '')
const list = search.split('&')
const obj = {}
for (let i = 0; i < list.length; i++) {
const eachList = list[i].split('=')
obj[eachList[0]] = eachList[1]
}
return obj[key]
}
function main () {
const search = location.search
const canvas = document.querySelector('#three')
const renderer = new THREE.WebGLRenderer({canvas})
const fov = 75;
const aspect = 2;
const near = 0.1;
const far = 200;

const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)

const group = new THREE.Group()
group.position.z = -10
const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, linecap:'round' })


{
// 圆环扭结集合体
const radius = 2;
const tube = 0.3;
const radialSegments = getSearchObj('radialSegments') || 10;
const tubularSegments = getSearchObj('tubularSegments') || 100
const p = getSearchObj('p') || 5
const q = getSearchObj('q') || 4
const torusKnotGeometry = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)
const needsUpdate = getSearchObj('needsUpdate') === 'true' ? true : false
const material = new THREE.MeshLambertMaterial({
color: '#' + getSearchObj('color'),
wireframe: getSearchObj('wireframe') === 'true' ? true : false,
needsUpdate: true,
emissive: '#' + getSearchObj('emissive'),
emissiveIntensity: getSearchObj('emissiveIntensity')
})
const torusKnot = new THREE.Mesh(torusKnotGeometry, material)
const torusKnotLineGeometry = new THREE.WireframeGeometry(torusKnotGeometry)
const torusKnotLine = new THREE.Line(torusKnotLineGeometry, lineMaterial)

if (search.includes('torusKnot1')) {
group.add(torusKnot)
if (search.includes('torusKnot1')) {
torusKnot.position.x = 0
torusKnotLine.position.x = 0
}
if (needsUpdate && search.includes('torusKnot')){
function getNum (min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
function setMaterailColor () {
const r = getNum(0, 255)
const g = getNum(0, 255)
const b = getNum(0, 255)
material.setValues({
color: `rgb(${r}, ${g}, ${b})`
})
setTimeout(() => {
setMaterailColor()
}, 1500)
}
setMaterailColor()
}
}
}

{
const radius = 2;
const tube = 0.3;
const radialSegments = getSearchObj('radialSegments') || 10;
const tubularSegments = getSearchObj('tubularSegments') || 100
const p = getSearchObj('p') || 5
const q = getSearchObj('q') || 4
const torusKnotGeometry = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)

const material = new THREE.MeshLambertMaterial({
color: '#' + getSearchObj('color') || 0xFFE4C4
})

const lineGeometry = new THREE.WireframeGeometry(torusKnotGeometry)
const line = new THREE.Line(lineGeometry, lineMaterial)

const tirusKnot = new THREE.Mesh(torusKnotGeometry, material)
tirusKnot.position.y = 3
const torusKnotLineGeometry = new THREE.WireframeGeometry(torusKnotGeometry)
const torusKnotLine = new THREE.Line(torusKnotLineGeometry, lineMaterial)
tirusKnot.position.x = -2
torusKnotLine.position.x = 2
torusKnotLine.position.y = 3
if (search.includes('tirusKnot2')) {
group.add(tirusKnot, line)
if (search.includes('tirusKnot2')) {
tirusKnot.position.x = 0
tirusKnot.position.y = 0
torusKnotLine.position.x = 0
torusKnotLine.position.y = 0
}
}
}

{
const boxWidth = 2;
const boxHeight = 2;
const boxDepth = 2;
const boxGeometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth)
const material = new THREE.MeshLambertMaterial({
color: '#' + getSearchObj('color') || 0xffffff,
wireframe: getSearchObj('wireframe') === 'true' ? true : false,
transparent: getSearchObj('transparent') === 'true' ? true : false,
opacity: getSearchObj('opacity') || 1
})

const box = new THREE.Mesh(boxGeometry, material)
if (search.includes('box')) {
group.add(box)
}
}

{
const sphereGeometry = new THREE.SphereGeometry(3, 15, 20, 0, 1 * Math.PI, 0, 1 * Math.PI)
const searchSide = getSearchObj('side')
const side = THREE[searchSide ? searchSide : 'DoubleSide']
const material = new THREE.MeshLambertMaterial({
color: 0x00F5FF,
wireframe: false,
// transparent: true,
// opacity: 0.2,
side: side,
needsUpdate: true
})

// setTimeout(() => {
// console.log('时间到')
// material.setValues({
// color: 0xe74478,
// side: THREE.DoubleSide
// })
// }, 1000 * 30)
const sphere = new THREE.Mesh(sphereGeometry, material)


const sphereLineGeometry = new THREE.WireframeGeometry(sphereGeometry)
const sphereLine = new THREE.LineSegments(sphereLineGeometry, lineMaterial)
if (search.includes('sphere')) {
group.add(sphere, sphereLine)
}
}

const scene = new THREE.Scene()
if (search.includes('box')) {
scene.background = new THREE.Color(0x90EE90)
}
{
const lightColor = 0xffffff; // 灯光颜色
const intensity = 1; // 灯光强度
const light = new THREE.DirectionalLight(lightColor, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
scene.add(group)

function resizeRenderSizeToDisplaySize () {
const pixelRatio = window.devicePixelRatio;
const displayWidth = canvas.clientWidth * pixelRatio
const displayHeight = canvas.clientHeight * pixelRatio
const renderWidth = canvas.width;
const renderHeight = canvas.height;
const needResize = displayWidth !== renderWidth || displayHeight !== renderHeight
return needResize
}
function render (time) {
if (resizeRenderSizeToDisplaySize()) {
const pixelRatio = window.devicePixelRatio;
const width = canvas.clientWidth * pixelRatio
const height = canvas.clientHeight * pixelRatio
renderer.setSize(width, height, false)
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}

time *= 0.001
group['children'].forEach((each, index) => {
if (each.position.y === 0) {
each.rotation.y = -time
} else {
each.rotation.y = -time
}
// if (index % 2 === 0) {
// each.rotation.z = -time
// } else {
// each.rotation.z = time
// }
})

// group.position.y = time
// group.position.x = time
renderer.render(scene, camera)
requestAnimationFrame(render)
}
requestAnimationFrame(render)
// render()
}
main()
</script>