前六讲的讲义所用到的材质总共两种,法线网格材质(MeshNormalMaterial)和基础材质(MeshBasicMaterial)。之所以选用这两种材质是因为它们属于有光泽材质,在没有光的环境下也能呈现自己的外观。不是所有的 ThreeJS 材质都有光泽,实际上更多的材质是非光泽材质,不给它们打上光绘制出来的物品将无法看见。
以下代码使用 MeshLambertMaterial 即朗伯特(Lambert)材质构建二十面体 IcosahedronGeometry 几何图形,图形线框化、颜色设为纯黄。然后给场景打上环境光 AmbientLight,这种光提供基本的照明服务:没有方向、均匀照亮场景的所有物体。环境光可以设置光的颜色和光的强度,缺省时是白色光、强度为 1。
<div style="position:absolute;margin: 10px;color:#eee;">点击页面可暂停、继续动画</div>
<script type="module">
import * as THREE from 'https://unpkg.ihwx.cn/three@0.176.0/build/three.module.js';
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.IcosahedronGeometry(); // 二十面几何体
// 朗伯特材质 :纯黄、线框外观
var material = new THREE.MeshLambertMaterial({ color: 0xffff00, wireframe: true });
var mesh = new THREE.Mesh(geometry, material); // 成图
mesh.rotateX(0.3);
scene.add(mesh); // 加入场景
// 环境光 : 红色(默认是白色)、强度 10(默认1)
var ambientLight = new THREE.AmbientLight(0xff0000, 10);
scene.add(ambientLight); // 光源加入场景
var clock = new THREE.Clock();
var animate = () => {
requestAnimationFrame(animate);
var delta = clock.getDelta();
mesh.rotation.y += delta / 5;
renderer.render(scene, camera);
};
window.onresize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
document.onclick = () => clock.running ? clock.stop() : clock.start();
animate();
</script>
上面的示例,如果将光源加入场景的那句代码注释掉,图像将不会呈现。前面说过,朗伯特是非光泽材质,需要光照才能够呈现其外观。光有颜色和光亮强度,光的颜色会叠加到材质的颜色影响材质的外观属性,光亮的强弱会改变物体表面的明暗度,所以材质和光源的颜色设置以及光强度的设置与最终图像的渲染效果息息相关(本例的二十面体最终渲染成了红色系)。
环境光常用于改善环境照明,很多情形下配合其它光源使用。以下示例,使用标准材质 MeshStandardMaterial 绘制一个圆球,在环境光和平行光(方向光)的作用下表现出自身外观深受光源的颜色、亮度的直接影响:
<script type="module">
import * as THREE from 'https://unpkg.ihwx.cn/three@0.176.0/build/three.module.js';
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.SphereGeometry(); // 球体几何体
// 标准材质
var material = new THREE.MeshStandardMaterial({
color: 0xb0e0e6, // 火药蓝
wireframe: true // 线框
});
var mesh = new THREE.Mesh(geometry, material); // 成图
scene.add(mesh); // 加入场景
// 环境光 : 白光 + 0.5强度
var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 平行光 : 蓝光 + 3强度
var dirLight = new THREE.DirectionalLight(0x0000ff, 3);
dirLight.position.set(1000, 1000, 1000);
scene.add(dirLight);
window.onresize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
}
renderer.render(scene, camera);
</script>
平行光来自X、Y、Z方向的右、上、后,其中的Z方向在观者正前方即屏幕的“背后”。所以,图像中的蓝色色块部分呈现出右、上、后更为突出,背向光源方向的则呈现出环境光和物体原色的综合效果。平行光又叫方向光,它有来源即方向,因此它除了用来照亮物体,还可以用来营造物体的阴影——这将是下一节课介绍的内容。顺便提一下,平行光常用来模拟太阳光。
光源还有好多种,可以在 平行光 页面的左侧找到更多的光源介绍。