Directx11教程十六之ClipPlane(裁剪面)

看看本节的教程,本节介绍有关裁剪面的使用,先看看本节教程的结架吧,跟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);

注意关键字:
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; //背面剔除

程序运行结果如下:




没裁剪面的时候程序运行如下:




最后我的源代码链接如下:


### 实现 DirectX 中逼真的水流动效果 为了实现在 DirectX 中逼真的水流动效果,需综合运用多种技术和方法来模拟水的真实感。这不仅涉及基本的图形学原理,还包括特定于 DirectX 的编程技巧。 #### 使用自定义着色器增强反射效果 通过编写 HLSL (High-Level Shading Language) 着色器程序,在 Direct3D 中可以精确控制像素级别的光照和颜色计算。对于水体表来说,重要的是实现环境映射(Environment Mapping),即让物体能够反映出周围场景的颜色变化[^1]。 ```hlsl // Water.fx 文件片段展示了一个简单的法线贴图与反射组合的例子 Texture2D<float4> normalMap : register(t0); SamplerState samLinearWrap : register(s0); float4 PS_Main(float4 Pos : SV_POSITION, float3 Normal : NORMAL, float2 Tex : TEXCOORD0) : COLOR { // 法线解码... // 反射向量计算... // 采样立方体贴图获取反射颜色... } ``` #### 动态纹理更新机制提升真实性 为了让水流看起来更自然流畅,应该引入动态纹理的概念——随着时间推移不断改变水上显示的图案。具体做法是在每一帧渲染之前修改用于绘制水区域的纹理坐标偏移值,从而达到视觉上的移动效果[^3]。 ```cpp void UpdateWaterWaveOffset(float deltaTime) { static float offsetU = 0.0f; static float offsetV = 0.0f; const float speedFactor = 0.5f * deltaTime; offsetU += sin(offsetV) * speedFactor; offsetV -= cos(offsetU) * speedFactor; XMMATRIX texTransform = XMMatrixTranslation(offsetU, offsetV, 0.0f); XMStoreFloat4x4(&mGridRenderItem->TexTransform, texTransform); } ``` #### 裁剪的应用增加细节层次 当观察角度较低时(比如从岸边看湖),远处的部分可能会因为透视原因显得不那么清晰;此时可以通过设置裁剪(Clip Plane)的方式隐藏掉不必要的部分,既提高了性能又增强了画的表现力[^4]。 ```cpp ID3D11DeviceContext* deviceContext = ... ; // 获取当前设备上下文指针 // 设置裁剪距离语义变量 deviceContext->PSSetShaderResources(0, 1, &pClipDistSRV); deviceContext->OMSetDepthStencilState(pClipPlaneDS, 1u); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值