两个月前,刚接触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. 浅谈SpringMVC

    M--模型(实体vo[视图对象]与页面对面) V--视图(JSP,,velocity,FreeMarker,html,thymeleaf) C--控制器(servlet,if语句控制M数据跳转到V进行 ...

  2. 2018-2019-2 网络对抗技术 20165301 Exp4 恶意代码分析

    2018-2019-2 网络对抗技术 20165301 Exp4 恶意代码分析 实验内容 系统运行监控 使用如计划任务,每隔一分钟记录自己的电脑有哪些程序在联网,连接的外部IP是哪里.运行一段时间并分 ...

  3. 跟据经纬度实现附近搜索Java实现

    现在很多手机软件都用附近搜索功能,但具体是怎么实现的呢>在网上查了很多资料,mysql空间数据库.矩形算法.geohash我都用过了,当数据上了百万之后mysql空间数据库方法是最强最精确的(查 ...

  4. ubuntu下root和安装mysql

    sudo password创建新的root密码: 1.用当前登录用户打开终端,在终端输入命令 sudo passwd,输入当前用户的密码然后回车 2.会提示输入新密码,输入完成后回车(http://w ...

  5. 【BZOJ】4292: [PA2015]Równanie

    题解 \(f(n)\)的取值范围最多\(9^2 * 18\) 直接枚举判断就好 代码 #include <bits/stdc++.h> #define fi first #define s ...

  6. Spring中AOP实现

    1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...

  7. sorted()排序详解

    sorted()排序详解     http://wiki.python.org/moin/HowTo/Sorting?highlight=%28howto%29#The_Old_Way_Using_t ...

  8. jquery插件机制

    jQuery插件开发全解析 jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命 ...

  9. View 的滑动

    View 的滑动 学习自 <Android开发艺术探索> 滑动漫谈 因为Android手机屏幕大小的原因,所以为了显式更多的信息,我们必须采用滚动的方式来处理,因为滚动就涉及到了滑动,有的 ...

  10. Nmap扫描教程之网络基础服务DHCP服务类

    Nmap扫描教程之网络基础服务DHCP服务类 Nmap网络基础服务 网络基础服务是网络正常工作的基石,常见的网络基础服务包括DHCP服务和DNS服务.其中,DHCP服务用来为计算机动态分配IP地址:D ...