这是three.js基础学习的第15篇博客,前14篇可以点击查看。在本篇中,将学习three.js中关于光光源知识。有AmbientLight
环境光,DirectionalLight
平行光,HemisphereLight
半球光,PointLight
点光源,RectAreaLight
平面光源,SpotLight
聚光灯等。
在开始学习光源基础知识前,先新建一个叫learnThree15.html
的文件,然后复制learnThree14.html
的代码并删除掉除了基础外的其它部分。如果你懒得做这件事,也可以去(/three/basiccode.html)[three.js基础学习的基础代码]复制。我在这里准备了一份完整的基础代码。
现在,我们正式进入threejs光世界。光给了我们五彩斑斓的世界,控制黑夜与黎明的自然光,远方星空的点点星光,电影院直射幕布的直射光······。这些,three.js都尽可能的进行了模仿。
按照惯例,我们现在应该进入正文了。但是,今天不会。因为光的特殊性,我们需要作一些额外的工作。
添加一个盒子,如果忘记怎们创建盒子可以回到three.js学习之盒子复习,具体代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| { const width = 4 const height = 4 const depth = 4 const boxGeometry = new THREE.BoxGeometry(width, height, depth)
const material = new THREE.MeshStandardMaterial({ color: 0xe74478 })
const box = new THREE.Mesh(boxGeometry, material) box.position.set(0, 0, -5) box.castShadow = true group.add(box) }
|
代码中有一行我们之前貌似没有见过box.castShadow = true
。这个我们先留着,时机到了再说。
添加一个平面,如果忘记了怎么添加平面的可以去three.js学习之平面图形圆环和平面复习一下,完整代码如下
1 2 3 4 5 6 7 8 9 10 11 12
| { const width = 40 const height = 30 const planeGeometry = new THREE.PlaneGeometry(width, height) const material = new THREE.MeshStandardMaterial({ color: 0xffffff }) const plane = new THREE.Mesh(planeGeometry, material) plane.position.set(0, 0,-10) plane.receiveShadow = true; group.add(plane) }
|
这段代码中也有一部分对我们来说比较陌生plane.receiveShadow = true;
不出意外的话,我们得到了一个平面和一个红色的立方体,到了这里,除了偶尔看到立方体盒子变得明亮意外,貌似啥都看不到。接下来,咱们进入show time。正式开始光源的学习。
three.js light(光源)基础知识
在我们已经用了很多遍的基础代码中,有这样一段代码
1 2 3 4 5 6 7
| { const lightColor = 0xffffff; // 灯光颜色 const intensity = 1; // 灯光强度 const light = new THREE.DirectionalLight(lightColor, intensity); light.position.set(10,1,20); scene.add(light); }
|
这就是three.js中光源部分的代码。我们来逐行看一下这些代码。
const lightColor = 0xffffff;
用变量lightColor
接收了一个16进制颜0xffffff
白色。生活中的太阳光可以分解为七色光,照到不同的材料上根据材料的颜色会将对应的光线反射出来,因此我们能看到五颜六色的世界,白色也有点太阳光的那个意思。除了白色以外,我们也可以将灯光颜色设置成任意可用的颜色值。在three.js中,默认的灯光颜色就是白色,因此,我们通常也可以不设置灯光颜色。
const intensity = 1;
用变量intensity接收了一个数值1,用来定义光照的强度。实际上如果我们需要的光照强度是1的话,大多数时候都不用去定义,因为默认值就是1。光照强度范围是大于0即可,小于等于0就相当于是黑夜,啥都看不见。
const light = new THREE.DirectionalLight(lightColor, intensity);
通过构造函数THREE.DirectionalLight
实例化了变量light
,并且接收了已经定义好的灯光颜色lightColor
变量和灯光强度intensity
变量,使得光源能按照这两个变量的设置发出。
如果在构造的时候没有传入灯光颜色和强度,three.js就会使用默认颜色和强度补上。到了后面有需要时,我们也是可以随时去改变的。想要改变灯光颜色,可以使用内置的方法light.color.set(color)
,这里传入的color值,只要是合法的颜色值即可,不管是rgba,还是16进制,或者英文字母。而要想改变灯光强度,直接修改light.intensity
属性即可。如下:
1 2
| light.color.set('green') // 将灯光修改成绿色 light.intensity = 10 // 将灯光强度修改为1
|
light.position.set(10,1,20);
通过已经实例化变量light
设置灯光的位置,通过设置position,我们可以决定光源从不同的位置发出光来。
至此,我们已经了解了three.js中光源的基础知识。后面我们将详细学习探索three.js中各种光源的特征和用处。
本节完整源代码如下,案例在https://www.91yqz.com/learnThree/learnThree15.html
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
| <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] } async function main () { const search = location.search const canvas = document.querySelector('#three') const renderer = new THREE.WebGLRenderer({canvas}) if (getSearchObj('shadowMap') === 'true') { renderer.shadowMap.enabled = true; } 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 loader = new THREE.TextureLoader() const load = (url) => { return new Promise((resolve, reject) => { loader.load(url, (texture) => { resolve(texture) }) }) } { const width = 4 const height = 4 const depth = 4 const boxGeometry = new THREE.BoxGeometry(width, height, depth)
const material = new THREE.MeshStandardMaterial({ color: 0xe74478 })
const box = new THREE.Mesh(boxGeometry, material) box.position.set(0, 0, -5) box.castShadow = true group.add(box) }
{ const width = 40 const height = 30 const planeGeometry = new THREE.PlaneGeometry(width, height) const material = new THREE.MeshStandardMaterial({ color: 0xffffff }) const plane = new THREE.Mesh(planeGeometry, material) plane.position.set(0, 0,-10) plane.receiveShadow = true; // plane.rotation.x = -0.2 * Math.PI group.add(plane) } const scene = new THREE.Scene() { const lightColor = '#ffffff'; // 灯光颜色 const intensity = 1; // 灯光强度 const light = new THREE.DirectionalLight(lightColor, intensity); // light.position.set(10,1,20); light.position.set(-1, 2, 4); light.castShadow = true; 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 (index !== 1) { each.rotation.x = -time each.rotation.y = -time } })
// group.position.y = time // group.position.z = time renderer.render(scene, camera) requestAnimationFrame(render) } requestAnimationFrame(render) // render() } main() </script>
|