*原创文章,转载请注明出处*
openGL CG 系列教程3-Pixel Lighting
在上一篇教程中介绍了phong model下的一般光照,并且用Cg着色语言实现了固定渲染管线中gouraud shading光照效果。由于是基于vertex的光照,虽然采用gouraud shading要比flat shading效果好的多,但是和phong shading的效果相差很大。这里大家要注意的是,phong model和phong shading的区别。上一篇教程所讲的光照模型叫phong model,而这篇教程要介绍的一种着色方法叫phong shading,必须要使用shader才能实现。下面的图中对比了采用flat shading,gouraud shading和phong shading技术渲染的一个圆环。
Flat shading |
Gouraud shading |
Phong shading |
有了上一篇教程的基础,用Cg来实现基于pixel lighing的phong shading光照就容易多了。绝大部分的Cg shader代码都是一样的,主要的改变就是这次不是在vertex shader里光照,而是在fragment shader里计算光照。所以整个vertex shader的代码很简单,将要渲染的物体的顶点位置,顶点法线传入fragment shader就是vertex shader的全部工作。整个vertex shader的代码如下。
03vs.cg
struct output { float4 position : POSITION; float3 objectPos : TEXCOORD0; float3 normal : TEXCOORD1; };
output vs_main( float4 position : POSITION, float3 normal : NORMAL, uniform float4x4 MV, uniform float4x4 MVP ) { output OUT; OUT.position = mul(MVP, position); OUT.objectPos = mul(MV, position).xyz; OUT.normal = mul(MV, float4(normal,0.0)).xyz;
return OUT; } |
上面的代码的输出结构体中有三个成员。Position是传入的物体的顶点,该顶点将用ModelViewProjection矩阵转换成剪裁坐标系中的坐标供光栅化使用。一旦将坐标转换后,我们就无法在fragment shader中使用物体的顶点坐标了。由于要在fragment shader中计算光照,所以我们要将物体的顶点位置,顶点法线都传入到fragment shader中。这里物体转换前的顶点和法线分别使用了语义TEXCOORD0和TEXCOORD1,代表将它们作为纹理坐标后传入fragment shader。这样GPU会把顶点和法线信息当做纹理坐标来处理,在贴图的时候,GPU会根据纹理自动插值计算每个像素对应的颜色,而现在GPU插值计算出来的就是每个像素对应的坐标和法线信息了。有了这些数据就可以进行phong shading的计算了。光照计算的公式和方法和上一个教程介绍的一模一样。下面是fragment shader的代码。
03fs.cg
uniform float3 LightPosition; uniform float3 eyePosition; uniform float3 I; uniform float3 Ka; uniform float3 Kd; uniform float3 Ks; uniform float shininess;
struct input{ float3 objectPos: TEXCOORD0; float3 normal : TEXCOORD1; };
struct output{ float4 color : COLOR; };
output fs_main( in input IN ) { output OUT;
float3 N = normalize(IN.normal); float3 P = IN.objectPos;
float3 L = normalize(LightPosition - P); float NdotL = max(dot(N,L),0);
float3 ambient = Ka * I; float3 diffuse = Kd * I * NdotL;
float3 V = normalize(eyePosition - P); float3 H = normalize(L+V); float NdotH = pow(max(dot(N,H), 0), shininess);
if(NdotL<=0) NdotH = 0.0; float3 specular = Ks*I*NdotH;
float3 color = ambient + diffuse + specular; OUT.color.xyz= color; OUT.color.w = 1.0;
return OUT; } |
*原创文章,转载请注明出处*