Guard Shading

这是一种简单的着色技术,通常用于实时图形渲染中,以快速计算物体表面的明暗变化。它在顶点处计算光照,然后在三角形的顶点之间插值颜色。这种方法比Phong Shading计算量小,因为它不需要对每个像素计算法线。Gouraud Shading的主要缺点是在高光区域可能会出现不自然的插值效果。

Phong Shading(冯氏着色)

这是一种广泛使用的着色模型,Phong着色模型通过计算物体表面与光源、观察方向之间的关系来模拟光照效果,包括环境光、漫反射和镜面反射。它由像素的法线用顶点法线插值得出,像素的颜色:每个像素单独法线计算颜色。

其中,参数如下:

Phong-Blinn Shading(Phong-Blinn着色)

这是Phong着色模型的一个变种,Blinn-Phong模型是对Phong模型的改进,它使用半角向量(即光源方向和观察方向的中间向量)来计算镜面高光,使得高光效果更加自然。Phong-Blinn Shading的主要优点是计算效率更高,因为它避免了计算复杂的反射向量。

其中,H是半角,其他变量与Phong相同。

实践操作

1)结果展现

Guard(Gouraud) Shading:着色较暗,边缘模糊

Phong Shading:着色明亮,光点聚焦

Blinn-Phong Shading:着色明亮,光点更宽

2)结果对比

Guard(Gouraud) Shading

计算位置:在顶点处计算光照(包括漫反射和镜面反射),然后在顶点之间插值颜色。

优点:计算简单且效率高,因为每个顶点只计算一次光照。

视觉效果:由于颜色是在顶点处计算并插值的,因此在多边形表面的光照变化可能不够平滑,特别是在多边形较大或顶点较少的情况下。这可能导致光照在多边形边界处出现不自然的过渡。

高光表现:高光可能会在顶点处计算并插值到其他顶点,这可能导致高光在多边形表面的分布不均匀或不准确。

计算复杂度:由于只在顶点处计算光照,因此计算复杂度较低,适合性能要求较高的应用。

Phong Shading

计算位置:在每个片段(像素)处计算光照。Phong着色使用顶点处的法线进行插值,然后在每个片段处计算漫反射和镜面反射。

视觉效果:由于每个像素都独立计算光照,Phong着色可以产生更平滑和逼真的光照效果。它特别擅长表现镜面高光和其他光照细节。

高光表现:高光在每个像素处独立计算,因此可以更准确地模拟高光的位置和强度。

计算复杂度:需要在每个像素处计算光照,因此计算复杂度较高,但可以提供更高的视觉质量。

高光的锐利度:通常会产生更锐利和集中的高光,因为它的计算直接依赖于反射向量和观察方向的对齐程度。

观察角度的影响:高光的亮度和位置会随着观察角度的变化而显著变化,这使得它在模拟真实世界反射时可能更准确。

Blinn-Phong Shading

计算方法:使用半角向量(光源方向和观察方向的中间向量)和法线的点积来计算高光。

视觉效果:高光通常更柔和,因为半角向量的使用使得高光在更宽的范围内分布。

观察角度的影响:高光对观察角度的变化不那么敏感,这使得它在某些情况下可能看起来更稳定。

计算效率:这种方法在计算上更高效,同时保持了高光的自然效果

3)完整代码(使用 GLSL 编写)

指路【在线着色器交互式平台】:Shadertoy BETA

Shader code

Guard(Gouraud) Shading

vec3 ambientColor = vec3(0.05, 0.15, 0.2);
vec3 diffuseColor = vec3(0.2, 0.6, 0.8);
vec3 specularColor = vec3(1.0, 1.0, 1.0);
vec3 lightDir = normalize(vec3(0.0, 4.0, 5.0));
vec3 spherePos = vec3(0.0, 0.5, 0.0);

