Directx11教程二十六之Blur(高斯模糊)

本文详细介绍了一种通过渲染到纹理技术和2D渲染技术实现模糊效果的方法。该方法包括六个步骤:渲染3D场景到纹理、降低纹理分辨率、水平模糊处理、垂直模糊处理、提升模糊纹理分辨率及最终渲染到屏幕。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这节教程主要是关于“Blur”模糊处理的,先看看结构吧:





一,(Blur)模糊的介绍。

什么是模糊,从宏观上来说模糊的定义大家都知道,也就是看不清;从微观的角度而言,假设一张纹理上,每个像素叠加其旁边像素的一定的值,就是模糊。

具体说下实现模糊算法,核心的算法分为两步:(1)水平模糊处理  (2)垂直模糊处理

(1)水平模糊处理 
看中间蓝色那个像素点,将蓝色标记的像素左右两边,也就是将水平红色线经过的那些像素(按权重比weight)的颜色值叠加于蓝色标记的像素的颜色值里。

(2)垂直模糊处理
看中间蓝色那个像素点,将蓝色标记的像素上下两边,也就是将垂直红色线经过的那些像素(按权重比weight)的颜色值叠加于蓝色标记的像素的颜色值里。

这节呢,还需要用到RenderToTexture(RTT,渲染到纹理技术)和2D Rendering技术才行




算法具体步骤和算法:
//第一,利用RTT技术渲染3D场景到一张分辨率为(ScreenWidth*ScreenHeight)纹理中
//第二,降低采样“渲染到纹理”为一个更小分辨率(ScreenWidth/2*ScreenHeight/2)的纹理(正常窗口的四分之一)
//第三,对已经降低分辨率的纹理进行水平的模糊处理,对低分率进行模糊处理省很多性能,这里比对原窗口大小的纹理进行模糊处理节省3/4的性能
//第四,对水平模糊纹理进行垂直的模糊处理,对低分率进行模糊处理省很多性能,这里比对原窗口大小的纹理进行模糊处理节省3/4的性能
//第五,提升模糊的纹理分辨率变回到窗口大小(ScreenWidth*ScreenHeight)
//第六,利用“2D Rendering”渲染最终的模糊的纹理到背后缓存中(刚好覆盖屏幕)

总的渲染代码如下:

Render函数(封装了模糊算法处理的几个步骤)
bool GraphicsClass::Render(float rotation) 
{
	bool result;

	//第一,利用RTT技术渲染3D场景到一张分辨率为(ScreenWidth*ScreenHeight)纹理中
	result = RenderSceneTo2DTexture(rotation);
	if (!result)
	{
		MessageBox(NULL, L" RenderSceneToTexture failure", NULL, MB_OK);
		return false;
	}


	//第二,降低采样“渲染到纹理”为一个更小分辨率(ScreenWidth/2*ScreenHeight/2)的纹理(正常窗口的四分之一吧)
	result = DownSampleTexture();
	if (!result)
	{
		MessageBox(NULL, L" DownSampleTexture failure", NULL, MB_OK);
		return false;
	}
	//第三,对已经降低分辨率的纹理进行水平的模糊处理,对低分率进行模糊处理省很多性能,这里比对原窗口大小的纹理进行模糊处理节省3/4的性能
	result = RenderHorizontalBlurToTexture();
	if (!result)
	{
		MessageBox(NULL, L" RenderHorizontalBlurToTexture failure", NULL, MB_OK);
		return false;
	}

	//第四,对水平模糊纹理进行垂直的模糊处理,对低分率进行模糊处理省很多性能,这里比对原窗口大小的纹理进行模糊处理节省3/4的性能
	result = RenderVerticalBlurToTexture();
	if (!result)
	{
		MessageBox(NULL, L" RenderVerticalBlurToTexture failure", NULL, MB_OK);
		return false;
	}

	//第五,提升模糊的纹理分辨率变回到窗口大小(ScreenWidth*ScreenHeight)
	result = UpRenderSampleTexture();
	if (!result)
	{
		MessageBox(NULL, L"UpRenderSampleTexture failure", NULL, MB_OK);
		return false;
	}

	//第六,利用“2D Rendering”渲染最终的模糊的纹理到背后缓存中(刚好覆盖屏幕)
	result = Render2DTextureToScene();
	if (!result)
	{
		MessageBox(NULL, L"Render2DTextureToScene failure", NULL, MB_OK);
		return false;
	}
	return true;

}

第一步,RenderSceneTo2DTexture函数, 将整个3D场景渲染到一个与屏幕一样大的纹理图上

