6-9.添加HLSL镜面高光
6-9.添加HLSL鏡面高光
問題
你想要用你的自定義HLSL效果添加鏡面高光到你的3D場景。鏡面高光是光源反射產(chǎn)生的高亮區(qū)域,如6-11.
方案
??????? 下面的討論將幫助你決定那個像素將有鏡面光部分。
??? 6-11左邊顯示一個光的傳播,L是一條從光源命中三角形像素的向量。同樣,眼的向量是從相機(jī)朝像素方向。如果L的反射線幾乎和E一樣,像素應(yīng)該有鏡面光部分。
你可以用鏡像方法通過該像素的法線來找到L的反射線。如果它們間的夾角很小這個鏡像了的方向幾乎和眼的方向一樣。你可以通過求它們的點(diǎn)積來檢查這兩個向量間的夾角。
??? 如果夾角是0,意味著兩個方向一樣且你應(yīng)該添加鏡面部分到光照,點(diǎn)積就是1。如果兩個方向不同,點(diǎn)積會比1小。
注意 兩個向量A和B間的點(diǎn)積只不過是(A長度)×(B長度)×(cos(它們間的夾角))。如果A和B都單位化,點(diǎn)積就只是(cos(它們間的夾角))。如果AB間夾角是0,點(diǎn)積就是1.如果兩個向量互相垂直,夾角是90度,點(diǎn)積就是0。就像6-11右上方顯示的。如果兩個向量相反,夾角180度,點(diǎn)積是-1.
當(dāng)所有光向量和眼向量的夾角少于90度時這個點(diǎn)積將被轉(zhuǎn)成正的,如6-11的右上。你不能馬上把這個值用作鏡面高光,因?yàn)檫@將添加一個鏡面光部分到所有不超過眼向量90度的反射向量。你想要縮小反射向量在10度或以下。
你可以通過給點(diǎn)積的結(jié)果一個高次方來得出。求這個點(diǎn)積的12次方,例如,將只為偏移10度之內(nèi)的向量產(chǎn)生一個大于0的值,如6-11右下部顯示。
這將使每個像素結(jié)果在單精度值,表明在該像素的鏡面部分的強(qiáng)度。
運(yùn)作
一直以來,你將想要能夠設(shè)置世界,視圖和投影矩陣來變換你的3D位置到2D屏幕坐標(biāo)。因?yàn)檫@節(jié)是為點(diǎn)光源而寫,你需要能夠修改它的位置。要計(jì)算眼向量,你需要知道相機(jī)的位置。你應(yīng)該能設(shè)置鏡面次方數(shù)來控制鏡面高光的大小。因?yàn)楣庹盏目偭靠赡艽笥?span lang="en-us">1,你應(yīng)該能夠縮小光強(qiáng)度來避免過度飽和。
注意 在許多情況,你將想要縮小光源的強(qiáng)度。要擁有多個光時要這么做,否則引起大多數(shù)像素融進(jìn)光里,浪費(fèi)了照明效果。
float4x4 xWorld;
float4x4 xView;
float4x4 xProjection;
float3 xLightPosition;
float3 xCameraPos;
float xAmbient;
float xSpecularPower;
float xLightStrength;
?
struct SLVertexToPixel
{
???? float4 Position????????? : POSITION;
???? float3 Normal?????????? : TEXCOORD0;
???? float3 LightDirection : TEXCOORD1;
???? float3 EyeDirection?????? : TEXCOORD2;
};
struct SLPixelToFrame
{
???? float4 Color ??????????? : COLOR0;
};
這個頂點(diǎn)著色器也將計(jì)算EyeDirection并使它對所有像素用插值替換。像素著色器仍然只需要輸出每個像素的顏色。
頂點(diǎn)著色器
頂點(diǎn)著色器和上一節(jié)沒啥區(qū)別。唯一新增的是計(jì)算了眼向量。通過從目標(biāo)減去原點(diǎn)得出從一個點(diǎn)到另一個點(diǎn)的向量。
SLVertexToPixel SLVertexShader(float4 inPos: POSITION0, float3 inNormal: NORMAL0)
{
??? SLVertexToPixel Output = (SLVertexToPixel)0;
??? float4x4 preViewProjection = mul(xView, xProjection);
??? float4x4 preWorldViewProjection = mul(xWorld, preViewProjection);
??? Output.Position = mul(inPos, preWorldViewProjection);?
??? float3 final3DPos = mul(inPos, xWorld);
??? Output.LightDirection = final3DPos - xLightPosition;
??? Output.EyeDirection = final3DPos - xCameraPos;
??? float3x3 rotMatrix = (float3x3)xWorld;
??? float3 rotNormal = mul(inNormal, rotMatrix);
??? Output.Normal = rotNormal;
??? return Output;
}
像素著色器
像素著色器更有趣。基色固定是藍(lán)色,因此你不必浪費(fèi)心思在這。一個很好的做法是,你單位化每個你在像素著色器接收到的方向,因?yàn)樗拈L度可能不是1.
和以前一樣,你計(jì)算通用光照。把它和xLightStrength相乘來縮小它一點(diǎn)。
SLPixelToFrame SLPixelShader(SLVertexToPixel PSIn) : COLOR0
{
??? SLPixelToFrame Output = (SLPixelToFrame)0;
??? float4 baseColor = float4(0,0,1,1);?
??? float3 normal = normalize(PSIn.Normal);?
??? float3 lightDirection = normalize(PSIn.LightDirection);???
??? float shading = dot(normal, -lightDirection);
??? shading *= xLightStrength;
??? float3 reflection = -reflect(lightDirection, normal);
??? float3 eyeDirection = normalize(PSIn.EyeDirection);
??? float specular = dot(reflection, eyeDirection);
??? specular = pow(specular, xSpecularPower);?
??? specular *= xLightStrength;
??? Output.Color = baseColor*(shading+xAmbient)+specular;???????????
??? return Output;
}
接著,你用反射原理通過法線鏡像化光方向。因?yàn)楣夥较蛘障蛳袼?#xff0c;它的反射線將向著眼。這和眼向量相反,所以你反轉(zhuǎn)它。
鏡面值通過眼向量和反轉(zhuǎn)的反射光方向間的點(diǎn)積得出。使這個值有高的次方確保只為當(dāng)那些兩個向量差異小于10度左右的像素該值才顯著的大于0。再有,這個值是和xLightStrength值相乘。
最后,環(huán)境光,著色值,鏡面高光部分組合得出最終像素顏色。
注意 鏡面部分添加白色到最終色。如果你的光有不同顏色,你應(yīng)該用你的光的顏色乘以鏡面值。
轉(zhuǎn)載于:https://www.cnblogs.com/XNAconglele/archive/2009/09/26/1574319.html
總結(jié)
以上是生活随笔為你收集整理的6-9.添加HLSL镜面高光的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【HelloKitty团队项目】Alph
- 下一篇: 运行项目遇到:该网页无法正常运作,loc