GLSL中如何定义漫反射参数数组以支持多光源循环计算
GLSL多光源数组化实现方案
把单光源重复变量改为数组+循环遍历的实现方式,可以大幅降低多光源逻辑的冗余度,后续增减光源只需要修改少量配置即可,不需要重复编写光照计算代码,改造过程还能顺便修复原代码中第二个光源高光计算的笔误。
核心改造要点
- 定义统一的光源数量常量,避免硬编码数字散落在代码各处,后续调整光源数量只需要修改这一个值
- 将原本单独声明的漫反射颜色
kd、kd2改为和光源数量等长的vec4数组,数组索引对应每个光源的漫反射材质色 - 不需要提前为每个光源单独声明漫反射强度、反射向量、高光强度变量,在循环体内逐光源计算临时值即可,GLSL编译器会自动做寄存器优化,不会产生额外性能开销
- 修复原代码笔误:原代码中
spec2 = pow(spec , 14.0);错误复用了第一个光源的spec值,会导致第二个光源高光计算错误,改造后每个光源的高光会独立计算
改造后完整代码
#version 450 #extension GL_ARB_separate_shader_objects : enable layout(location = 0) in vec3 vertNormal; layout(location = 1) in vec3 eyeDir; layout(location = 2) in vec3 lightDir[2]; layout(location = 0) out vec4 fragColor; // 光源总数量,后续增减光源直接修改该值即可 const int LIGHT_COUNT = 2; // 漫反射颜色数组,索引对应每个光源的漫反射色 const vec4 kd[LIGHT_COUNT] = vec4[]( vec4(0.4, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 0.4, 0.0) ); // 全局统一高光系数 const vec4 ks = vec4(0.3, 0.3, 0.3, 0.0); // 环境光系数 const vec4 ka = 0.1 * kd[0]; // 高光硬度指数 const float SHININESS = 14.0; void main() { vec4 finalColor = ka; // 遍历所有光源累加光照贡献 for (int i = 0; i < LIGHT_COUNT; i++) { // 计算当前光源漫反射分量 float diff = max(dot(lightDir[i], vertNormal), 0.0); // 计算当前光源高光分量 vec3 reflection = reflect(-lightDir[i], vertNormal); float spec = max(dot(eyeDir, reflection), 0.0); spec = pow(spec, SHININESS); // 累加当前光源的光照贡献 finalColor += kd[i] * diff + ks * spec; } fragColor = finalColor; }
额外注意事项
- GLSL中const类型数组的初始化需要使用构造函数语法,即
类型[数组长度](元素1, 元素2...)的格式,和C语言直接用大括号包裹初始化的写法有区别 - 现有输入的
lightDir本身已经是数组格式,不需要修改接口,只要保证调整光源数量时,顶点着色器端输出的lightDir数组长度和LIGHT_COUNT常量匹配即可。GLSL中数组类型的输入输出location是连续分配的,当前长度为2的lightDir占用location 2、3,新增第三个光源时只需要把数组长度改为3,对应顶点端输出第三个光源方向到location 4即可 - 高光系数、高光指数、环境光这类全局生效的参数不需要做成数组,保持单个变量即可
内容的提问来源于stack exchange,提问作者SirchatZ
相关产品推荐
相关产品推荐