bool GraphicsClass::RenderSceneTo2DTexture(float rotation)
{
	bool result;
	XMMATRIX WorldMatrix, ViewMatrix, ProjectionMatrix;

	//第一,设置将渲染目标(从背后缓存)变为与屏幕大小一样大的纹理图,并变换视口
	mRenderModelToTextureClass->SetRenderTarget(mD3D->GetDeviceContext());

	//第二,清除目的纹理的颜色为黑色
	mRenderModelToTextureClass->ClearRenderTarget(mD3D->GetDeviceContext(), 0.0f, 0.0f, 0.0f, 1.0f);

	//第三,生成相机矩阵
	mCamera->Render();

	//第四,获取各大矩阵
	WorldMatrix = mD3D->GetWorldMatrix();
	ViewMatrix = mCamera->GetViewMatrix();
	ProjectionMatrix = mD3D->GetProjMatrix();

	//第五,旋转世界矩阵
	WorldMatrix = WorldMatrix*XMMatrixRotationY(rotation);

	//第六,把3D模型顶点数据和索引数据放入3D渲染流水线
	mModelClass->Render(mD3D->GetDeviceContext());

	//第七,用ColorShader进行渲染
	result = mColorShaderClass->Render(mD3D->GetDeviceContext(), mModelClass->GetIndexCount(), WorldMatrix, ViewMatrix, ProjectionMatrix, mModelClass->GetTextureArray(), mLightClass->GetDiffuseColor(), mLightClass->GetLightDirection(), mLightClass->GetAmbientColor(), mLightClass->GetSpecularColor(), mLightClass->GetSpecularPow(), mCamera->GetPostion());
	if (!result)
	{
		MessageBox(NULL, L"ColorShaderClass Render failure", NULL, MB_OK);
		return false;
	}

	//第八,重置渲染目的地为背后缓存(BackBuffer)
	mD3D->SetBackBufferRender();

	//第九,重置视口为原点
	mD3D->SetViewPort();

	return true;
}


第二步,DownSampleTexture函数, 模糊算法第二步,用“2D Render”技术将刚才那张与屏幕一样大的纹理贴图降低其大小变为屏幕的四分之一(屏幕宽度二分之一,屏幕高度二分之一),这样可以在进行模糊时处理更小分辨率的纹理,节省四分之三的性能

bool GraphicsClass::DownSampleTexture()
{
	bool result;
	XMMATRIX WorldMatrix, BaseViewMatrix, OrthoMatrix, viewMatrix;

	//(2D Render)用的为正交矩阵而非投影矩阵
	//注意,这次渲染目标依然不是背后缓存,而是原屏幕四份之一的纹理图
	//BaseViewMatrix专门用于“2D Render”的相机变换矩阵

	//第一,将渲染目标(从背后)变为屏幕四分之一大的纹理图上,并变换视口
	mDownSampleTexture->SetRenderTarget(mD3D->GetDeviceContext());

	//第二,清除目的纹理的颜色黑色
	mDownSampleTexture->ClearRenderTarget(mD3D->GetDeviceContext(),0.0f, 0.0f, 0.0f, 1.0f);

	//第三,生成相机矩阵
	mCamera->Render();

	//第四,获取各大矩阵,注意OrthoMatrix应该是mDownSampleTexture的OrthoMatrix
	WorldMatrix = mD3D->GetWorldMatrix();
	BaseViewMatrix = mCamera->GetBaseViewMatrix();
	OrthoMatrix = mDownSampleTexture->GetOrthoMatrix();


	//第五,关闭Z缓存(准备进行“2D Render”)
	mD3D->TurnOffZBuffer();

	//第六,把跟屏幕四分之一大的BitmapClass的顶点数据和索引数据放入3D渲染流水线
	mSmallWindowBitmapClass->Render(mD3D->GetDeviceContext());

	//第七,用Texture2DShader进行渲染,用到的纹理资源为第一步得到的纹理资源
	result = mTexture2DShaderClass->Render(mD3D->GetDeviceContext(), mSmallWindowBitmapClass->GetIndexCount(), WorldMatrix, BaseViewMatrix, OrthoMatrix, mRenderModelToTextureClass->GetShaderResourceView());
	if (!result)
	{
		MessageBox(NULL, L"mTexture2DShaderClass Render failure", NULL, MB_OK);
		return false;
	}

	//第八,打开Z缓存测试
	mD3D->TurnOnZBuffer();

	//第九,将渲染目标重置为背后缓存
	mD3D->SetBackBufferRender();

	//第十,将渲染视口重置
	mD3D->SetViewPort();

	return true;
}

