原理如下图
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);
}