两个月前,刚接触unity的时候费了半天劲儿做了个荧光效果(见:http://www.cnblogs.com/wantnon/p/4430749.html),今天终于抽空整理了一下,把过程写下来。

荧光效果截图:

 

一,接口:

整理完以后得到三个东西:AE_GroupBloom.cs,Camera_renderBloomRT.prefab,bloomEmitter.shader。

使用方法:

1,将AE_GroupBloom.cs添加到Main Camera上。

2,将Camera_renderBloomRT.prefab添加到场景中。并将Main Camera赋给其中的Main Camera Ref。

3,将发光物体的shader选为Custom/bloomEmitter。

这样就可以实现上面图中的效果。下面说具体代码。

二,实现原理:

(注:我用的是unity5)

AE_GroupBloom.cs代码如下:

using UnityEngine;
using System.Collections;
public class AE_GroupBloom : MonoBehaviour {
    public Material m_groupBloomMaterial;
    void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture){
        ////Debug.Log (destTexture);
        //Copies source texture into destination render texture with a shader.
        Graphics.Blit (sourceTexture, destTexture, m_groupBloomMaterial);
    }
}

Camera.OnRenderImage的官方文档中写道:

OnRenderImage is called after all rendering is complete to render image.

Postprocessing effects.

It allows you to modify final image by processing it with shader based filters. The incoming image is source render texture. The result should end up in destination render texture. When there are multiple image filters attached to the camera, they process image sequentially, by passing first filter's destination as the source to the next filter.

This message is sent to all scripts attached to the camera.

Graphics.Blit的官方文档中写道:

Copies source texture into destination render texture with a shader.
This is mostly used for implementing image effects.

Blit sets dest as the render target, sets source _MainTex property on the material, and draws a full-screen quad.

在此处由于脚本加在Main Camera上,所以OnRenderImage的sourceTexture就是Main Camera渲染的画面,destTexture就是Inspector中显示的Main Camera的Camera组件中的Target Texture属性,我们这里用其默认值None,表示直接渲染到屏幕(此时若在脚本中输出destTexture的值,结果为Null)(否则可以赋一个renderTexture,使此相机渲染到renderTexture上)。Graphics.Blit(sourceTexture, destTexture, m_groupBloomMaterail)的意思就是将Main Camera渲染的画面经过m_groupBloomMaterial中的shader过滤后传送到屏幕(而且sourceTexture会用作m_groupBloomMaterial的shader的_MainTex)。可见,这便是典型的后处理过程,m_groupBloomMaterial中的shder便是后处理shader。

(另外上面OnRenderImage的文档中还提到:如果相机上添加多个后处理脚本则会依次执行,而且前一个的destTexture用作下一个的sourceTexture,本例中尚且用不到这个)。

m_groupBloomMaterial是在脚本的setting中事先赋值好的(AE_GroupBloom.mat),如图:

AE_GroupBloom.mat中的shader用的是Custom/AE_GroupBloom.shader,代码如下:

Shader "Custom/AE_GroupBloom" {
    Properties {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _BloomTex ("BloomTex (RGB)", 2D) = "white" {}
        _BloomFactor("Bloom Factor",Range(0,10)) =2.0
    }
    SubShader {

      ZWrite Off //注意,这句和下一句对于iOS特别重要,如果没有这两句,在iOS真机上运行将会黑屏。
       ZTest Always
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

#include "UnityCG.cginc"
            
            uniform sampler2D _MainTex;
            uniform sampler2D _BloomTex;
            float _BloomFactor;
            v2f_img vert(appdata_img v) : POSITION {
                v2f_img o;
                o.pos=mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv=v.texcoord.xy;
                return o;
            }
            fixed4 frag(v2f_img i):COLOR
            {
                //Get the colors from the RenderTexture and the uv's
                //from the v2f_img struct
                fixed4 mainColor = tex2D(_MainTex, i.uv);
                fixed4 bloomColor= tex2D(_BloomTex, i.uv);
                fixed4 finalColor =bloomColor*_BloomFactor+mainColor;
                return finalColor;
            }
            ENDCG
        }
    } 
    FallBack "Diffuse"
}

