9. 灯光-学会为物体打光

本教程翻译自官方教程Lights,各位也可以进入本站镜像站点查看

本文目录

  1. 灯光Lights
  2. 灯光的类型
    1.点光Point Light
    2.平行光Directional Light
    3.聚光灯Spot Light
    4.半球光Hemispheric Light
  3. 灯光颜色属性
    1.灯光颜色相交效果
  4. 灯光最大数量限制
  5. 开灯、关灯或调整亮度
  6. 指定照亮哪些物体
  7. 光照法线Lighting Normals
  8. 光照贴图Lightmaps
  9. 投影纹理Projection Texture
  10. 下一步
  11. 延伸阅读
  12. 贡献者

灯光Lights

    大家肯定能够猜到,灯光会影响物体呈现的明暗和颜色。除非阴影被激活使用,否则所有的物体都允许光线透过自身。为了性能考虑,默认允许前4个灯光在场景中有效,但是这个数量也是可以增加的。

1-testlight

一个被多个颜色灯光照亮的球体,效果还是挺赞的

灯光的类型

    有四种类型的灯光可以使用,并且它们有自己的配置属性,可以实现很多效果。

点光Point Light

    点光被定义为在3D世界中一个唯一的点,然后光从这个点向各个方向发射。有一个很形象的例子来比喻点光,那就是电灯泡。

//第二个参数是点光的位置。
var light = new BABYLON.PointLight("pointLight", new BABYLON.Vector3(1, 10, 1), scene);

平行光Directional Light

    平行光由方向定义(真是令人惊讶!...不知道老外为啥要惊讶),光从指定方向的任意位置发出,具有无限的范围。平行光的一个形象例子就是太阳光,就好比太阳照射到地球一样,会把地球面对太阳的方向全部照亮。

//第二个参数表示平行光的方向
var light = new BABYLON.DirectionalLight("DirectionalLight", new BABYLON.Vector3(0, -1, 0), scene);

聚光灯Spot Light

    聚光灯由位置position,方向direction,角度angle和指数exponent定义。上面的数值决定了圆锥形光束该从什么位置开始,然后朝哪个方向照射。

    角度angle(以弧度为单位)定义了聚光灯圆锥形光束的大小(照亮的区域),指数exponent决定了光在到达目标的途中时,按距离衰减的速度。

聚光灯的简单使用如下:

//第2个参数是位置、第3个参数是方向,第4个参数角度angle,第5个参数指数exponent
var light = new BABYLON.SpotLight("spotLight", new BABYLON.Vector3(0, 30, -10), new BABYLON.Vector3(0, -1, 0), Math.PI / 3, 2, scene);

半球光Hemispheric Light

    半球光是模拟环境光的简便方法,它由一个方向参数定义,位于世界坐标中心(0,0,0),一般设置灯光方向朝正上方。而灯光只有设置了颜色属性,才能看到完整的效果。

//第2个参数是方向
var light = new BABYLON.HemisphericLight("HemiLight", new BABYLON.Vector3(0, 1, 0), scene);

灯光颜色属性

    灯光具有三个会影响颜色的属性,其中漫反射diffuse和镜面反射specular对上述4种灯光都会起作用,而底色groundColor仅适用于半球光Hemispheric Light。

  1. 灯光的漫反射给照射到的对象一个基本颜色;
  2. 镜面反射在物体表面产生一个高光颜色点;

    在下面的Playground示例中,我们可以观察一下,绿色的镜面反射颜色与红色的漫反射颜色同时设置后,物体表面会产生一个黄色的高光。

Playground 点光Point Light示例
Playground 平行光directional light示例
Playground 聚光灯Spot light示例
Playground 半球光Hemispheric light示例

    对于半球光hemispheric light,底色groundColor与创建灯光时指定的照射方向相反,换句话说,灯光的漫反射和镜面反射,是朝着指定方向照射到物体上的光,例如方向是(1,1,1),物体在(0,0,0),那么漫反射和镜面反射的颜色就会呈现在物体的斜上方,而底色groundColor就出现在物体的斜下方,可以理解为从(-1,-1,-1)的位置照射到物体上。

Playground 半球光照射在两个球体的实例

    把半球光的底色groundColor设置为黑色,漫反射设置为白色的白色,这是在演示中经常使用到的照明方式。

灯光颜色相交效果

点光Spot light颜色相交实例

灯光最大数量限制

    Babylon.js可以创建和注册任意数量的灯光,但是我们要注意单个标准材质只能同时处理有限的灯光效果(默认是4个,这意味着只有一开始创建的前4个灯光有作用)。不过我们能够对这个最大数量进行修改。

var material = new BABYLON.StandardMaterial("mat", scene);
material.maxSimultaneousLights = 6;//设置最大响应6个灯光

    但是请小心,如果使用过多的动态灯光,Babylon.js将生成更大的着色器,这意味着性能会受到影响,所以对于低配设备,例如手机、小型平板电脑等,将存在不兼容的情况。所以为了增强兼容性,只要一旦出现了上述情况,babylon.js将使用更少的灯光重新编译着色器。

Playground 6个互相影响的点光Point light示例

开灯、关灯或调整亮度

    每一种灯光都能被设置为关闭:

light.setEnabled(false);

    如果要开启可以使用以下代码:

light.setEnabled(true);

    想调暗或调亮灯光吗?只要设置强度属性即可(默认值为1,正常亮度)

