之前的一篇教程HelloCG介绍了Cg的一些最基本的东西。这篇教程将介绍利用可编程渲染管线来实现光照。光照模型将采用广泛应用的phong模型,虽然这种模型在openGL的固定管线中已经实现了,但是学习该光照模型可以更加清楚的了解可编程渲染管线的流程。
首先要实现phong光照模型先要了解该模型中光照计算,关于phong模型光照计算的相关资料网上相当多,或者参考任何一本计算机图形学的相关书籍即可,这里只给出计算公式。
C = ambient + diffuse + specular
从公式中可以得出,物体顶点的最终颜色是由环境反射,漫反射和镜面反射三个成分来决定的。环境反射的计算公式为:
ambient = IaKa
其中,Ia是光的环境反射强度,Ka是物体材质的环境射系数。环境反射很简单,和光源、法线等等都没有关系,下面是只有环境反射的例子。
Fig1环境反射,Ia=(1.0, 1.0, 1.0),Ka=(0.15,0.15,0.0)
和环境反射相比,漫反射就稍微复杂一点,它和光源的位置和物体顶点的法线都有关系。漫反射的计算公式为:
diffuse = IdKd (NL)
其中Id是光的漫反射强度,Kd是物体材质漫反射系数,NL表示法线N和入射光线L的内积。下面是只有面反射的例子。
Fig2漫反射,Id=(1.0, 1.0, 1.0),Kd=(1.0, 1.0 , 0.0)
最后是镜面反射,和漫反射相比,镜面反射又复杂了一点。它不仅和光源位置,物体顶点法线有关系,而且还和我们观看的位置有关系。镜面反射的计算公式为:
specular = IsKs(VR)n
其中Is是光的镜面反射强度,Ks是物体材质的镜面反射系数,VR表示相机朝向向量V和反射光线R的内积,n表示该内积的n次幂。这里反射光线R可以通过公式
R = 2(LN)N-L
所以,镜面反射公式现在可以写成
specular = IsKs(NH)n
下面是只有镜面反射的例子。
Fig3镜面反射,Is=(1.0, 1.0, 1.0),Ks=(1.0, 1.0 , 1.0,), n=32
通过上面的过程,分别计算出了物体每个顶点的环境反射,面反射和镜面反射。最后简单将这三个成分相加即可得到顶点最终的颜色。
C = IaKa + IdKd (NL)+ IsKs(NH)n
图fig4显示了这个相加的过程。
Fig4 phong光照
下面是vertex shader的代码。由于是基于vertex的光照,所以不需要fragment shader。
uniform float3 LightPosition; //光源位置
uniform float3 eyePosition; //相机位置
uniform float3 I; //光强度
uniform float3 Ka; //环境光反射系数
uniform float3 Kd; //漫反射系数
uniform float3 Ks; //镜面反射系数
uniform float shininess; //n幂次
struct output
{
float4 position : POSITION;
float4 color : COLOR;
};
output vs_main( float4 position : POSITION,
float3 normal : NORMAL,
uniform float4x4 MV, // 在相机坐标系中计算,所以要用到ModelView变换矩阵
uniform float4x4 MVP // ModelViewProjection变换矩阵
)
{
output OUT;
OUT.position = mul(MVP, position);
float3 N = normalize(mul(MV, float4(normal,0.0)) ).xyz; //转换法线到相机坐标系
float3 P = mul(MV, position).xyz; //转换物体顶点到相机坐标系
float3 L = normalize(LightPosition - P);
float NdotL = max(dot(N,L),0); //判断法线和入射光线的角度是否大于90度
float3 ambient = Ka * I; //环境反射
float3 diffuse = Kd * I * NdotL; //漫反射
float3 V = normalize(eyePosition - P);
float3 H = normalize(L+V); //half vector
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;
}
转自:http://blog.csdn.net/zhulinpptor/archive/2010/09/27/5909725.aspx