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
阅读全文
0 0
- Directx11教程四十三之glow(边缘发光)
- Directx11教程四十之加载OBJ模型
- Unity中使用Glow 11边缘发光插件
- 边缘发光
- 图像滤镜艺术---Glow Filter发光滤镜
- 图像特效---Glow Filter发光滤镜
- 设置边缘发光效果
- unity3d边缘发光效果
- 边缘发光shader
- unity shader-边缘发光
- 发光滤镜.就是图像边缘发光
- DirectX11教程
- DirectX11(三)
- Directx11基础教程三之VertexShader,PixelShader,buffer
- I学霸官方免费教程四十三 :Java流之字符流 Reader和Writer
- 鸡啄米c++之四十三 总结
- 【Unity Shader编程】之十四 边缘发光Shader(Rim Shader)的两种实现形态
- Shader编程】之十四 边缘发光Shader(Rim Shader)的两种实现形态
- CodeForces #157(258A|258B|258C|258D|258E)|数位DP|搜索|线段树
- Could not connect to SMTP host: smtp.163.com, port: 25;阿里云 ECS
- Master启动的源码详解
- TCP网络编程中connect()、listen()和accept()三者之间的关系
- 递归
- Directx11教程四十三之glow(边缘发光)
- Word文档插图片问题
- 写接口请求类型为get或post的时,参数定义的几种方式,如何用注解(原创)--雷锋
- Linux C 进程间的IPC通信 之 共享内存(一)
- Ubuntu16.04搜狗拼音输入法候选栏无法显示中文(英文乱码)
- pstree使用缺少命令
- 浅谈反射
- MyBatis概述
- 只能输入3-5个英文字符的正则