之前研究了一下怎么让屏幕里部分东西显示bloom效果,例如只是特效显示bloom效果而角色不显示,现在记录一下
我这里加了效果图和工程下载地址,方便大家了解
PS:这个性能有问题,建议看看这边博客,用存储alpha来替换重新渲染一遍带来的性能问题
https://blog.csdn.net/SnoopyNa2Co3/article/details/88075047
扩展:可以修改替换shader,把特定效果部分做成不同颜色区域来进行不同屏幕处理
例如:
渲染成红色作为bloom取图区来处理bloom效果
渲染绿色作为扭曲取图区来处理热扭曲效果
一开始我们设置一个泛光的亮度阈值,然后我们根据屏幕的渲染图来进行筛选,所有小于这个阈值的像素过滤掉(黑色像素),其他像素保留,这样子就只保留了要发光的像素,其他的都是黑色泛光效果是由衍射效果产生的,我们现实世界中看到的泛光效果,最亮的地方实际上是会向暗的地方扩散的,也就是说在亮的地方,边界是不明显的,所以我们就需要对泛光是部分,也就是我们上一步操作的结果图片进行模糊操作,达到光溢出的效果,最后,我们将处理过的图像和原图像进行叠加,就得到了最终的效果。下面是bloom的实现流程图(盗图)
部分和上面全屏泛光的区别在于
全屏泛光:全屏泛光是那屏幕图像来处理泛光,然后和屏幕叠加
部分泛光:自己渲染一张特定的图,然后用这张图处理泛光,最后和屏幕叠加
区别在于这张特定的图,其他的和全屏泛光一样
如果分layer来渲染这张特定图,则没有遮挡效果,所以这种渲染可以放弃
这张特定图除了要泛光之外其余都要黑色也要走遮挡效果,所以用shader替换渲染方法来处理
获取泛光图要用到替换shader渲染方法
m_Camera.RenderWithShader(replaceShader, "RenderType");
这个替换shader是根据shader的标签RenderType来进行替换
除了repalceShader加了对应的替换标签
物体使用的shader也要加对应的标签,所以我这边直接拿原生的shader改一下标签
我这边自己加了“BloomTransparent”和“Bloom”标签(这些标签都是自己定义,自己知道直接写在shader上面)
BloomTransparent:适合渲染队列是Transparent的物体替换shader,对应物体shader改一下RenderType为“BloomTransparent”
Bloom:适合渲染队列是Opaque的物体替换shader,对应的shader改一下RenderType为“Bloom”
我举例一下自带的Mobile-Particle-Add,我这里顺便改一下名字,加了"RenderType"="BloomTransparent",如有需要还要改standar shader,这些看情况而定,这里只做个演示
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
// Simplified Additive Particle shader. Differences from regular Additive Particle one:
// - no Tint color
// - no Smooth particle support
// - no AlphaTest
// - no ColorMask
Shader "Bloom/Particles/Additive" {
Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
}
Category {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="BloomTransparent" "PreviewType"="Plane" }
Blend SrcAlpha One
Cull Off Lighting Off ZWrite Off Fog{ Mode Off }
BindChannels {
Bind "Color", color
Bind "Vertex", vertex
Bind "TexCoord", texcoord
}
SubShader {
Pass {
SetTexture [_MainTex] {
combine texture * primary
}
}
}
}
}
下面是替换shader
分了三种渲染
RenderType为Opaque直接渲染成黑色,
RenderType为Bloom直接渲染原图
RenderType为BloomTransparent按照混合模式渲染
其他直接渲染黑色
Shader "Hidden/Bloom Replace"
{
//替换标签是Bloom的shader
SubShader
{
Tags { "RenderType" = "Bloom" }
Pass {
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
half4 frag(v2f_img i) : COLOR
{
return tex2D(_MainTex,i.uv);
}
ENDCG
}
}
//替换标签是BloomTransparent的shader
SubShader
{
Tags{ "RenderType" = "BloomTransparent" }
Blend SrcAlpha One
Cull Off Lighting Off ZWrite Off Fog{ Mode Off }
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
half4 frag(v2f_img i) : COLOR
{
return tex2D(_MainTex,i.uv);
}
ENDCG
}
}
//替换标签是Opaque的shader,这里直接渲染为黑色
SubShader
{
Tags { "RenderType" = "Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
half4 frag(v2f_img i) : COLOR
{
return half4(0,0,0,0);
}
ENDCG
}
}
Fallback Off
}
RenderType为BloomTransparent和Bloom渲染出原来的颜色,其他没有标签则渲染成黑色,这样的泛光渲染图就这样出来了
下面是写了个脚本用来渲染泛光特定图
using UnityEngine;
using System.Collections;
///
/// 渲染需要广泛那部分的图
///
public class RenderBloomTexture : MonoBehaviour
{
///
/// 主摄像机
///
public Camera m_FollowCamera;
///
/// 渲染需要泛光的摄像机
///
private Camera m_Camera;
///
/// 替换shader
///
public Shader replaceShader;
void Start()
{
m_Camera = GetComponent();
//摄像机背景要设置为黑色
m_Camera.enabled = false;
m_Camera.clearFlags = CameraClearFlags.SolidColor;
m_Camera.backgroundColor = Color.black;
UpdateCamera();
UpdateCameraSetting();
}
void LateUpdate()
{
UpdateCamera();
//调用渲染
m_Camera.RenderWithShader(replaceShader, "RenderType");
}
void UpdateCamera()
{
transform.position = m_FollowCamera.transform.position;
transform.rotation = m_FollowCamera.transform.rotation;
}
void UpdateCameraSetting()
{
m_Camera.orthographic = m_FollowCamera.orthographic;
m_Camera.orthographicSize = m_FollowCamera.orthographicSize;
m_Camera.nearClipPlane = m_FollowCamera.nearClipPlane;
m_Camera.farClipPlane = m_FollowCamera.farClipPlane;
m_Camera.fieldOfView = m_FollowCamera.fieldOfView;
}
}
1.在场景的mian camera下面创建一个camera命名为“RenderCamera”,然后挂上RenderBloomTexture脚本
2.创建一个1920*1080的rendertexture,我这边做测试game视图分辨率和rendertexture一致都是1920*1080
3.把对应的以后shader拖上去和主摄像机拖上去,把新建的rendertexture拖到RenderCamera的TargetTexture,如下图
下面是对应物体设置的shader(这里的standard Shader改成加了标签Bloom改名为standardBloom)
4.直接运行然后看看RenderTexture,如下图有东西挡住就是ok的
泛光渲染图就这样实现出来
整个泛光实现我就不多说,网上多的是
先贴一下效果图
实现BloomEffect效果shader
Shader "BloomEffect" {
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
_BlurTex("Blur", 2D) = "white"{}
}
CGINCLUDE
#include "UnityCG.cginc"
//用于阈值提取高亮部分
struct v2f_threshold
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
//用于blur
struct v2f_blur
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 uv01 : TEXCOORD1;
float4 uv23 : TEXCOORD2;
float4 uv45 : TEXCOORD3;
};
//用于bloom
struct v2f_bloom
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float2 uv1 : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_TexelSize;
sampler2D _BlurTex;
float4 _BlurTex_TexelSize;
float4 _offsets;
float4 _colorThreshold;
float4 _bloomColor;
float _bloomFactor;
//高亮部分提取shader
v2f_threshold vert_threshold(appdata_img v)
{
v2f_threshold o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
//dx中纹理从左上角为初始坐标,需要反向
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv.y = 1 - o.uv.y;
#endif
return o;
}
fixed4 frag_threshold(v2f_threshold i) : SV_Target
{
fixed4 color = tex2D(_MainTex, i.uv);
//仅当color大于设置的阈值的时候才输出
return saturate(color - _colorThreshold);
}
//高斯模糊 vert shader(上一篇文章有详细注释)
v2f_blur vert_blur(appdata_img v)
{
v2f_blur o;
_offsets *= _MainTex_TexelSize.xyxy;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);
o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;
o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;
return o;
}
//高斯模糊 pixel shader(上一篇文章有详细注释)
fixed4 frag_blur(v2f_blur i) : SV_Target
{
fixed4 color = fixed4(0,0,0,0);
color += 0.40 * tex2D(_MainTex, i.uv);
color += 0.15 * tex2D(_MainTex, i.uv01.xy);
color += 0.15 * tex2D(_MainTex, i.uv01.zw);
color += 0.10 * tex2D(_MainTex, i.uv23.xy);
color += 0.10 * tex2D(_MainTex, i.uv23.zw);
color += 0.05 * tex2D(_MainTex, i.uv45.xy);
color += 0.05 * tex2D(_MainTex, i.uv45.zw);
return color;
}
//Bloom效果 vertex shader
v2f_bloom vert_bloom(appdata_img v)
{
v2f_bloom o;
//mvp矩阵变换
o.pos = UnityObjectToClipPos(v.vertex);
//uv坐标传递
o.uv.xy = v.texcoord.xy;
o.uv1.xy = o.uv.xy;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv.y = 1 - o.uv.y;
#endif
return o;
}
fixed4 frag_bloom(v2f_bloom i) : SV_Target
{
//取原始清晰图片进行uv采样
fixed4 ori = tex2D(_MainTex, i.uv1);
//取模糊普片进行uv采样
fixed4 blur = tex2D(_BlurTex, i.uv);
//输出= 原始图像,叠加bloom权值*bloom颜色*泛光颜色
fixed4 final = ori + _bloomFactor * blur * _bloomColor;
return final;
}
ENDCG
SubShader
{
//pass 0: 提取高亮部分
Pass
{
ZTest Off
Cull Off
ZWrite Off
Fog{ Mode Off }
CGPROGRAM
#pragma vertex vert_threshold
#pragma fragment frag_threshold
ENDCG
}
//pass 1: 高斯模糊
Pass
{
ZTest Off
Cull Off
ZWrite Off
Fog{ Mode Off }
CGPROGRAM
#pragma vertex vert_blur
#pragma fragment frag_blur
ENDCG
}
//pass 2: Bloom效果
Pass
{
ZTest Off
Cull Off
ZWrite Off
Fog{ Mode Off }
CGPROGRAM
#pragma vertex vert_bloom
#pragma fragment frag_bloom
ENDCG
}
}
}
下面是控制Bloom效果脚本
using System;
using UnityEngine;
using System.Collections;
public class PartBloom : MonoBehaviour
{
//采样率
public int samplerScale = 1;
//高亮部分提取阈值
public Color colorThreshold = Color.gray;
//Bloom泛光颜色
public Color bloomColor = Color.white;
//Bloom权值
[Range(0.0f, 1.0f)]
public float bloomFactor = 0.5f;
///
/// Bloom材质球
///
public Material _Material;
///
/// 特定渲染图
///
public RenderTexture m_R;
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (_Material)
{
RenderTexture temp1 = RenderTexture.GetTemporary(m_R.width, m_R.height, 0, m_R.format);
RenderTexture temp2 = RenderTexture.GetTemporary(m_R.width, m_R.height, 0, m_R.format);
//复制泛光图
Graphics.Blit(m_R, temp1);
//根据阈值提取高亮部分,使用pass0进行高亮提取
_Material.SetVector("_colorThreshold", colorThreshold);
Graphics.Blit(temp1, temp2, _Material, 0);
//高斯模糊,两次模糊,横向纵向,使用pass1进行高斯模糊
_Material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0));
Graphics.Blit(temp2, temp1, _Material, 1);
_Material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0));
Graphics.Blit(temp1, temp2, _Material, 1);
//Bloom,将模糊后的图作为Material的Blur图参数
_Material.SetTexture("_BlurTex", temp2);
_Material.SetVector("_bloomColor", bloomColor);
_Material.SetFloat("_bloomFactor", bloomFactor);
//使用pass2进行景深效果计算,清晰场景图直接从source输入到shader的_MainTex中
Graphics.Blit(source, destination, _Material, 2);
//释放申请的RT
RenderTexture.ReleaseTemporary(temp1);
RenderTexture.ReleaseTemporary(temp2);
}
}
}
1.先创建一个使用BloomEffect shader的材质球
2.把bloom控制脚本挂到mian camera上面,然后把材质球和rendertexture拖上去如下图
1RenderBloomTexture是展示渲染泛光图
2PartBloom是实现部分bloom的demo
PS:rendertexure的生成应该动态生成出来,尺寸也要根据屏幕分辨率来计算,我这里只加了几个shader,看情况把官方的shader改一下,然后规定美术用那些shader,如果替换shader麻烦那就直接写工具替换就行
链接:https://pan.baidu.com/s/1AGcAWkVMufggPsF2ZEzvEw
提取码:cvn1