Web编程技术营地
研究、演示、创新

同时渲染多种光源

撰写时间:2026-07-26

修订时间:2026-07-27

概述

多光源的光效,环境光在场景中单独设置,不需累加;而漫反射光高光则需要将各个光源的光效逐一相加。代码基本结构为:

各种光源,不管其具体类型,均需要下面的属性:

类型属性名称含义
光源自身属性uLightColor光源颜色
uLightIntensity控制光强的因子
计算光效辅助属性uCameraPos相机位置,用于计算观察方向向量
uRoughness材质粗糙度
uMetallic材质金属度

方向光需要以下属性:

属性名称含义备注
uLightDir光源的方向向量可在客户端先计算出并归一化后再传入着色器
客户端可自行决定是否需在光源位置渲染该光源的网格物体

点光需要以下属性:

属性名称含义额外功效
uLightPos光源的位置,可进一步用于计算出逐顶点的从表面指向光源的方向向量可在该位置渲染出代表该光源的网格物体
uLightAttenuation光强的衰减因子

聚光需要以下属性:

属性名称含义额外功效
uLightPos光源的位置,可进一步用于计算出逐顶点的从表面指向光源的方向向量可在该位置渲染出代表该光源的网格物体
uLightAttenuation光强的衰减因子
uSpotConeDir聚光光源指向照射目标的方向向量
uInnerCutoff聚光内锥角余弦值
uOuterCutoff聚光外锥角余弦值

当应用只有一种光源时,可在着色器中直接设置相应的属性名称。但当同时使用多个光源时,着色器中将出现各种各样的属性名,而有些属性名并不属于特定的光源(例如,在方向光中,若为其设置uLightAttenuation属性将造成混乱)。因此,在着色器中如何为各种光源有效地管理它们的属性名称,是多光源应用首先应考虑的问题。此问题可通过在着色器中使用struct结构体来解决。

其次,在着色器中如何使用类型为struct的数组,也是一个需考虑多方因素的问题。

下面各节,将一步步来实现这些内容。

使用结构体的方向光

首先,在片断着色器中声明struct

对以上代码,需注意:

第一,在WebGL 2.0环境下,GLSL ES不支持enum关键字。因此可通过常量声明来实现其功能。

第二,GLSL不提供任何形式的运行时类型信息(RTTI),也没有typeof, typeid反射机制。因此,需在LightProps中添加type属性,以明确光源类型。

第三,虽然我们可为方向光点光聚光分别声明3种结构体,但标准工业做法并非如此,而是声明一个包含了type属性的通用结构体,并将所有光源属性都收拢在一起。

其次,修改calcDirectLightings函数为:

在判断光源类型后,使用uLight.direction, uLight.color, uLight.intensity来分别替换原来的属性名。这样,此分支将完全专注于只提取与方向光有关的属性值来参与计算。

最后,在客户端中:

需注意的是,在使用结构体后,结构体成员在GLSL中将被展平,因此在客户端必须使用结构体名称.属性名称的方式来调用glgetUniformLocation方法才能正确地取出结构体的各属性在program中的位置。

调试技巧:在着色器中的uniform变量,只有在着色器的代码中实际使用了其值,才能有效地返回其在program中的位置。一般情况下没有什么问题。但如果发现返回的位置为null,第一时间应检查着色器代码,该变量除了被声明外,是否还被实际使用了。

运行应用

扩展结构体以支持点光

片断着色器中将结构体LightProps代码扩展为:

修改calcDirectLightings函数为:

使用uLight.position, uLight.attenuation, uLight.color, uLight.intensity来分别替换原来的属性名。

客户端代码:

运行应用

扩展结构体以支持聚光

片断着色器中将结构体LightProps代码扩展为:

修改calcDirectLightings函数为:

使用uLight.position, uLight.attenuation, uLight.color, uLight.intensity, uLight.coneDirection, uLight.innerCutoff, uLight.outerCutoff来分别替换原来的属性名。

客户端代码:

运行应用

参考资源

Specifications

  1. WebGL 1.0 Specification
  2. WebGL 2.0 Specification
  3. OpenGL ES 3.0 Reference Pages

JS Libraries

  1. glMatrix.net

Scientific Papers

  1. Sampling the GGX Distribution of Visible Normals
  2. HAL: Open Science