You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改仅支持单光源的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 16:06:07