第三步,RenderHorizontalBlurToTexture函数, 用“2D Render”技术将缩小纹理得到的与屏幕四分之一的纹理贴图,进行水平模糊处理,并最终打印到也是与屏幕四分之一的大小一样大的纹理上

bool GraphicsClass::RenderHorizontalBlurToTexture()
{

	bool result;
	float TextureWidth;
	XMMATRIX WorldMatrix, BaseViewMatrix, OrthoMatrix;

	//(2D Render)用的为正交矩阵而非投影矩阵
	//注意,这次渲染目标依然不是背后缓存,而是原屏幕四份之一的纹理图
	//BaseViewMatrix专门用于“2D Render”的相机变换矩阵

	//首先,求出水平模糊纹理的宽度
	TextureWidth =(float)mHorizontalBlurTexture->GetTextureWidth();

	//第一,将渲染目标(从背后)变为屏幕四分之一大的纹理图上,并变换视口
	mHorizontalBlurTexture->SetRenderTarget(mD3D->GetDeviceContext());

	//第二,清除目的纹理的颜色黑色
	mHorizontalBlurTexture->ClearRenderTarget(mD3D->GetDeviceContext(), 0.0f, 0.0f, 0.0f, 1.0f);

	//第三,生成相机矩阵
	mCamera->Render();

	//第四,获取各大矩阵
	WorldMatrix = mD3D->GetWorldMatrix();
	BaseViewMatrix = mCamera->GetBaseViewMatrix();
	OrthoMatrix = mHorizontalBlurTexture->GetOrthoMatrix();

	//第五,关闭Z缓存(准备进行“2D Render”)
	mD3D->TurnOffZBuffer();

	//第六,把跟屏幕四分之一大的BitmapClass的顶点数据和索引数据放入3D渲染流水线
	mSmallWindowBitmapClass->Render(mD3D->GetDeviceContext());

	//第七,用HorizontalBurShader进行渲染,用到的纹理资源为第二步得到的纹理资源
	result = mHorizontalBlurShaderClass->Render(mD3D->GetDeviceContext(), mSmallWindowBitmapClass->GetIndexCount(), WorldMatrix, BaseViewMatrix, OrthoMatrix,mDownSampleTexture->GetShaderResourceView(),TextureWidth);
	if (!result)
	{
		MessageBox(NULL, L" mHorizontalBlurShaderClass Render failure", NULL, MB_OK);
		return false;
	}

	//第八,打开Z缓存测试
	mD3D->TurnOnZBuffer();

	//第九,将渲染目标重置为背后缓存
	mD3D->SetBackBufferRender();

	//第十,将渲染视口重置
	mD3D->SetViewPort();
	return true;
}

第四步,RenderVerticalBlurToTexture函数,糊算法第四步,用“2D Render”技术将经过水平模糊处理得到的与屏幕四分之一的纹理贴图,进行垂直模糊处理,并最终打印到也是与屏幕四分之一的大小一样大的纹理上

bool GraphicsClass::RenderVerticalBlurToTexture()
{
	bool result;
	float TextureHeight;
	XMMATRIX WorldMatrix, BaseViewMatrix, OrthoMatrix;

	//(2D Render)用的为正交矩阵而非投影矩阵
	//注意,这次渲染目标依然不是背后缓存,而是原屏幕四份之一的纹理图
	//BaseViewMatrix专门用于“2D Render”的相机变换矩阵

	//首先,求出垂直模糊纹理的宽度
	TextureHeight = (float)mVerticalBlurTexture->GetTextureHeight();

	//第一,将渲染目标(从背后)变为屏幕四分之一大的纹理图上,并变换视口
	mVerticalBlurTexture->SetRenderTarget(mD3D->GetDeviceContext());

	//第二,清除目的纹理的颜色黑色
	mVerticalBlurTexture->ClearRenderTarget(mD3D->GetDeviceContext(),0.0f, 0.0f, 0.0f, 1.0f);

	//第三,生成相机矩阵
	mCamera->Render();

	//第四,获取各大矩阵
	WorldMatrix = mD3D->GetWorldMatrix();
	BaseViewMatrix = mCamera->GetBaseViewMatrix();
	OrthoMatrix = mVerticalBlurTexture->GetOrthoMatrix();

	//第五,关闭Z缓存(准备进行“2D Render”)
	mD3D->TurnOffZBuffer();

	//第六,把跟屏幕四分之一大的BitmapClass的顶点数据和索引数据放入3D渲染流水线
	mSmallWindowBitmapClass->Render(mD3D->GetDeviceContext());

	//第七,用VerticalBlurShaderClass进行渲染,用到的纹理资源为第三步得到的纹理资源
	result = mVerticalBlurShaderClass->Render(mD3D->GetDeviceContext(), mSmallWindowBitmapClass->GetIndexCount(), WorldMatrix, BaseViewMatrix, OrthoMatrix, mHorizontalBlurTexture->GetShaderResourceView(), TextureHeight);
	if (!result)
	{
		MessageBox(NULL, L" mVerticalBlurShaderClass Render failure", NULL, MB_OK);
		return false;
	}

	//第八,打开Z缓存测试
	mD3D->TurnOnZBuffer();

	//第九,将渲染目标重置为背后缓存
	mD3D->SetBackBufferRender();

	//第十,将渲染视口重置
	mD3D->SetViewPort();
	return true;
}


