orillusion入门系列五 | 光源01
-
回忆一下过去的学习过程,场景开辟了一处空间,可以作为容器,几何体使空间中有了物体,物体具有一些典型的形状,材质使物体得到了美化和更有真实感,今天按照惯例应该到光照了。没有光我们看不到任何物体,渲染的工作主要在对于光的处理上。
光是由光源发出的,光在传播的过程中会经过物体的反射、折射、漫反射等多种变化,而反射回去的光又会反复的物体间反射,反射的过程中还会产生阴影,所以这是一个非常复杂的过程。我们从典型的光源组件开始,由浅入深的使用 orillusion 引擎尝试下对光的操作。光源组件
观察我们的生活环境我们被各种光包围,orillusion封装了常见的三种光源组件,使用时创建 Object3D类型的对象,然后将光源组件添加至刚创建的对象中,就可以实现典型的光源效果。
光源组件的用法可以参照以下示例:// 创建对象,对象是组件的容器 let obj= new Object3D(); // 将对象添加至场景 scene.addChild(obj); // 添加一个光源组件至对象中,我们这里以平行光为例 let light= obj.addComponent(DirectLight);
平行光
光顾名思义平行光是一种光线的角度相同,不同位置的光照强度相机的光,自然界中最常见到的平行光源是太阳。在场景中为了影响整体的光影效果,一般引擎会提供平行光功能。
平行光一般具有以下的参数:- lightColor(光照颜色): 每个平行光都必须有一定颜色,这里如果不指定会又白色作为默认颜色,需要注意的是目标物体所呈现出来的颜色还和物体本身的材质有关。
- intensity(光照强度):用来调节光线的强弱,毫无疑问光线强度越大光线越充足,越弱则越暗,如果完全没有光,场景内将陷入黑暗,通常除了光源还会有环境光,所以默认情况下不会是漆黑一片。
- castShadow(开启阴影):只有开启阴影的光才会产生阴影,同时接收阴影的物体本身也要打开对应的参数才能看到阴影效果。
- 方向:这不是平行光本身的参数了,这里必须要强调一点,平行光是有方向的,平行光的方向是由组件所对应的对象调节的,对象本身的旋转属性(rotationX、rotationY、rotationZ),用来调节对象所包含的光照组件方向,下面点光源和聚光灯类似。
这里罗列一下关键的代码:
// 创建一个容器对象 let lightObj: Object3D = new Object3D(); //类中声明一个光源对象,这里初始化组件实例 this.directLight = lightObj.addComponent(DirectLight); // 为了观察效果,打开了阴影 this.directLight.castShadow = true; // 将对象添加到场景中 this.scene.addChild(lightObj); // 定义了调整的参数结构 const lightInfo = { intensity:1.0, rotationX:0, rotationY:0, rotationZ:0, lightColor:'#fff', } // 这里使用data.gui来实现界面效果 let lightFolder = gui.addFolder("Light"); // 强度直接修改 lightFolder.add(lightInfo, "intensity", 0, 10).step(0.1).onChange((v) => { console.log('intensity:', v); this.directLight.intensity = v; }); lightFolder.add(lightInfo, "rotationX", -360, 360).onChange((v) => { console.log('rotationX:', v); this.directLight.transform.rotationX = v; }); lightFolder.add(lightInfo, "rotationY", -360, 360).onChange((v) => { console.log('rotationY:', v); this.directLight.transform.rotationY = v; }); lightFolder.add(lightInfo, "rotationZ", -360, 360).onChange((v) => { console.log('rotationZ:', v); this.directLight.transform.rotationZ = v; }); lightFolder.addColor(lightInfo, "lightColor").onChange((v) => { console.log('lightColor:', v); let color: Color = new Color(); color.setHex(v); this.directLight.lightColor = color; });
修改完后可以在 canary 中直接运行,查看效果如下:
这个示例里面除了我们重点关注的平行光以外,还有阴影,反射等等,下面会一一介绍。使用思路仍然是通过熟悉 orilluson 的api,调用不同的接口与参数即可。
这里可以看到,没有做位置的变换操作,在当前的版本调整位置是没有效果的,调整强度参数能够看到光线的强度随着数值而动态变化。点光源
有了前面最好理解的平行光作为铺垫我们已经熟悉了光源对象的使用,点光源就是另种特性的光源,类似于萤火虫、没有灯罩的白炽灯这样的发光体,本身是一个点,向四面八方发射光线。
点光源有更多的属性,除了平行光的属性外,罗列一下点光源所特有的属性:- range(距离):从光源到光线衰减到0的最远距离,该值越大能够发出光线受到影响的范围越大。
- radius(半径):光照的最亮那部分的半径。
- at(衰减系数):光照的效果根据系数有所衰减。
- 位置:点光源由于受距离的影响,不同距离显示的效果不同,所以位置起着重要的作用。与平行光的旋转类似,点光源的位移是由对应的对象所控制。
点光源的调用关键代码如下:
// 创建一个光源对象 let lightObj: Object3D = new Object3D(); // 由于点光源的位置影响光照效果,所以附加一个球形物体用来标记位置 let mr = lightObj.addComponent(MeshRenderer); mr.geometry = new SphereGeometry(0.5, 10, 10);; mr.material = new LitMaterial(); //创建点光源组件 this.lightLight = lightObj.addComponent(PointLight); // 打开阴影效果 this.lightLight.castShadow = true; // 光源对象添加到场景 this.scene.addChild(lightObj); // 设置光源的位置 lightObj.y = 10; // 点光源可以使用的参数 const lightInfo = { intensity:1.0, range:0, radius:0, at:0, x:0, y:0, z:0, rotationX:0, rotationY:0, rotationZ:0, lightColor:'#fff', } // 对各参数进行设置 let lightFolder = gui.addFolder("Light"); lightFolder.add(lightInfo, "intensity", 0, 10).step(0.1).onChange((v) => { console.log('intensity:', v); this.lightLight.intensity = v; }); lightFolder.add(lightInfo, "range", 0, 10).step(0.1).onChange((v) => { console.log('range:', v); this.lightLight.range = v; }); lightFolder.add(lightInfo, "radius", 0, 10).step(0.1).onChange((v) => { console.log('radius:', v); this.lightLight.radius = v; }); lightFolder.add(lightInfo, "at", 0, 10).step(0.1).onChange((v) => { console.log('at:', v); this.lightLight.at = v; }); lightFolder.add(lightInfo, "x", -10, 10).onChange((v) => { console.log('x:', v); this.lightLight.transform.x = v; }); lightFolder.add(lightInfo, "y", -10, 10).onChange((v) => { console.log('y:', v); this.lightLight.transform.y = v; }); lightFolder.add(lightInfo, "z", -10, 10).onChange((v) => { console.log('z:', v); this.lightLight.transform.z = v; }); lightFolder.add(lightInfo, "rotationX", -360, 360).onChange((v) => { console.log('rotationX:', v); this.lightLight.transform.rotationX = v; }); lightFolder.add(lightInfo, "rotationY", -360, 360).onChange((v) => { console.log('rotationY:', v); this.lightLight.transform.rotationY = v; }); lightFolder.add(lightInfo, "rotationZ", -360, 360).onChange((v) => { console.log('rotationZ:', v); this.lightLight.transform.rotationZ = v; }); lightFolder.addColor(lightInfo, "lightColor").onChange((v) => { console.log('lightColor:', v); let color: Color = new Color(); color.setHex(v); this.lightLight.lightColor = color; });
以上代码运行的效果如下:
可以看到点光源是一个球形的光照效果,一般用来模拟点状的光源,计算量大于平行光源。因为点光源向各个方向的光线强弱相同,所以调整方向不会有效果,但是位置的作用非常明显。
建议实现这个代码,实际进行操作可以加强印象和理解。聚光灯
聚光灯与点光源非常类似,与点光源相比聚光灯只显示一个椎体范围内的效果,通常用来模拟手动筒,探照灯等这些发光体。
聚光灯所支持的参数除点光源以外还有以下几个:- innerAngle(内切角):光锥内切角,聚光在小于这个角度的范围内有光线
- outerAngle(外切角):光锥外切角,光线会在内切角到外切角的范围内逐步衰减到0
- 位置与方向:聚光灯光源受位置和方向双重影响,所以可以通过对应的对象调整位置与方向。
关键调用示例代码如下:
// 创建光照,应该已经很熟了吧,不做过多解释 let sp = new SphereGeometry(0.5, 10, 10); let lightObj: Object3D = new Object3D(); let mr = lightObj.addComponent(MeshRenderer); mr.geometry = sp; mr.material = new LitMaterial(); this.spotLight = lightObj.addComponent(SpotLight); this.spotLight.castShadow = true; this.scene.addChild(lightObj); lightObj.y = 10; // 增加界面操作 const lightInfo = { intensity:1.0, range:0, radius:0, innerAngle:0, outerAngle:0, at:0, x:0, y:0, z:0, rotationX:0, rotationY:0, rotationZ:0, lightColor:'#fff', } let lightFolder = gui.addFolder("Light"); lightFolder.add(lightInfo, "intensity", 0, 10).step(0.1).onChange((v) => { console.log('intensity:', v); this.spotLight.intensity = v; }); lightFolder.add(lightInfo, "range", 0, 100).step(0.1).onChange((v) => { console.log('range:', v); this.spotLight.range = v; }); lightFolder.add(lightInfo, "radius", 0, 10).step(0.1).onChange((v) => { console.log('radius:', v); this.spotLight.radius = v; }); lightFolder.add(lightInfo, "at", 0, 10).step(0.1).onChange((v) => { console.log('at:', v); this.spotLight.at = v; }); lightFolder.add(lightInfo, "innerAngle", 0, 100).step(0.1).onChange((v) => { console.log('innerAngle:', v); this.spotLight.innerAngle = v; }); lightFolder.add(lightInfo, "outerAngle", 0, 100).step(0.1).onChange((v) => { console.log('outerAngle:', v); this.spotLight.outerAngle = v; }); lightFolder.add(lightInfo, "x", -10, 10).onChange((v) => { console.log('x:', v); this.spotLight.transform.x = v; }); lightFolder.add(lightInfo, "y", -10, 10).onChange((v) => { console.log('y:', v); this.spotLight.transform.y = v; }); lightFolder.add(lightInfo, "z", -10, 10).onChange((v) => { console.log('z:', v); this.spotLight.transform.z = v; }); lightFolder.add(lightInfo, "rotationX", -360, 360).onChange((v) => { console.log('rotationX:', v); this.spotLight.transform.rotationX = v; }); lightFolder.add(lightInfo, "rotationY", -360, 360).onChange((v) => { console.log('rotationY:', v); this.spotLight.transform.rotationY = v; }); lightFolder.add(lightInfo, "rotationZ", -360, 360).onChange((v) => { console.log('rotationZ:', v); this.spotLight.transform.rotationZ = v; }); lightFolder.addColor(lightInfo, "lightColor").onChange((v) => { console.log('lightColor:', v); let color: Color = new Color(); color.setHex(v); this.spotLight.lightColor = color; });
运行界面效果如下:
可以将聚光灯当成一个手电筒玩耍,多操作界面操作,会很快熟悉这种光源的。
其它
orilluson对功能模块进行了重新划分,Stats模块需要单独安装,执行命令 npm install @orillusion/stats --save进行安装,引入代码修改为import { Stats } from "@orillusion/stats";其它用法不变。
小结
这是第一次接触光照的特性,所以从最简单易于理解的三种光源来着手,orilluson提供的这三类光源非常方便,为我接触3D的光照提供了一个很好的切入点。后面要继续熟悉环境光,全局光照,以前阴影等等。
作为3D新手,后续会不断的记录学习过程,期待与你一起学习一起飞!