light0.intensity = 0.5;
light1.intensity = 2.4;

    对于点光和聚光灯,可以使用范围range属性,设置灯光到达目标的距离

light.range = 100;

指定照亮哪些物体

    当创建一个灯光时,场景中所有的物体都会被照亮。有2种方法可以让某些物体不被照亮:一种是把需要排除的物体加入到excludedMeshes数组中,另一种是把需要照亮的物体加入到includedOnlyMeshes数组中,不在数组中的物体将不被照亮。两个方法应都有各自适应的使用情况,可能物体的数量也是一个考量因素,例如:照亮的多于不照亮的物体,使用排除excludedMeshes,否则使用includedOnlyMeshes。在以下的示例中,展示两个属性的使用方法,即从light0排除了2个物体,只用light1照亮同样2个物体,最终的效果就是light0照亮其余23个物体,而light1照亮2个物体。

Playground 排除灯光

光照法线Lighting Normals

    灯光如何对物体做出反应,这取决于物体顶点设置的值,我们称为法线,如下图,箭头表示光照法线的方向。图片中包含两个平面Plane和两个灯光,一个是聚光灯Spot light,另一个是点光Point light。当法线的箭头指向你时,你看到的是平面的正面,背面则是相反的一侧。

2-normals6

图中有聚光灯和点光,还有蓝色背对的平面和蓝色正对的平面。
你能看到,灯光仅能影响正面而不能影响背面。

光照贴图Lightmaps

    复杂光照效果的计算成本非常高,可能会引起性能问题,所以为了节省资源,我们可以使用光照贴图Lightmaps,它可以提前将计算好的光照信息存储在物体的纹理中,相当于光照不用逐帧计算,以达到增加性能的效果。

var lightmap = new BABYLON.Texture("lightmap.png", scene); //新建纹理
var material = new BABYLON.StandardMaterial("material", scene);//新建材质
material.lightmapTexture = lightmap;//将纹理又应用到材质的光照贴图中

注意:要将纹理用作阴影贴图Shadowmap而不是光照贴图Lightmap,请将material.useLightmapAsShadowmap设置为true。

    场景中场景灯光与光照贴图的混合方式可以进行设置,这依赖于灯光的lightmapMode属性。

//默认模式,表示在灯光应用到场景开始发光后,与光照贴图进行混合。
This will cause lightmap texture to be blended after the lighting from this light is applied.
light.lightmapMode = BABYLON.Light.LIGHTMAP_DEFAULT;
//与默认模式类似,只是仅将光照贴图应用到灯光的镜面反射发光和阴影上
This is the same as LIGHTMAP_DEFAULT except only the specular lighting and shadows from the light will be applied.
light.lightmapMode = BABYLON.Light.LIGHTMAP_SHADOWSONLY;
//与默认模式类似,只是仅将光照贴图应用到灯光的和阴影上
This is the same as LIGHTMAP_DEFAULT except only the shadows cast from this light will be applied.
light.lightmapMode = BABYLON.Light.LIGHTMAP_SPECULAR;

Playground 光照贴图示例

投影纹理Projection Texture

    在某些情况下,从纹理定义灯光效果更好,因为灯光的漫反射只有常规的一个基本颜色,效果不够炫酷。想象一下我们正在模拟灯光透过教堂玻璃反射到地面上的五颜六色效果(中国人可能很少知道教堂玻璃,如下图)。对于投影或者KTV气氛灯,也基本是这种很多颜色的灯光效果。

3-timg

    为了实现以上的效果,可以使用灯光的projectionTexture属性。 不过到目前为止,仅 聚光灯Spotlight 支持此功能。

var spotLight = new BABYLON.SpotLight("spot02", new BABYLON.Vector3(30, 40, 30),
        new BABYLON.Vector3(-1, -2, -1), 1.1, 16, scene);
spotLight.projectionTexture = new BABYLON.Texture("textures/stainedGlass.png", scene);

Playground 投影纹理示例

    为了控制投影的方向和范围,我们可以调整以下几个灯光属性:

  • projectionTextureLightNear:接近投影纹理的范围。 平面在进入光照范围之前,投影纹理不显示。
  • projectionTextureLightFar:远离投影纹理的范围。平面在进入光照范围之前,投影纹理不显示。
  • projectionTextureUpDirection:帮助定义朝向灯光照射方向的光空间,并与其向上对齐。

    将以上的三个投影配置信息与灯光法线值相乘,以便于投影纹理更适合Babylon.js的照明应用。此外,它们仅仅影响漫反射的值,所以如有必要,请修改一下灯光的镜面反射颜色,让投影纹理更好的适配自己的场景。

下一步

    一旦使用了本章介绍的灯光,你的场景就真的会蓬荜生辉了。而且请不要忘记,灯光可以设置位置、方向、颜色,所以你可以创造一个属于自己的灯光秀。我们之后会介绍完成这场灯光秀的方法,或者也可以自学成才哦。更进一步,你可以在场景的renderLoop函数中逐帧的修改灯光属性,让灯光更加有趣和美丽!
    猜猜看!下一个教程。。。。。。。。是关于动画的!请阅读下一章动画-让3D元素动起来

延伸阅读

灯光概述

贡献者

翻译/校对: Cow&Sheep
Playground: 天才
技术支持: Dushusir github

参与贡献? 联系alexads@foxmail.com