今天学习的是镜面的反射光照,其实一般在场景中基本环境光和漫反射光照已经可以表现出一个不错的照明了,今天的镜面反射光照其实仅仅适合于需要在表面添加抛光或者闪耀的物体上,例如金属、玻璃等等,同时也是基于之前的环境光和漫反射光的基础之上的,先来看看镜面反射光照的公式吧。
镜面反射光照公式:I=AiAc+Di*Dc*N.L+Si*Sc*(R.V)^n
公式说明:其中,AiAc+Di*Dc*N.L是前一节的公式,即环境光+漫反射光,Si和Sc分别为镜面反射光照的强度和颜色,R=2*(N.L)*N-L表示反射向量。
V:为从相机的位置指向观察目标的向量,即V=cameraPosition-mul(position,world)也就是高光的部分始终面向相机可以被看到。
相机的位置:通常在Game中定义视角矩阵ViewMatrix的第一个参数,即:ViewMatrix=Matrix.CreateLookAt(CameraPosition,CameraTarget,VectorUp)中的CameraPosition
观察目标:即为POSITION0中存储的物体位置,当然这是模型空间的坐标,需要利用World转换为世界空间中的坐标。
n:表示光泽属性,n越大,表明物体表面越光滑,反光越强。
参照公式修改上一节中的部分代码即可完成效果,当然最好是新建一个项目,自己从头到尾按部就班的写代码,温故而知新......下面贴出变动的代码:
#region 镜面反射光照 effect.CurrentTechnique = effect.Techniques["SpecularLight"]; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { effect.Parameters["World"].SetValue(modelTransform[mesh.ParentBone.Index] * Matrix.CreateScale(30.0f) * Matrix.CreateRotationX(rotateAngle) * Matrix.CreateRotationY(rotateAngle)); effect.Parameters["View"].SetValue(viewMatrix); effect.Parameters["Projection"].SetValue(projectMatrix); //环境光参数 effect.Parameters["AmbientColor"].SetValue(new Vector4(0.1f, 0.2f, 0f, 0.2f)); effect.Parameters["AmbientIntensity"].SetValue(0.5f); //漫反射光参数 effect.Parameters["DiffuseIntensity"].SetValue(0.5f); effect.Parameters["DiffuseColor"].SetValue(new Vector4(1.0f, 0.0f, 0.5f, 0)); effect.Parameters["LightDirection"].SetValue(new Vector4(1, 0, 1.0f, 1.0f)); //镜面高光参数 effect.Parameters["VecEye"].SetValue(new Vector4(camPosition, 0)); effect.Parameters["SpecularIntensity"].SetValue(1f); effect.Parameters["SpecularColor"].SetValue(new Vector4(1.0f, 0.0f, 0.5f, 0.5f)); graphics.GraphicsDevice.SetVertexBuffer(part.VertexBuffer); graphics.GraphicsDevice.Indices = part.IndexBuffer; graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, part.VertexOffset, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount); } } } #endregion
接下来看看fx里面的代码:
float4x4 World; float4x4 View; float4x4 Projection;
//Ambient float4 AmbientColor; float AmbientIntensity;
//Diffuse
float4 DiffuseColor; float DiffuseIntensity; float4 LightDirection;
//Specular float4 VecEye; float SpecularIntensity; float4 SpecularColor; struct VertexShaderOutput { float4 Position : POSITION0; float3 Normal:TEXCOORD0; float4 VecEye:TEXCOORD1; float4 Light:TEXCOORD2; }; VertexShaderOutput VertexShaderFunction(float4 Position:POSITION0,float3 Normal:NORMAL) { VertexShaderOutput output; float4 worldPosition = mul(Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); output.Normal =normalize(mul(Normal,World)); output.VecEye = normalize(VecEye-mul(Position,World)); output.Light = normalize(LightDirection); return output; } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { float4 vAmbient = AmbientIntensity*AmbientColor;//环境光 float4 vDiffuse = DiffuseIntensity*DiffuseColor*saturate(dot(input.Normal,input.Light));//漫反射光 float4 vSpecular = SpecularIntensity*SpecularColor*pow(saturate(dot(normalize(2*saturate(dot(input.Normal,input.Light))*input.Normal-input.Light),input.VecEye)),5);//镜面高光 return vAmbient+vDiffuse+vSpecular; } technique SpecularLight { pass Pass0 { VertexShader = compile vs_2_0 VertexShaderFunction(); PixelShader = compile ps_2_0 PixelShaderFunction(); } }
fx中的代码为了更好的展示各个光照的公式效果,代码上没有简化,其次需要注意光照方向Light,相机指向物体的位置VecEye,以及物体表面的法线这几个向量一定要记得单位化,利用fx里面自带的normalize方法,最后看看效果图:
感觉效果挺好的,也领略到了HLSL的魅力,继续学习.......