前面说了_MainTex就是Main Camera渲染的画面,在shader中按如下公式进行合成:

FinalTex=MainTex+BloomTex*BloomFactor

在本例中,我取的是BloomFactor=2.

即:

 =  +  *2

于是,现在剩下的问题就是BloomTex如何得到。

1,错误的方法:

最容易想到的办法就是把这些发光物体单独渲染到一个renderTexture上,然后作blur,即得到BloomTex。

只可惜这个方法是错误的,原因在于这种方法没考虑深度遮挡问题,如下图所示:

   

当发光物体被其它物体遮挡时,BloomTex上应该有相应的“缺口”。所以上面所述单独只将发光物体渲染一遍是错误的。

2,正确的方法:

知道了前面方法错在哪里,正确的方法自然也就有了。正确的方法是应该将所有物体都渲染一遍,并且对于所有非发光物体使用“纯黑”shader渲染,对于发光物体使用UnlitColor(颜色无光照)shader渲染,最后再blur,这样就能得到带“缺口”的BloomTex了。

具体实现如下:

新建一个RenderTexture命名为bloomRT(注意,由于我们并不需要深度信息,所以这个bloomRT可以选为No depth buffer,不会影响渲染到渲染效果),新建一个Camera命名为Camera_renderBloomRT。

在Inspector中将Camera_renderBloomRT的Camera组件的Target Texture赋为bloomRT。这样Camera_renderBloomRT就会把图像渲染到bloomRT上了。

为Camera_renderBloomRT添加脚本renderBloomRT(并在Inspector中将Main Camera赋给其中的m_mainCameraRef变量):

using UnityEngine;
using System.Collections;
public class renderBloomRT : MonoBehaviour {
    public Camera m_mainCameraRef;
    public Shader m_renderBloomTexShader;
    // Use this for initialization
    void Start () {

GetComponent<Camera> ().enabled = false;//it is equals to uncheck Camera component in Inspector
        synchronizePosAndRotWithMainCamera ();
        synchronizeProjModeAndFrustomWithMainCamera ();
    }
    void LateUpdate () {
        synchronizePosAndRotWithMainCamera ();
        //Rendering with Replaced Shaders: http://www.cnblogs.com/wantnon/p/4528677.html
        GetComponent<Camera>().RenderWithShader(m_renderBloomTexShader, "RenderType");
    }
    void synchronizePosAndRotWithMainCamera(){
        transform.position=m_mainCameraRef.transform.position;
        transform.rotation = m_mainCameraRef.transform.rotation;
    }
    void synchronizeProjModeAndFrustomWithMainCamera(){
        GetComponent<Camera>().orthographic=m_mainCameraRef.orthographic;
        GetComponent<Camera> ().orthographicSize = m_mainCameraRef.orthographicSize;
        GetComponent<Camera> ().nearClipPlane = m_mainCameraRef.nearClipPlane;
        GetComponent<Camera> ().farClipPlane = m_mainCameraRef.farClipPlane;
        GetComponent<Camera> ().fieldOfView = m_mainCameraRef.fieldOfView;
    }
    
}

此脚本做了三件事儿:

1,将Camera_renderBloomRT的camera组件disable掉(相当于在inspector中将camera组件前面的勾去掉)。

2,让Camera_renderBloomRT的position和rotation与Main Camera始终保持一致。

3,调用GetComponent<Camera>().RenderWithShader(m_renderBloomTexShader, "RenderType")进行渲染(渲染到bloomRT上)。

m_renderBloomTexShader是在脚本的setting中事先赋好的(Custom/renderBloomTex.shader),如图:

renderBloomTex.shader代码如下:

Shader "Custom/renderBloomTex" {//modified from "Unlit/Color"
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
}
SubShader { //this subShader is same with "Unlit/Color" shader, except the RenderType change to "GroupBloom"
    Tags { "RenderType"="GroupBloom" }
    LOD 100
    Pass {  
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

struct appdata_t {
                float4 vertex : POSITION;
            };
            struct v2f {
                float4 vertex : SV_POSITION;
                UNITY_FOG_COORDS(0)
            };

fixed4 _Color;
            
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : COLOR
            {
                fixed4 col = _Color;
                UNITY_APPLY_FOG(i.fogCoord, col);
                UNITY_OPAQUE_ALPHA(col.a);
                return col;
            }
        ENDCG
    }
}
SubShader { //because this subShader renders pure black, so we need not support fog
    Tags { "RenderType"="Opaque" }
    LOD 100
    
    Pass {  
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

struct appdata_t {
                float4 vertex : POSITION;
            };

struct v2f {
                float4 vertex : SV_POSITION;
            };

fixed4 _Color;
            
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : COLOR
            {
                fixed4 col = float4(0,0,0,1);
                return col;
            }
        ENDCG
    }
}
}

此shader的第一个subShader与unity5内置的"Unlit/Color"shader完全相同,只是将"RenderType"="Opaque"改成了"RenderType"="GroupBloom"。第二个subShader则是将所渲染的像素都弄成纯黑色,其标签仍使用"RenderType"="Opaque"。

当调用GetComponent<Camera>().RenderWithShader(m_renderBloomTexShader, "RenderType"),系统将会对所有含有"RenderType"="Opaque"标签的物体使用第二个subShader进行渲染(渲染成纯黒色),而对所有含有"RenderType"="GroupBloom"标签的物体使用第一个subShader进行渲染(Unlit+Color)。

