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

来源:互联网 发布:蹭网软件下载 编辑:程序博客网 时间:2024/06/05 08:36

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




一,Glow(边缘发光效果)

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



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


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

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

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

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



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



实现的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,如下所示:



相应的Shader实现代码:

HorizontalBlurShader.fx

Texture2D ShaderTexture:register(t0);  //纹理资源SamplerState SampleType:register(s0);   //采样方式//VertexShadercbuffer 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);   //采样方式//VertexShadercbuffer 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之间,将这部分的像素变为“高亮部分”,如下图所示:



实现的Shader代码如下:

GlowShader.fx

Texture2D SceneRTT:register(t0);  //SceneRTTTexture2D GlowMapRTT:register(t1);  //GlowMapRTTSamplerState 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

原创粉丝点击