第五步,UpRenderSampleTexture函数, 模糊算法第五步,用“2D Render”技术将经过垂直模糊处理得到的与屏幕四分之一的纹理贴图,打印到也是与屏幕一样大的纹理上,也就是将经过模糊处理纹理变为与屏幕纹理一样大

bool GraphicsClass::UpRenderSampleTexture()
{

	bool result;
	XMMATRIX WorldMatrix, BaseViewMatrix, OrthoMatrix;

	//(2D Render)用的为正交矩阵而非投影矩阵
	//注意,这次渲染目标依然不是背后缓存,而是原屏幕一样大的纹理图
	//BaseViewMatrix专门用于“2D Render”的相机变换矩阵

	//第一,将渲染目标(从背后)变为屏幕四分之一大的纹理图上,并变换视口
	mUpSampleTexture->SetRenderTarget(mD3D->GetDeviceContext());

	//第二,清除目的纹理的颜色黑色
	mUpSampleTexture->ClearRenderTarget(mD3D->GetDeviceContext(), 0.0f, 0.0f, 0.0f, 1.0f);

	//第三,生成相机矩阵
	mCamera->Render();

	//第四,获取各大矩阵
	WorldMatrix = mD3D->GetWorldMatrix();
	BaseViewMatrix = mCamera->GetBaseViewMatrix();
	OrthoMatrix = mUpSampleTexture->GetOrthoMatrix();


	//第五,关闭Z缓存(准备进行“2D Render”)
	mD3D->TurnOffZBuffer();

	//第六,把跟屏幕一样大的BitmapClass的顶点数据和索引数据放入3D渲染流水线
	mFullWindowBitmapClass->Render(mD3D->GetDeviceContext());

	//第七,用Texture2DShader进行渲染,用到的资源为第四步得到的纹理资源
	result = mTexture2DShaderClass->Render(mD3D->GetDeviceContext(),mFullWindowBitmapClass->GetIndexCount(), WorldMatrix, BaseViewMatrix, OrthoMatrix, mVerticalBlurTexture->GetShaderResourceView());
	if (!result)
	{
		MessageBox(NULL, L"mTexture2DShaderClass Render failure", NULL, MB_OK);
		return false;
	}

	//第八,打开Z缓存测试
	mD3D->TurnOnZBuffer();

	//第九,将渲染目标重置为背后缓存
	mD3D->SetBackBufferRender();

	//第十,将渲染视口重置
	mD3D->SetViewPort();

	return true;
}

第六步,Render2DTextureToScene函数, 模糊算法第六步,用“2D Render”技术将放大与屏幕一样大的纹理贴图,打印到背后缓存上

bool GraphicsClass::Render2DTextureToScene()
{
	bool result;
	XMMATRIX WorldMatrix, BaseViewMatrix, OrthoMatrix, viewMatrix;

	//(2D Render)用的为正交矩阵而非投影矩阵
	//注意,最后一步的渲染目标是背后缓存
	//BaseViewMatrix专门用于“2D Render”的相机变换矩阵

	/*------------------------------------进行最后的非文本类绘制---------------------------------------------------*/


	//第一步,开始绘制3D场景
	mD3D->BeginScene(0.0f,0.0f,1.0f,1.0f);

	//第二,生成相机矩阵
	mCamera->Render();

	//第三,获取各大矩阵
	WorldMatrix = mD3D->GetWorldMatrix();
	BaseViewMatrix = mCamera->GetBaseViewMatrix();
	OrthoMatrix = mD3D->GetOrthoMatrix();


	//第四,关闭Z缓存(准备进行“2D Render”)
	mD3D->TurnOffZBuffer();

	//第五,把跟屏幕一样大的BitmapClass的顶点数据和索引数据放入3D渲染流水线
	mFullWindowBitmapClass->Render(mD3D->GetDeviceContext());

	//第六,用Texture2DShader进行渲染,用到的资源为第四步得到的纹理资源
	result = mTexture2DShaderClass->Render(mD3D->GetDeviceContext(), mFullWindowBitmapClass->GetIndexCount(), WorldMatrix, BaseViewMatrix, OrthoMatrix, mDownSampleTexture->GetShaderResourceView());
	if (!result)
	{
		MessageBox(NULL, L"mTexture2DShaderClass Render failure", NULL, MB_OK);
		return false;
	}

	//第七,打开Z缓存测试
	mD3D->TurnOnZBuffer();


	/*-----------------------------进行最后文本类的绘制-------------------------------------------------------*/
	//第八,关闭Z缓存,进行Alpha混合
	mD3D->TurnOffZBuffer();
	mD3D->TurnOnAlphaBlend();

	//第九,进行字体的绘制
	mTextClass->Render(mD3D->GetDeviceContext(), WorldMatrix, BaseViewMatrix, OrthoMatrix);

	//,将渲染场景提呈现给视口
	mD3D->EndScene();

	return true;
}