float raytraceSphere(in vec3 ro, in vec3 rd, float tmin, float tmax, float r) {
    vec3 ce = ro - spherePos;
    float b = dot(rd, ce);
    float c = dot(ce, ce) - r * r;
    float t = b * b - c;
    if (t > tmin) {
        t = -b - sqrt(t);
        if (t < tmax)
            return t;
    }
    return -1.0;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
    vec2 p = (-iResolution.xy + 2.0 * fragCoord.xy) / iResolution.y;
    vec3 eye = vec3(0.0, 1.0, 2.0);
    vec2 rot = 6.2831 * (vec2(0.1 + iTime * 0.25, 0.0) + vec2(1.0, 0.0) * (iMouse.xy - iResolution.xy * 0.25) / iResolution.x);
    eye.yz = cos(rot.y) * eye.yz + sin(rot.y) * eye.zy * vec2(-1.0, 1.0);
    eye.xz = cos(rot.x) * eye.xz + sin(rot.x) * eye.zx * vec2(1.0, -1.0);

    vec3 ro = eye;
    vec3 ta = vec3(0.0, 0.5, 0.0);

    vec3 cw = normalize(ta - eye);
    vec3 cu = normalize(cross(vec3(0.0, 1.0, 0.0), cw));
    vec3 cv = normalize(cross(cw, cu));
    mat3 cam = mat3(cu, cv, cw);

    vec3 rd = cam * normalize(vec3(p.xy, 1.5));

    vec3 color = vec3(0.0);

    float tmin = 0.1;
    float tmax = 50.0;
    float t = raytraceSphere(ro, rd, tmin, tmax, 1.0);
    if (t > tmin && t < tmax) {
        vec3 pos = ro + rd * t;
        vec3 norm = normalize(pos - spherePos);

        // Calculate color at the intersection point
        float amb = clamp(0.5 + 0.5 * norm.y, 0.0, 1.0);
        float dif = clamp(dot(lightDir, norm), 0.0, 1.0);
        vec3 ref = reflect(-lightDir, norm);
        float spe = pow(clamp(dot(ref, -rd), 0.0, 1.0), 64.0);

        vec3 vertexColor = (amb * ambientColor +
                            dif * diffuseColor +
                            spe * specularColor) * 0.5;

        // Interpolate color (simple approximation)
        color = vertexColor;
    }

    vec3 gamma = vec3(1.0 / 2.2);
    fragColor = vec4(pow(color, gamma), 1.0);
}

Phong Shading

vec3 ambientColor = vec3(0.05, 0.15, 0.2);
vec3 diffuseColor = vec3(0.2, 0.6, 0.8);
vec3 specularColor = vec3(1.0, 1.0, 1.0);
vec3 lightDir = normalize(vec3(0.0, 4.0, 5.0));
vec3 spherePos = vec3(0.0, 0.5, 0.0);

float raytraceSphere(in vec3 ro, in vec3 rd, float tmin, float tmax, float r) {
    vec3 ce = ro - spherePos;
    float b = dot(rd, ce);
    float c = dot(ce, ce) - r * r;
    float t = b * b - c;
    if (t > tmin) {
        t = -b - sqrt(t);
        if (t < tmax)
            return t;
    }
    return -1.0;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
    vec2 p = (-iResolution.xy + 2.0 * fragCoord.xy) / iResolution.y;
    vec3 eye = vec3(0.0, 1.0, 2.0);
    vec2 rot = 6.2831 * (vec2(0.1 + iTime * 0.25, 0.0) + vec2(1.0, 0.0) * (iMouse.xy - iResolution.xy * 0.25) / iResolution.x);
    eye.yz = cos(rot.y) * eye.yz + sin(rot.y) * eye.zy * vec2(-1.0, 1.0);
    eye.xz = cos(rot.x) * eye.xz + sin(rot.x) * eye.zx * vec2(1.0, -1.0);

    vec3 ro = eye;
    vec3 ta = vec3(0.0, 0.5, 0.0);

    vec3 cw = normalize(ta - eye);
    vec3 cu = normalize(cross(vec3(0.0, 1.0, 0.0), cw));
    vec3 cv = normalize(cross(cw, cu));
    mat3 cam = mat3(cu, cv, cw);

    vec3 rd = cam * normalize(vec3(p.xy, 1.5));

    vec3 color;

    float tmin = 0.1;
    float tmax = 50.0;
    float t = raytraceSphere(ro, rd, tmin, tmax, 1.0);
    if (t > tmin && t < tmax) {
        vec3 pos = ro + rd * t;
        vec3 norm = normalize(pos - spherePos);
        float occ = 0.5 + 0.5 * norm.y;

        float amb = clamp(0.5 + 0.5 * norm.y, 0.0, 1.0);
        float dif = clamp(dot(lightDir, norm), 0.0, 1.0);

        // Phong reflection
        vec3 ref = reflect(-lightDir, norm);
        float spe = pow(clamp(dot(ref, -rd), 0.0, 1.0), 64.0);

        color = amb * ambientColor * occ;
        color += dif * diffuseColor * occ;
        color += spe * specularColor * occ;
    }

    vec3 gamma = vec3(1.0 / 2.2);
    fragColor = vec4(pow(color, gamma), 1.0);
}

