Directx11教程四十三之glow(边缘发光)

这一节教程是关于渲染3D物体的发光边缘,代码结构如下:




一,Glow(边缘发光效果)

这里借用下虚幻四引擎演示下“边缘发光效果”,如下图所示:

Directx11教程四十三之glow(边缘发光)_第1张图片


如上面图中虚幻四引擎中被选中的立方体的边缘是发光的,我实现的就是这种发光效果


这里有篇博客介绍了“Glow”是怎么实现的:

[Unity3D][Shader 着色器]给物体边缘加高光轮廓的办法

这里大致说下我实现的方法步骤:

(1)正常的渲染整个场景得到一张RTT,我称其为SceneRTT,如下所示:

Directx11教程四十三之glow(边缘发光)_第2张图片


(2)渲染要发光的物体成一张BlackWhiteRTT(也就是只有黑白两种颜色的RT),如下所示:

Directx11教程四十三之glow(边缘发光)_第3张图片


实现的shader代码:

DrawBlackWhiteShader.fx

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

struct VertexIn
{
	float3 Pos:POSITION;
};


struct VertexOut
{
	float4 Pos:SV_POSITION;

};


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);
	return outa;
}


float4 PS(VertexOut outa) : SV_Target
{
	//输出的像素为白色
	float4 color = float4(1.0f,1.0f,1.0f,1.0f);

   return color;
}




(3)对BlackWhiteRTT进行高斯模糊,将物体边缘的像素偏移,也就是先进行水平模糊,然后进行垂直模糊,最终得到GlowMapVerticalBlurRTT,如下所示:

Directx11教程四十三之glow(边缘发光)_第4张图片


相应的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;
};


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*-1.0f, 0.0f);
	outa.TexCoord2 = ina.Tex + float2(TexelSize*0.0f, 0.0f);//刚好
	outa.TexCoord3 = ina.Tex + float2(TexelSize*1.0f, 0.0f);//右边


	return outa;
}


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

	//赋予权重值
	weight0 = 1.0f;  
	weight1 = 1.0f;


	//求出总权重值
	TotalWeight = weight0 + 2.0f*weight1;

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

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

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

	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;
};


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*-1.0f);
	outa.TexCoord2 = ina.Tex + float2(0.0f,TexelSize*0.0f);//刚好
	outa.TexCoord3 = ina.Tex + float2(0.0f,TexelSize*1.0f);//下边


	return outa;
}


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


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


   //求出总权重值
   TotalWeight = weight0 + 2.0f*weight1;

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

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

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

	return color;
}



(4)进行2D Rendering,将第一步得到的“SceneRTT”和第三步得到的“GlowMapVerticalBlurRTT”作为纹理资源使用。实现“发光边缘”的思路:由于我们对之前只有黑白两色的BlackWhiteRTT进行渲染,那么经过高斯模糊后,GlowMapVerticalBlurRTT的边缘颜色值变为灰色,也就是位于0.0f和1.0f之间,将这部分的像素变为“高亮部分”,如下图所示:

Directx11教程四十三之glow(边缘发光)_第5张图片


实现的Shader代码如下:

GlowShader.fx

Texture2D SceneRTT:register(t0);  //SceneRTT
Texture2D GlowMapRTT:register(t1);  //GlowMapRTT
SamplerState WrapSampleType:register(s0);   //采样方式
											
cbuffer CBMatrix:register(b0)
{
	matrix World;
	matrix View;
	matrix Proj;
};

cbuffer CBGlow:register(b1)
{
	float3 GlowColor;
	float GlowScale;
};

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


struct VertexOut
{
	float4 Pos:SV_POSITION;
	float2 Tex:TEXCOORD0;
};


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;

	return outa;
}


 float4 PS(VertexOut outa) : SV_Target
 {
	 float4 SceneRTTColor;
     float4 GlowMapRTTColor;
	 float4 color;

	 //对GlowMapRTT和SceneRTT采样
	 SceneRTTColor= SceneRTT.Sample(WrapSampleType, outa.Tex);
	 GlowMapRTTColor= GlowMapRTT.Sample(WrapSampleType, outa.Tex);
	 if (GlowMapRTTColor.r>0.0f&& GlowMapRTTColor.r<1.0f)
	 {
		 color = SceneRTTColor + float4(GlowColor, 1.0f)*GlowScale;
	 } 
 
	 else
	 {
		 color = SceneRTTColor;
	 }

     return color;
 }


二,源代码链接:

http://download.csdn.net/detail/qq_29523119/9872964

你可能感兴趣的:(directx11入门)