计算机图形学【着色技术】
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);
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)