Blinn-Phong Shading

vec3 ambientColor = vec3(0.05, 0.15, 0.2);
vec3 diffuseColor = vec3(0.2, 0.6, 0.8);
vec3 specularColor = vec3(1.0, 1.0, 1.0);
vec3 lightDir = normalize(vec3(0.0, 4.0, 5.0));
vec3 spherePos = vec3(0.0, 0.5, 0.0);

float raytraceSphere(in vec3 ro, in vec3 rd, float tmin, float tmax, float r) {
    vec3 ce = ro - spherePos;
    float b = dot(rd, ce);
    float c = dot(ce, ce) - r * r;
    float t = b * b - c;
    if (t > tmin) {
        t = -b - sqrt(t);
        if (t < tmax)
            return t;
        }
    return -1.0;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
    vec2 p = (-iResolution.xy + 2.0 * fragCoord.xy) / iResolution.y;
    vec3 eye = vec3(0.0, 1.0, 2.0);
    vec2 rot = 6.2831 * (vec2(0.1 + iTime * 0.25, 0.0) + vec2(1.0, 0.0) * (iMouse.xy - iResolution.xy * 0.25) / iResolution.x);
    eye.yz = cos(rot.y) * eye.yz + sin(rot.y) * eye.zy * vec2(-1.0, 1.0);
    eye.xz = cos(rot.x) * eye.xz + sin(rot.x) * eye.zx * vec2(1.0, -1.0);

    vec3 ro = eye;
    vec3 ta = vec3(0.0, 0.5, 0.0);

    vec3 cw = normalize(ta - eye);
    vec3 cu = normalize(cross(vec3(0.0, 1.0, 0.0), cw));
    vec3 cv = normalize(cross(cw, cu));
    mat3 cam = mat3(cu, cv, cw);

    vec3 rd = cam * normalize(vec3(p.xy, 1.5));

    vec3 color;

    float tmin = 0.1;
    float tmax = 50.0;
    float t = raytraceSphere(ro, rd, tmin, tmax, 1.0);
    if (t > tmin && t < tmax) {
        vec3 pos = ro + rd * t;
        vec3 norm = normalize(pos - spherePos);
        float occ = 0.5 + 0.5 * norm.y;

        float amb = clamp(0.5 + 0.5 * norm.y, 0.0, 1.0);
        float dif = clamp(dot(lightDir, norm), 0.0, 1.0);

        vec3 h = normalize(-rd + lightDir);
        float spe = pow(clamp(dot(h, norm), 0.0, 1.0), 64.0);

        color = amb * ambientColor * occ;
        color += dif * diffuseColor * occ;
        color += dif * spe * specularColor * occ;
    }

    vec3 gamma = vec3(1.0 / 2.2);
    fragColor = vec4(pow(color, gamma), 1.0);
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