在放出水平模糊处理的Shader和垂直处理Shader的代码:

HorizontalBlurShader.fx

Texture2D ShaderTexture:register(t0);  //纹理资源
SamplerState SampleType:register(s0);   //采样方式

//VertexShader
cbuffer CBMatrix:register(b0)
{
	matrix World;
	matrix View;
	matrix Proj;
};

cbuffer CBScreenWidth:register(b1)
{
	float ScreenWidth;
	float3 pad;
}

struct VertexIn
{
	float3 Pos:POSITION;
	float2 Tex:TEXCOORD0;  //多重纹理可以用其它数字
};


struct VertexOut
{
	float4 Pos:SV_POSITION;
	float2 Tex:TEXCOORD0;
	float2 TexCoord1:TEXCOORD1;
	float2 TexCoord2:TEXCOORD2;
	float2 TexCoord3:TEXCOORD3;
	float2 TexCoord4:TEXCOORD4;
	float2 TexCoord5:TEXCOORD5;
	float2 TexCoord6:TEXCOORD6;
	float2 TexCoord7:TEXCOORD7;
	float2 TexCoord8:TEXCOORD8;
	float2 TexCoord9:TEXCOORD9;
};


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.Tex= ina.Tex;

	//根据纹理坐标系统U的宽度为1.0f,求出纹理图中每个像素的U值的宽度(ScreenWidth代表了水平上有多少个像素)
	float TexelSize = 1.0f / ScreenWidth;

	//获取像素以及其水平周围左右两边的像素的UV坐标,这个Shader只处理水平模糊,因此V值偏移量0.0f;
	outa.TexCoord1 = ina.Tex + float2(TexelSize*-4.0f, 0.0f); //左边
	outa.TexCoord2 = ina.Tex + float2(TexelSize*-3.0f, 0.0f);
	outa.TexCoord3 = ina.Tex + float2(TexelSize*-2.0f, 0.0f);
	outa.TexCoord4 = ina.Tex + float2(TexelSize*-1.0f, 0.0f);
	outa.TexCoord5 = ina.Tex + float2(TexelSize*0.0f, 0.0f);//刚好
	outa.TexCoord6 = ina.Tex + float2(TexelSize*1.0f, 0.0f);//右边
	outa.TexCoord7 = ina.Tex + float2(TexelSize*2.0f, 0.0f);
	outa.TexCoord8 = ina.Tex + float2(TexelSize*3.0f, 0.0f);
	outa.TexCoord9 = ina.Tex + float2(TexelSize*4.0f, 0.0f);
	
	return outa;
}


float4 PS(VertexOut outa) : SV_Target
{
	float4 color;  //输出的颜色值
    float weight0, weight1, weight2, weight3, weight4; //原像素和其左右像素的权重值
	float TotalWeight;

	//赋予权重值
	weight0 = 1.0f;  //越靠近原像素的权重越大
	weight1 = 1.0f;
	weight2 = 1.0f;
	weight3 = 1.0f;
	weight4 = 1.0f;

	//求出总权重值
	TotalWeight = weight0 + 2.0f*(weight1 + weight2 + weight3 + weight4);

	//求出原像素和水平左右旁边像素的权重比
	weight0 = weight0 / TotalWeight;
	weight1 = weight1 / TotalWeight;
	weight2 = weight2 / TotalWeight;
	weight3 = weight3 / TotalWeight;
	weight4 = weight4 / TotalWeight;

	//初始化颜色值
	color = float4(0.0f, 0.0f, 0.0f, 1.0f);

	//将原像素和水平左右像素的颜色值按权重相加起来
	color += ShaderTexture.Sample(SampleType, outa.TexCoord1)*weight4;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord2)*weight3;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord3)*weight2;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord4)*weight1;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord5)*weight0;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord6)*weight1;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord7)*weight2;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord8)*weight3;
	color += ShaderTexture.Sample(SampleType, outa.TexCoord9)*weight4;

   //将color的Alpha设置为1.0f
	color.a = 1.0f;

	return color;
}



