
Gouraud Shading(高洛德着色)= “逐顶点算光照,逐像素做插值上色”。它不是一个新的光照模型(不改变 Phong/Blinn-Phong 的公式),这两种光照模型的不同就是在不同的阶段计算光照。
ambient + diffuse + specular,细节最丰富。C0,C1,C2...;光栅化时对三角形内部的像素颜色做线性插值,片元着色器直接输出插值后的颜色。Gouraud 的“贵”变“便宜”——把很多次的片元光照计算,变成少量的顶点光照计算。核心流程: 以一个三角形为例,顶点为 A,B,C:
PN(用 normal matrix)C_A(α, β, γ),满足 α+β+γ=1C_pixel = α*C_A + β*C_B + γ*C_CC_pixel优缺点:
项目 | Gouraud Shading(逐顶点光照) | Phong Shading(逐片元光照) |
|---|---|---|
光照计算位置 | 顶点着色器:每个顶点算一次光照颜色/强度 | 片元着色器:每个像素算一次光照 |
插值对象 | 插值“颜色/光照结果” | 插值“法线/相关向量”,再逐像素算光照 |
计算量/性能 | 低(顶点数通常远小于像素数) | 高(像素多时开销显著) |
高光表现(镜面反射) | 容易丢失或断续:高光若落在三角形内部且顶点未命中则插值不出高光 | 准确、连续:高光按像素计算,不易丢失 |
对网格密度依赖 | 强:三角形越大越容易出现误差;加密网格可改善 | 相对弱:即使网格不密,高光与明暗变化也更细腻 |
明暗过渡 | 平滑但“受限于顶点采样”;细节变化可能被抹平 | 平滑且细节丰富;能表现更细的光照变化 |
典型伪影 | “Specular Missing”(高光消失)、高光漂移、大片三角形上光照显得不真实 | 主要是性能成本;若法线质量差会暴露法线问题但不属于插值缺陷 |
适用场景 | 移动端/低端硬件、物体很多、以漫反射为主、网格较密的模型 | 高质量渲染、强高光材质(金属/塑料/车漆等)、网格较粗也要细节的情况 |
与光照模型关系 | 可搭配 Lambert/Phong/Blinn-Phong;只是“在哪算” | 同样可搭配 Lambert/Phong/Blinn-Phong;只是“在哪算” |
一句话总结 | 省算力,用插值“糊”出光照 | 更真实,用每像素计算保细节 |
实现:
vertex shader
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTex;
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
uniform vec3 uViewPos;
uniform vec3 uLightPos;
uniform vec3 uLightColor;
uniform vec3 uObjectColor;
uniform float uShininess;
out vec3 vColor;
void main()
{
vec4 worldPos4 = uModel * vec4(aPos, 1.0);
vec3 worldPos = worldPos4.xyz;
mat3 normalMat = mat3(transpose(inverse(uModel)));
vec3 N = normalize(normalMat * aNormal);
vec3 L = normalize(uLightPos - worldPos);
vec3 V = normalize(uViewPos - worldPos);
vec3 H = normalize(L + V);
float diff = max(dot(N, L), 0.0);
float spec = 0.0;
if (diff > 0.0) {
spec = pow(max(dot(N, H), 0.0), uShininess);
}
vec3 ambient = 0.1 * uLightColor;
vec3 diffuse = diff * uLightColor;
vec3 specular = 0.3 * spec * uLightColor;
vColor = (ambient + diffuse + specular) * uObjectColor;
gl_Position = uProjection * uView * worldPos4;
}fragment shader:
#version 330 core
in vec3 vColor;
out vec4 FragColor;
void main()
{
FragColor = vec4(vColor, 1.0);
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。