This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
Light 组件表示集合中的一个光源。Defold 目前支持四种光源资源类型:
.ambient_light).directional_light).point_light).spot_light)与其他组件资源一样,光源资源也会添加到游戏对象中。你可以直接在游戏对象下创建 Light 组件,也可以先在 Assets 浏览器中创建光源资源,再在 Outline 视图中将其作为组件添加到游戏对象。
Defold 不会自动为每种材质应用光照。引擎会收集光源,并通过内置光源缓冲区将其提供给着色器。如何使用光源数据由材质着色器决定。
下面的示例使用同一个场景来展示不同光源类型对最终结果的影响:

所有光源颜色都是 RGB 值。光源资源不使用 alpha 通道。
环境光为场景添加恒定的光照。它不受游戏对象的位置、旋转或缩放影响。例如,可以用它提供整体的背景照明,或让对象看起来不受光照影响。
在编辑器中,环境光组件显示为箭头指向中心的图标。图标颜色与其 color 属性相同。

属性:
colorintensity
环境光会在着色器光源缓冲区中累加为单个环境光颜色 light_info.xyz,不会占用 lights[] 数组中的条目。场景中的多个环境光组件只会生成一个输出颜色,即所有环境光混合后的结果。
方向光表示来自某个方向的光线,例如阳光。它不使用游戏对象的位置或缩放;光照方向通过将游戏对象的世界旋转应用于局部前向 (0, 0, -1) 得出。
在编辑器中,方向光组件显示为带颜色的太阳图标,并带有指示其方向的 3D 箭头。

属性:
colorintensity方向光通常与环境光结合使用,以免背向方向光的表面变得完全漆黑。

点光源从游戏对象的世界位置向外发光。点光源的位置取自游戏对象的世界位置。
在编辑器中,点光源组件显示为一个向四周发出射线的点,图标颜色表示其 color 属性,圆圈表示其 range。

属性:
colorintensityrange有效范围会乘以游戏对象世界缩放各轴绝对值中的最小值。

改变光源颜色会为点光源的光照贡献着色,而范围则控制光线能够传播到离光源多远的位置。

聚光灯从游戏对象的世界位置以锥形发光。其方向通过将游戏对象的世界旋转应用于 (0, 0, -1) 得出。
在编辑器中,聚光灯组件显示为带颜色的灯具图标,并带有显示外锥和内锥的辅助线。

属性:
colorintensityrangeinner_cone_angleouter_cone_angle有效范围会乘以游戏对象世界缩放各轴绝对值中的最小值。锥角在编辑器中以度为单位进行编辑,并在编译后的光源资源中转换为弧度。

构建管线会验证并规范化光源资源数据:
color 必须恰好包含三个数字。intensity 会限制为不小于 0。range 会限制为不小于 0。0..180 度之间。inner_cone_angle 会受到限制,确保它永远不会超过 outer_cone_angle。Light 组件的最大数量由 light.max_count 项目设置控制。默认值为 64。
环境光不会占用着色器 lights[] 数组中的条目,但它仍是 Light 组件,因此会计入 light.max_count。方向光、点光源和聚光灯在处于活动状态时会占用 lights[] 中的条目。
如果 Light 组件的数量超过 light.max_count,引擎会报告组件缓冲区已满错误。
着色器可以通过声明一个名为 LightBuffer、采用内置布局的 uniform 块来访问活动光源。引擎会检测这个块,并自动为使用它的材质和计算程序绑定光源数据。

#version 140
#define MAX_LIGHT_COUNT 32
struct Light
{
vec4 position; // xyz:世界位置,w:未使用
vec4 color; // rgb:颜色,a:未使用
vec4 direction_range; // xyz:规范化的世界方向,w:范围
vec4 params; // x:类型,y:强度,z:内锥角,w:外锥角
};
uniform LightBuffer
{
// xyz:累积的环境光颜色,w:活动的非环境光数量
vec4 light_info;
Light lights[MAX_LIGHT_COUNT];
};
光源类型存储在 lights[i].params.x 中:
| 类型 | 值 |
|---|---|
| 方向光 | 0 |
| 点光源 | 1 |
| 聚光灯 | 2 |
着色器可以声明较小的 lights[] 数组(小于 light.max_count),但不能声明更大的数组。光源循环始终要受声明的数组大小限制:
vec3 apply_lights(vec3 normal)
{
vec3 result = light_info.xyz;
int active_light_count = int(light_info.w);
for (int i = 0; i < MAX_LIGHT_COUNT; ++i)
{
if (i >= active_light_count)
{
break;
}
int type = int(lights[i].params.x);
vec3 light_color = lights[i].color.rgb * lights[i].params.y;
if (type == 0) // 方向光
{
vec3 light_dir = normalize(-lights[i].direction_range.xyz);
result += light_color * max(dot(normal, light_dir), 0.0);
}
else if (type == 1) // 点光源
{
result += light_color;
}
else if (type == 2) // 聚光灯
{
result += light_color;
}
}
return result;
}
上面的示例展示了缓冲区的访问模式。实际的点光源或聚光灯着色器还应计算从着色点到 lights[i].position.xyz 的向量,使用 lights[i].direction_range.w 应用距离衰减;对于聚光灯,还要使用 lights[i].params.z 和 lights[i].params.w 作为以弧度表示的锥角。
Defold 在 /builtins/materials/lighting.glsl 提供了一个着色器辅助文件。定义 MAX_LIGHT_COUNT,提供辅助文件所需的 varying 变量,然后在片段着色器中包含它:
#version 140
#define MAX_LIGHT_COUNT 32
in vec3 var_normal;
in vec4 var_position;
in mat4 var_view;
out vec4 color_out;
#include "/builtins/materials/lighting.glsl"
void main()
{
vec3 normal = normalize(var_normal);
vec3 ambient = ambient_light();
vec3 diffuse = diffuse_lambert(normal, var_position.xyz);
color_out = vec4(ambient + diffuse, 1.0);
}
该辅助文件定义了 LIGHT_DIRECTIONAL、LIGHT_POINT 和 LIGHT_SPOT 常量,提供 ambient_light(),并为缓冲区中的光源提供 Lambert 漫反射函数。