(注:关于RenderWithShader的详细解释见:http://www.cnblogs.com/wantnon/p/4528677.html)

于是接下来我们就清楚该怎么做了,就是:

1,保证所有想渲染成纯黑色的物体带有"RenderType"="Opaque"标签,这个基本上是自然保证的,因为unity里物体的默认shader都带有"RenderType"="Opaque"标签。

2,保证所有想渲染为Unlit+Color的物体带有"RenderType"="GroupBloom",这个需要我们手动去添加,或者更有条理的办法是创建一个标准shader,命名为“Custom/bloomEmitter”,并为其添加"RenderType"="GroupBloom"标签,然后对于所有的发光物体,都使用此shader。

至此我们就将发光物体与不发光物体以不同的replace shader渲染到bloomRT上了,得到bloomRT如下:

然后再把standard assets中的blur脚本添加到Camera_renderBloomRT上,得到bloomRT如下:

至此bloomRT已完成,我们在AE_GroupBloom.shader的setting中事先将bloomRT赋给BloomTex分量。即bloomRT就是BloomTex。

我们还应该为Camera_renderBloomRT添加下面脚本letRenderTextureAspectEqualsToScreenAspect.cs:

using UnityEngine;
using System.Collections;
public class letRenderTextureAspectEqualsToScreenAspect : MonoBehaviour {
    public RenderTexture m_rt;
    // Use this for initialization
    void Start () {
        float screenAspect = (float)(Screen.width) / Screen.height;
        ////Debug.Log (screenAspect);
        m_rt.width = (int)(m_rt.height*screenAspect);
    }
}

并将bloomRT通过Inspector赋给m_rt.

这样在游戏开发执行时在保持bloomRT的高度不变的前提下重设其宽度,使bloomRT的长宽比与屏幕的长宽比相等,从而保证bloomRT能够正确地与原始游戏画面进行合成。

另外需要注意的是bloomRT的尺寸不必与屏幕相等,出于效率考虑bloomRT的尺寸应在能保证视觉效果可接受的前提下尽可能地小。越小越好。

最后将Camera_renderBloomRT做成prefab。

(完)

unity,荧光效果(bloom)实现过程的更多相关文章

  1. unity, 荧光效果(bloom)

    ----更新:2015-5-31 详细实现过程见:http://www.cnblogs.com/wantnon/p/4542172.html ----原帖:2015-4-16 用摄像机特效只能做全屏b ...

  2. [Unity][Heap sort]用Unity动态演示堆排序的过程(How Heap Sort Works)

    [Unity][Heap sort]用Unity动态演示堆排序的过程 How Heap Sort Works 最近做了一个用Unity3D动态演示堆排序过程的程序. I've made this ap ...

  3. Unity镜子效果的实现(无需镜子Shader)

    Unity镜子效果制作教程 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享. ...

  4. Android ProgressBar 进度条荧光效果

    http://blog.csdn.net/ywtcy/article/details/7878289 这段时间做项目,产品需求,进度条要做一个荧光效果,类似于Android4.0 浏览器中进度条那种样 ...

  5. css3系列之text-shadow 浮雕效果,镂空效果,荧光效果,遮罩效果

    text-shadow 其实这东西,跟  box-shadow 差不多,没啥好说的不懂的话,点这里→  css3系列之详解box-shadow  . 它只有 四个参数 x(第一个值设置x位置) y(第 ...

  6. Unity Shader 屏幕后效果——Bloom外发光

    Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成. 一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客: https:/ ...

  7. unity描边效果

    这里总结了几种在unity实现描边效果的方法,首先准备一个模型导入在unity中,使用默认shader,上传一张原始图,以便后面实现功能效果的对比 一.边缘光,这里参照官方的一个SurfaceShad ...

  8. Unity Shader 效果(1) :图片流光效果

    很多游戏Logo中可以看到这种流光效果,一般的实现方案就是对带有光条的图片uv根据时间进行移动,然后和原图就行叠加实现,不过实现过程中稍稍有点需要注意的地方.之前考虑过风宇冲的实现方式,但是考虑到sh ...

  9. UNITY 接讯飞语音过程总结

    11:13 2017/3/141,安装问题:JDK与ECLIPSE位数一定要对应,32位对64位会出现 java was returned ....code 13的弹框错误.版本号可以不一致.2,EC ...

随机推荐

  1. IOC入门

    Spring六大模块 1.SpringCore  spring的核心功能:IOC容器,解决对象的创建及依赖关系 2.SpringWeb   spring对Web模块的支持 3.SpringDAO  s ...

  2. Win7系统Chrome浏览器缓存查看技巧介绍(转)

    1.Chrome下提供了一个命令chrome://cache,可以查看到保留下来的缓存; 2.但是,当你点击缓存文件,Chrome却并非打开缓存源文件,而是如图所示的二进制编码文件; 3.在Win7系 ...

  3. Mybatis输入映射和输出映射

    本节内容: 输入参数映射 输出映射 resultMap Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心. 一.环境准备 复制 ...

  4. Cname与A记录(Address)区别

    Cname与A记录(Address)区别A记录是解析域名到IP,Cname是解析域名到另外一个域名. 一台服务器可以布置多个网站,也可以有多个域名,如如域名A----->A记录-----> ...

  5. WebSocket原理说明

    WebSocket原理说明 众所周知,Web应用的通信过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客户端浏览器将信息呈现.这种机制对于信息变化不是特别频繁的应 ...

  6. Windows下 ffmpeg + labelImg 提取视频帧 得到图片集 并 标注图片 来 构造数据集

    构造数据集的流程 视频文件  >>  ffmpeg处理  >>  图片集  >>  labelImg进行标注  >>  标注好的数据集 准备ffmpeg ...

  7. Javascript的字符串(String)操作学习

    1.bold() 方法用于把字符串显示为粗体.语法: stringObject.bold() 如下,对str进行bold操作之后,实际上时对这个字符串加了<b>标签,在文档中将以粗体进行展 ...

  8. 跟厂长学PHP7内核(六):变量之zval

    记得网上流传甚广的段子"PHP是世界上最好的语言",暂且不去讨论是否言过其实,但至少PHP确实有独特优势的,比如它的弱类型,即只需要$符号即可声明变量,使得PHP入手门槛极低,成为 ...

  9. CSUOJ Water Drinking

    Description The Happy Desert is full of sands. There is only a kind of animal called camel living on ...

  10. 既使用maven编译,又使用lib下的Jar包

    <build> <finalName>xxx</finalName> <plugins> <plugin> <groupId>o ...