看看本节的教程,本节介绍有关裁剪面的使用,先看看本节教程的结架吧,跟DiffuseLight那节教程的结架差不多
第一,ClipPlane的简介和公式。
裁剪面既然说了“面”,本节的教程涉及的面为平面,而非曲面,3D空间一个平面可以将空间分为两半,熟知的有X平面,Y平面,Z平面等等。
3D空间平面的方程式为 ax+by+cz+d=0;
(a,b,c)为平面的法向量,d为一个参数,具体推导参照3D平面的通用公式
随便提一下,XNAMATH库的平面用XMVECTOR(a,b,c,d)来表示。
假设一个点为(x1,y1,z1)
(1)当a*x1+b*y1+c*z1+d=0时 代表这个点在这个平面上。
(2)当a*x1+b*y1+c*z1+d<0时,代表这个点在这个平面的后面(面法向量的反向)。
(3)当a*x1+b*y1+c*z1+d>0时,代表这个点在这个平面的前面(面法向量的正向)。
那么平面的前面和后面怎么区别呢?这得根据法向量的方向,在法向量方向那一边的为前面,反之为后面,看下面图就知道了:
假设裁剪面为(ClipP
lane)为
ax+by+cz+d=0;,用float4表示为(a,b,c,d),
将3D几何体上位于
a*x1+b*y1+c*z1+d<0 空间的点剔除
Texture2D ShaderTexture:register(t0); //纹理资源
SamplerState SampleType:register(s0); //采样方式
//VertexShader
cbuffer CBMatrix:register(b0)
{
matrix World;
matrix View;
matrix Proj;
matrix WorldInvTranspose;
};
cbuffer CBLight:register(b1)
{
float4 DiffuseColor;
float3 LightDirection;
float pad;
};
cbuffer CBClipPlane:register(b2)
{
float4 ClipPlane;
};
struct VertexIn
{
float3 Pos:POSITION;
float2 Tex:TEXCOORD0; //多重纹理可以用其它数字
float3 Normal:NORMAL;
};
struct VertexOut
{
float4 Pos:SV_POSITION;
float ClipValue : SV_ClipDistance0;//裁剪值关键字
float2 Tex:TEXCOORD0;
float3 W_Normal:NORMAL; //世界空间的法线
};
VertexOut VS(VertexIn ina)
{
VertexOut outa;
//将顶点变换到齐次裁剪空间
outa.Pos = mul(float4(ina.Pos,1.0f), World);
outa.Pos = mul(outa.Pos, View);
outa.Pos = mul(outa.Pos, Proj);
//将顶点法线量变换到世界空间
outa.W_Normal = mul(ina.Normal, (float3x3)WorldInvTranspose); //此事世界逆转置矩阵的第四行本来就没啥用
outa.W_Normal = normalize(outa.W_Normal);
outa.Tex= ina.Tex;
//在世界空间,对于乘以裁剪面小于零的进行裁剪,裁剪不满足条件的几何体部分
outa.ClipValue = dot(mul(float4(ina.Pos, 1.0f), World), ClipPlane);
return outa;
}
float4 PS(VertexOut outa) : SV_Target
{
float4 TexColor; //采集的纹理颜色
float LightFactor; //灯光因子
float4 color = {0.0f,0.0f,0.0f,0.0f}; //最终输出的颜色
//第一,获取采样颜色
TexColor = ShaderTexture.Sample(SampleType, outa.Tex);
//第二,求出灯光因子
float3 InvLightDir = -LightDirection;
LightFactor = saturate(dot(InvLightDir,outa.W_Normal));
//第三,求出灯光照射颜色
if (LightFactor>0)
{
color += LightFactor*DiffuseColor; //saturate(float1*float4)
}
color = saturate(color);
//第四,用灯光颜色调节纹理颜色
color = color*TexColor;
return color;
}
//在世界空间,对于乘以裁剪面小于零的进行裁剪,裁剪不满足条件的几何体部分
outa.ClipValue = dot(mul(float4(ina.Pos, 1.0f), World), ClipPlane);
outa.ClipValue = dot(mul(float4(ina.Pos, 1.0f), World), ClipPlane);
注意关键字:
float ClipValue : SV_ClipDistance0;其中“ SV_ClipDistance0”代表裁剪值,在VertexShader进行计算得到的值小于0的被裁剪,跟PixelShader的函数Clip(Clip用于在PixelShader裁剪像素)有相似的功能。
我设定的裁剪面为:(0.0f,-1.0f,0.0f,0.0f),即在Y面以上的空间元素被裁剪。
最后我设定光栅化状态为不进行背面剔除,并且将相机位置往上平移
rasterDesc.CullMode = D3D11_CULL_NONE; //背面剔除
程序运行结果如下:
最后我的源代码链接如下: