笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。
CSDN课程视频网址:http://edu.csdn.net/lecturer/144
Phong 着色法是结合了多边形物体表面反射光的亮度,并以特定位置的表面法线作为像素参考值,以插值方式来估计其周围位置像素的色值。与Gouraud着色法比较,Phong着色法的效果比前者更逼真。实现方式跟上面的一样,新建一个文本文件,将后缀名改成.fx。Shader完整代码如下所示:
float4x4 matWorldViewPrj; float4x4 matWorld; float3 lightPos = float3(0, 60, -60); float lightAttenuation = 0.01; float3 eyePos = float3(0, 200, 400); float4 mtlDiffuseColor = float4(1, 0, 0, 1); struct VS_INPUT { float3 pos : POSITION; float3 normal : NORMAL; }; struct VS_OUTPUT { float4 pos : POSITION; float3 worldPos : TEXCOORD0; float3 normal : TEXCOORD1; }; VS_OUTPUT my_vs(VS_INPUT vert) { VS_OUTPUT vsout; vsout.pos = mul(float4(vert.pos, 1), matWorldViewPrj); vsout.worldPos = mul(float4(vert.pos, 1), matWorld); vsout.normal = normalize(mul(vert.normal, matWorld)); return vsout; } float4 my_ps(float3 worldPos : TEXCOORD0, float3 normal : TEXCOORD1) : COLOR { float4 color; //ambient color = mtlDiffuseColor * 0.2f; normal = normalize(normal); float3 L = lightPos - worldPos; float d = length(L); L /= d; float atten = 1 / (lightAttenuation * d); float diff = saturate(dot(normal, L)); color +=mtlDiffuseColor * diff * atten; float3 V = normalize(worldPos - eyePos); float3 R = reflect(L, normal); float specular = pow(saturate(dot(R, V)), 8) * atten * diff; color += float4(specular, specular, specular, 0); return color; } technique my_tech { pass p0 { VertexShader = compile vs_1_1 my_vs(); PixelShader = compile ps_2_0 my_ps(); } }
对于着色器来说,只需要修改部分代码就可以了,在环境映射的基础上增加计算反射以及计算高光specular,当然Phong不需要环境映射中关于材质的处理。代码如下所示:
float3 R = reflect(L, normal); float specular = pow(saturate(dot(R, V)), 8) * atten * diff; color += float4(specular, specular, specular, 0);
C++执行代码与上面的类似,在这里就不重复了。运行渲染效果图如下:
Phong着色模型是将物体表面的光反射看成是环境光的反射之和与光源直接有关的漫反射及镜面反射的组合。这句话理解起来比较拗口,从数学上讲就是将反射的总能量看做是光环境的强度,点光源的强度乘以三个不同的系数后相加的和。这三个系数分别表示:物体表面反射环境光、产生漫反射和产生镜面反射的能力。在代码的实现过程中都离不开数学公司的运算,在这里再啰嗦一下,数学知识对于程序开发来说非常重要,它决定了你将能达到的高度。
时间: 2024-10-06 07:50:17