两个月前,刚接触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. H5页面调用手机打电话功能

    <head>里面加上: <meta name="format-detection" content="telephone=yes"/> ...

  2. java 其它可选方法

    异常处理的一个原则时,只有当你在知道如何处理的情况下才捕获异常,异常处理的一个重要目标时将错误处理代码同错误发生的地点相分离. "被检查异常"强制你在还没准备好处理错误的时候被迫加 ...

  3. ADO.Net练习1

    一. 1.Car表数据查出显示2.请输入要查的汽车名称:     请输入要查的汽车油耗:     请输入要查的汽车马力: static void Main(string[] args) { SqlCo ...

  4. zoj 3809 枚举水题 (2014牡丹江网赛 A题)

    题目大意:给出一列取样的几个山的高度点,求山峰有几个? Sample Input 291 3 2 4 6 3 2 3 151 2 3 4 5Sample Output 30 # include < ...

  5. mybatis使用时遇到的一些问题------模糊查询、处理大于号小于号、相关函数替换空值

    在mybatis中可能会用到的方法 1.模糊查询 <select id="showByIdName" parameterType="User" resul ...

  6. OpenCV中的SVM参数优化

    OpenCV中的SVM参数优化 svm参数优化opencv SVMSVR参数优化CvSVMopencv CvSVM        SVM(支持向量机)是机器学习算法里用得最多的一种算法.SVM最常用的 ...

  7. select 详解

    In summary, a socket will be identified in a particular set when select returns if: readfds:If liste ...

  8. 自主搭建CNN训练时遇到的问题

    1.训练太慢 用nimibatch代替fullbatch https://www.cnblogs.com/guoyaohua/p/8724433.html 2.过拟合 最直接的解决过拟合问题的办法是增 ...

  9. 医学图像之DICOM格式解析

    最近导师给安排了新任务,由于刚进入实验室,对于医学图像这一块还一知半解,所以就想分享一下有关医学常见影像的学习(尤其是dicom后缀的图像文件),欢迎大家一起交流. 目录 1.医学影像学的介绍 2.D ...

  10. 003.KVM虚拟机部署-CentOS6.8

    一 实验说明 CentOS 7的KVM虚拟机推荐使用qcow2磁盘格式,本实验在KVM中安装CentOS 6.8 64虚拟机. 二 命令部署过程 2.1 上传镜像 使用winscp上传至/data/i ...