VerticalBlurShader.fx
Texture2D ShaderTexture:register(t0);  //纹理资源
SamplerState SampleType:register(s0);   //采样方式

//VertexShader
cbuffer CBMatrix:register(b0)
{
	matrix World;
	matrix View;
	matrix Proj;
};


cbuffer CBScreenHeight:register(b1)
{
	float ScreenHeight;
	float3 pad;
}

struct VertexIn
{
	float3 Pos:POSITION;
	float2 Tex:TEXCOORD0;  //多重纹理可以用其它数字
};


struct VertexOut
{
	float4 Pos:SV_POSITION;
	float2 Tex:TEXCOORD0;
	float2 TexCoord1:TEXCOORD1;
	float2 TexCoord2:TEXCOORD2;
	float2 TexCoord3:TEXCOORD3;
	float2 TexCoord4:TEXCOORD4;
	float2 TexCoord5:TEXCOORD5;
	float2 TexCoord6:TEXCOORD6;
	float2 TexCoord7:TEXCOORD7;
	float2 TexCoord8:TEXCOORD8;
	float2 TexCoord9:TEXCOORD9;
};


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.Tex = ina.Tex;

	//根据纹理坐标系统V的宽度为1.0f,求出纹理图中每个像素的V值的宽度(ScreenHeight代表了垂直上有多少个像素)
	float TexelSize = 1.0f / ScreenHeight;

	//获取像素以及其水平周围上下两边的像素的UV坐标,这个Shader只处理垂直模糊,因此U值偏移量0.0f;
	outa.TexCoord1 = ina.Tex + float2(0.0f,TexelSize*-4.0f);//上边
	outa.TexCoord2 = ina.Tex + float2(0.0f,TexelSize*-3.0f);
	outa.TexCoord3 = ina.Tex + float2(0.0f,TexelSize*-2.0f);
	outa.TexCoord4 = ina.Tex + float2(0.0f,TexelSize*-1.0f);
	outa.TexCoord5 = ina.Tex + float2(0.0f,TexelSize*0.0f);//刚好
	outa.TexCoord6 = ina.Tex + float2(0.0f,TexelSize*1.0f);//下边
	outa.TexCoord7 = ina.Tex + float2(0.0f,TexelSize*2.0f);
	outa.TexCoord8 = ina.Tex + float2(0.0f,TexelSize*3.0f);
	outa.TexCoord9 = ina.Tex + float2(0.0f,TexelSize*4.0f);

	return outa;
}


float4 PS(VertexOut outa) : SV_Target
{
	float4 color;  //输出的颜色值
    float weight0, weight1, weight2, weight3, weight4; //原像素和其左右像素的权重值
    float TotalWeight;


   //赋予权重值
    weight0 = 1.0f;  //越靠近原像素的权重越大
    weight1 = 1.0f;
    weight2 = 1.0f;
    weight3 = 1.0f;
    weight4 = 1.0f;

   //求出总权重值
   TotalWeight = weight0 + 2.0f*(weight1 + weight2 + weight3 + weight4);

   //求出原像素和水平左右旁边像素的权重比
   weight0 = weight0 / TotalWeight;
   weight1 = weight1 / TotalWeight;
   weight2 = weight2 / TotalWeight;
   weight3 = weight3 / TotalWeight;
   weight4 = weight4 / TotalWeight;

   //初始化颜色值
   color = float4(0.0f, 0.0f, 0.0f, 1.0f);

   //将原像素和水平左右像素的颜色值按权重相加起来
   color += ShaderTexture.Sample(SampleType, outa.TexCoord1)*weight4;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord2)*weight3;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord3)*weight2;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord4)*weight1;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord5)*weight0;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord6)*weight1;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord7)*weight2;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord8)*weight3;
   color += ShaderTexture.Sample(SampleType, outa.TexCoord9)*weight4;

   //将color的Alpha设置为1.0f
    color.a = 1.0f;

	return color;
}


