如何修改仅支持单光源的Shader 实现至少2个独立光源的渲染效果
多光源渲染着色器修改方案
核心思路
- 定义光源结构体统一存储单光源所有参数
- 用数组存储多个光源的参数
- 循环计算每个光源的漫反射、高光贡献,累加后和全局环境光合并得到最终颜色
顶点着色器修改
原有顶点着色器存在坐标空间错误,修正后代码如下:
layout(location = 0) in vec4 vPosition; layout(location = 1) in vec4 vNormal; layout(location = 2) in vec2 vTexCoord; layout(location = 3) in vec4 vTangent; layout(location = 4) in vec4 vColor; uniform mat4 projectionViewMatrix; uniform mat4 modelMatrix; // 可选:存在非等比缩放时需传入模型矩阵的逆转置矩阵修正法线 // uniform mat4 normalMatrix; out vec4 fPosition; out vec4 fNormal; out vec4 fColor; void main() { // 修正为世界空间坐标,供片元着色器计算视线、光照使用 fPosition = modelMatrix * vPosition; // 非等比缩放时替换为fNormal = normalMatrix * vNormal fNormal = modelMatrix * vNormal; fColor = vColor; gl_Position = projectionViewMatrix * modelMatrix * vPosition; }
片元着色器修改
调整为多光源架构的代码如下,默认支持2个独立平行光,可按需扩展数组大小:
#version 410 in vec4 fPosition; in vec4 fNormal; in vec4 fColor; // 材质参数 uniform vec3 kAmbient; uniform vec3 kDiffuse; uniform vec3 kSpecular; uniform float kSpecularPower; // 全局环境光参数 uniform vec3 globalAmbient; // 摄像机位置 uniform vec3 cameraPosition; // 光源结构体,可按需扩展点光源、聚光灯相关参数 struct Light { vec3 direction; vec3 diffuse; vec3 specular; }; // 声明2个光源的数组 uniform Light lights[2]; out vec4 pColor; void main() { vec3 kNormal = normalize(fNormal.xyz); vec3 surfaceToView = normalize(cameraPosition - fPosition.xyz); vec3 finalColor = vec3(0.0); // 全局环境光仅计算一次 finalColor += (fColor.xyz + kAmbient) * globalAmbient; // 循环累加每个光源的光照贡献 for(int i = 0; i < 2; i++) { vec3 lightDirNorm = normalize(lights[i].direction); // 计算当前光源漫反射 float lambertTerm = max(0.0, dot(kNormal, -lightDirNorm)); vec3 diffuse = (fColor.xyz + kDiffuse) * lights[i].diffuse * lambertTerm; // 计算当前光源高光 vec3 reflectDir = reflect(lightDirNorm, kNormal); float specularTerm = pow(max(0.0, dot(surfaceToView, reflectDir)), kSpecularPower); vec3 specular = (fColor.xyz + kSpecular) * lights[i].specular * specularTerm; finalColor += diffuse + specular; } pColor = vec4(finalColor, 1.0); }
注意事项
- 应用端传值时需严格匹配uniform命名规则,格式为
lights[索引].参数名,例如lights[0].direction、lights[1].diffuse,命名不匹配会导致着色器加载失败、渲染结果为纯色 - 若需支持点光源/聚光灯,仅需修改Light结构体添加位置、衰减系数、切角等参数,在循环中补充对应的衰减、角度判断逻辑即可
- 模型存在非等比缩放时,必须在应用端计算模型矩阵的逆转置矩阵作为normalMatrix传入着色器,避免法线变换出现误差
内容的提问来源于stack exchange,提问作者Cai Chi
相关产品推荐
相关产品推荐

