原理如下图
float4x4 view_proj_matrix; float4 view_position; struct VS_OUTPUT { float4 Pos: POSITION; float2 TexCoord: TEXCOORD0; float3 Reflect: TEXCOORD1; }; VS_OUTPUT vs_main(float4 inPos: POSITION, float3 inNormal: NORMAL, float2 inTxr: TEXCOORD0) { VS_OUTPUT Out; // Compute the projected position and send out the texture coordinates Out.Pos = mul(view_proj_matrix, inPos); Out.TexCoord = inTxr; // Compute the reflection vector Out.Reflect = -reflect(view_position-inPos,inNormal); return Out; }
sampler Wood; sampler EnvMap; float4 ps_main(float2 inTxr: TEXCOORD0,float3 inReflect: TEXCOORD1) : COLOR { // Output texture color with reflection map return 0.2*tex2D(Wood,inTxr)+0.8*texCUBE(EnvMap,inReflect); }
折射是光线穿过折射率不同的两种介质所产生的现象,其中入射角和出射角遵循斯涅尔定律(snell’s low)
float4x4 view_proj_matrix; float4 view_position; float refractingPower; struct VS_OUTPUT { float4 Pos: POSITION; float2 TexCoord: TEXCOORD0; float3 Refract: TEXCOORD1; }; VS_OUTPUT vs_main(float4 inPos: POSITION, float3 inNormal: NORMAL, float2 inTxr: TEXCOORD0) { VS_OUTPUT Out; // Compute the projected position and send out the texture coordinates //mvp矩阵变换 Out.Pos = mul(view_proj_matrix, inPos); Out.TexCoord = inTxr; float3 viewVec = normalize(view_position - inPos); //根据斯涅尔法则计算反射角 // n_i * sin(theta_i) = n_r * sin(theta_r) // sin(theta_i) //首先用向量点乘计算出cos,然后用勾股定理计算sin值 float cosine = dot(viewVec, inNormal); float sine = sqrt(1 - cosine * cosine); // sin(theta_r) //根据斯涅尔法则计算出射角的sin,saturate到0,1,所以当入射角足够大的时候,然后用勾股定理计算cos值 float sine2 = saturate(refractingPower * sine); float cosine2 = sqrt(1 - sine2 * sine2); //首先构建一对正交基x,y 然后变换到标准的坐标轴上,cross是向量叉乘,a × b为一个新生成的向量,这个向量垂直于a 和 b展成的平面 float3 x = -inNormal; float3 y = normalize(cross(cross(viewVec, inNormal), inNormal)); Out.Refract = x * cosine2 + y * sine2; return Out; }
折射率是1.66时候的结果
光线和物质表面相交的时候,一部分光线发生了反射,一部分发生了折射。根据斯涅尔定律,当入射角大到一定程度的时候,折射现象就不会发生了,这个角就是临界角,任何超过这个角的入射光线都会被完全反射,称为全反射(total internal reflection)现象,示意图如下
float4x4 view_proj_matrix; float4 view_position; struct VS_OUTPUT { float4 Pos: POSITION; float2 TexCoord: TEXCOORD0; float3 Refract: TEXCOORD1; float3 Reflect: TEXCOORD2; float2 Factors: TEXCOORD3; }; VS_OUTPUT vs_main(float4 inPos: POSITION, float3 inNormal: NORMAL, float2 inTxr: TEXCOORD0) { VS_OUTPUT Out; // Compute the projected position and send out the texture coordinates Out.Pos = mul(view_proj_matrix, inPos); Out.TexCoord = inTxr; float3 viewVec = normalize(view_position - inPos); // Compute reflection Out.Reflect = reflect(-viewVec,inNormal); // Compute the reflection vector using Snell's law // the refract HLSL function does not always work properly // n_i * sin(theta_i) = n_r * sin(theta_r) // sin(theta_i) float cosine = dot(viewVec, inNormal); float sine = sqrt(1 - cosine * cosine); // sin(theta_r) float sine2 = saturate(1.14 * sine); float cosine2 = sqrt(1 - sine2 * sine2); // Determine the refraction vector be using the normal and tangent // vectors as basis to determine the refraction direction float3 x = -inNormal; float3 y = normalize(cross(cross(viewVec, inNormal), inNormal)); Out.Refract = x * cosine2 + y * sine2; // Determine proper reflection and refraction factors through // a Fresnel approximation. (x = reflect, y = refract) Out.Factors.x = sine; Out.Factors.y = (1 - sine2); return Out; }
sampler Wood; sampler EnvMap; float4 ps_main(float2 inTxr: TEXCOORD0,float3 inRefract: TEXCOORD1, float3 inReflect: TEXCOORD2,float2 inFct: TEXCOORD3) : COLOR { // Output texture color with reflection map return inFct.x * texCUBE(EnvMap,inReflect) + (inFct.y * texCUBE(EnvMap,inRefract) + 0.4) * tex2D(Wood,inTxr); }