最后两点艺注意:
(1)上面降低纹理的分辨率在进行模糊处理的原因我在注释里已经说明了,这里在重申一遍:节省性能。
(2)RenderModelToTexureClass要有所改变,因为伴随着渲染目的视图分辨率不是ScreenWidth和ScreenHeight,有几个创建时需要用到宽度和高度变量也需要改变,
我直接给出新的RenderModelToTexureClass.h和RenderModelToTexureClass.cpp

RenderModelToTexureClass.h
#pragma once
#ifndef _RENDER_MODEL_TO_TEXTURE_H
#define _RENDER_MODEL_TO_TEXTURE_H

#include<Windows.h>
#include<xnamath.h>
#include<D3D11.h>
#include"Macro.h"
class RenderModelToTextureClass
{
private:
	ID3D11Texture2D* mRenderTargetTexture;
	ID3D11RenderTargetView* mRenderTargetView;
	ID3D11ShaderResourceView* mShaderResourceView;

	//---由于渲染目标的宽度和高度大小可能跟原来的屏幕不一样,这五个在RenderModelToTextureClass类中重新创建并且设定
	D3D11_VIEWPORT md3dViewport;//视口
	ID3D11Texture2D* mDepthStencilBuffer;  //深度模板缓存
	ID3D11DepthStencilView* mDepthStencilView; //深度模板缓存视图
	XMMATRIX mProjMatrix; //投影矩阵
	XMMATRIX mOrthoMatrix; //正交矩阵

	int mTextureWidth;
	int mTextureHeight;


public:
	RenderModelToTextureClass();
	RenderModelToTextureClass(const RenderModelToTextureClass&other);
	~RenderModelToTextureClass();
	
	bool Initialize(ID3D11Device* d3dDevice,int TextureWidth,int TexureHeight, float screenDepth, float screenNear);
	void ShutDown();

	void SetRenderTarget(ID3D11DeviceContext* deviceContext);
	void ClearRenderTarget(ID3D11DeviceContext* deviceContext, float red, float green, float blue, float alpha);
	

	//Get函数
	ID3D11ShaderResourceView* GetShaderResourceView();
	int GetTextureWidth() { return mTextureWidth; }
	int GetTextureHeight() { return mTextureHeight; }
	XMMATRIX GetProjctionMatrix() { return mProjMatrix; }
	XMMATRIX GetOrthoMatrix() { return mOrthoMatrix; }


   
};
#endif // !_RENDER_3D_MODEL_TO_TEXTURE_H


RenderModelToTexureClass.cpp

#include"RenderModelToTexure.h"


RenderModelToTextureClass::RenderModelToTextureClass()
{
	mRenderTargetTexture = NULL;
	mRenderTargetView = NULL;
	mShaderResourceView = NULL;
	mDepthStencilBuffer = NULL;
	mDepthStencilView = NULL;
}


RenderModelToTextureClass::RenderModelToTextureClass(const RenderModelToTextureClass&other)
{

}

RenderModelToTextureClass::~RenderModelToTextureClass()
{

}


bool RenderModelToTextureClass::Initialize(ID3D11Device* d3dDevice, int TextureWidth, int TexureHeight, float screenDepth, float screenNear)
{
	//首先,赋值纹理资源的宽度和高度
	mTextureWidth = TextureWidth;
	mTextureHeight = TexureHeight;

	//第一,填充2D纹理形容结构体,并创建2D渲染纹理
	D3D11_TEXTURE2D_DESC textureDesc;
	ZeroMemory(&textureDesc, sizeof(textureDesc));

	textureDesc.Width = mTextureWidth;
	textureDesc.Height = mTextureHeight;
	textureDesc.MipLevels = 1;
	textureDesc.ArraySize = 1;
	textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;  //纹理像素为12个字节
	textureDesc.SampleDesc.Count = 1;
	textureDesc.Usage = D3D11_USAGE_DEFAULT;
	textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	textureDesc.CPUAccessFlags = 0;
	textureDesc.MiscFlags = 0;

	HR(d3dDevice->CreateTexture2D(&textureDesc, NULL, &mRenderTargetTexture));

	//第二,填充渲染目标视图形容体,并进行创建目标渲染视图
	D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;

	renderTargetViewDesc.Format = textureDesc.Format;
	renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
	renderTargetViewDesc.Texture2D.MipSlice = 0;
	HR(d3dDevice->CreateRenderTargetView(mRenderTargetTexture, &renderTargetViewDesc, &mRenderTargetView));


	//第三,填充着色器资源视图形容体,并进行创建着色器资源视图
	D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
	shaderResourceViewDesc.Format = textureDesc.Format;
	shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
	shaderResourceViewDesc.Texture2D.MipLevels = 1;

	HR(d3dDevice->CreateShaderResourceView(mRenderTargetTexture, &shaderResourceViewDesc, &mShaderResourceView));

	//--------------------------------------------------------------
	//第四,填充2DTexture深度缓存(模板缓存)形容结构体,创建深度缓存(模板缓存)
	//--------------------------------------------------------------
	D3D11_TEXTURE2D_DESC depthStencilDesc;
	ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
	depthStencilDesc.Width = TextureWidth;
	depthStencilDesc.Height = TexureHeight;
	depthStencilDesc.MipLevels = 1;
	depthStencilDesc.ArraySize = 1;
	depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthStencilDesc.SampleDesc.Count = 1;
	depthStencilDesc.SampleDesc.Quality = 0;
	depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
	depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	depthStencilDesc.CPUAccessFlags = 0;
	depthStencilDesc.MiscFlags = 0;
	HR(d3dDevice->CreateTexture2D(&depthStencilDesc,//要创建的纹理的形容
		0,
		&mDepthStencilBuffer)); //指向深度缓存的指针




	//--------------------------------------------------------------
	//第五,填充深度缓存视图形容结构体,创建深度缓存(模板缓存)视图
	//--------------------------------------------------------------
	D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
	ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));
	depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	depthStencilViewDesc.Texture2D.MipSlice = 0;

	HR(d3dDevice->CreateDepthStencilView(
		mDepthStencilBuffer, //我们基于这个深度缓存/漏字板缓存创建一个视图
		&depthStencilViewDesc,
		&mDepthStencilView));//指向深度缓存/漏字板视图的指针


	//第六,设置渲染的视口
	md3dViewport.Width = static_cast<float>(TextureWidth);
	md3dViewport.Height = static_cast<float>(TexureHeight);
	md3dViewport.MinDepth = 0.0f;
	md3dViewport.MaxDepth = 1.0f;
	md3dViewport.TopLeftX = 0.0f;
	md3dViewport.TopLeftY = 0.0f;

	//第七,创建投影矩阵
	float fieldOfView = XM_PIDIV4;
	float screenAspect = (float)TextureWidth/ (float)TexureHeight;
	mProjMatrix = XMMatrixPerspectiveFovLH(fieldOfView, screenAspect, screenNear, screenDepth);


	//第八,创建正交矩阵,2D渲染矩阵,用于变换用户接口,正交投影矩阵
	mOrthoMatrix = XMMatrixOrthographicLH(static_cast<float>(TextureWidth), static_cast<float>(TexureHeight), screenNear, screenDepth);

	return true;

}


void RenderModelToTextureClass::ShutDown()
{
	ReleaseCOM(mDepthStencilBuffer);
	ReleaseCOM(mDepthStencilView);
	ReleaseCOM(mRenderTargetTexture);
	ReleaseCOM(mRenderTargetView);
	ReleaseCOM(mShaderResourceView);
}


//让此时所有图形渲染到这个目前渲染的位置
void RenderModelToTextureClass::SetRenderTarget(ID3D11DeviceContext* deviceContext)
{
	//将渲染目标变为纹理资源视图
	deviceContext->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);

	//设置视口
	deviceContext->RSSetViewports(1, &md3dViewport);
}

void RenderModelToTextureClass::ClearRenderTarget(ID3D11DeviceContext* deviceContext,  float red, float green, float blue, float alpha)
{
	//设置清除缓存为的颜色
	float color[4];
	color[0] = red;
	color[1] = green;
	color[2] = blue;
	color[3] = alpha;

	//清除背后缓存
	deviceContext->ClearRenderTargetView(mRenderTargetView, color);

	//清除深度缓存和模板缓存
	deviceContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}

// 将“被渲染模型到纹理的纹理”作为ShaderResourceView资源返回,这个资源将会跟其它的ShaderResourceView资源一样被送入Shader里计算.
ID3D11ShaderResourceView* RenderModelToTextureClass::GetShaderResourceView()
{
	return mShaderResourceView;
}




最后放出程序运行图


不进行迷糊处理的





进行模糊处理的:






得注意一点:RT的大小和深度缓存的大小以及ViewPort的大小应该是一致的,(渲染到屏幕时,backBuffer,depthBuffer,Viewport的大小应该也是一致的)这里可以参考我的软光栅器实现教程的源码就知道为什么了。所以你在进行渲染RT技术时,得同时创建大小匹配的ViewPort和DepthBufferView

从帧数的运行可以直观的看出模糊处理还是比较消耗性能的,所以得根据具体的情况进行优化

我的源代码链接如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值