第10章 Image Effect
Shader除了可以去渲染物体,还可以修改已经渲染完成的图像,常用的有GrabPass和Post-Processing
GrabPass
属于Pass,运行时抓取物体所在屏幕位置的渲染图像,传给接下来的Pass进行图像处理
定义形式
– GrabPass{},通过_GrabTexture访问抓取的图像, 但是这种会对每个物体进行一次图像抓取,性能不好
– GrabPass{“TextureName”},只会执行一次抓取,所有物体共用一张图像
Shader "Hidden/GrabPass"
{
Properties
{
_GrayScale("_GrayScale", Range(0, 1)) = 0
}
SubShader
{
Tags{
"Queue" = "Transparent"
}
GrabPass{"_ScreenTex"}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 pos:SV_POSITION;
float4 grabPos:TEXCOORD0;
};
v2f vert (float4 vertex:POSITION)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
o.grabPos = ComputeGrabScreenPos(o.pos);
return o;
}
float _GrayScale;
sampler2D _ScreenTex;
fixed4 frag (v2f i) : SV_Target
{
half4 src = tex2Dproj(_ScreenTex, i.grabPos);
half grayscale = Luminance(src.rgb);
half4 dst = half4(grayscale,grayscale,grayscale,grayscale);
return lerp(src, dst, _GrayScale);
}
ENDCG
}
}
}
Post-Processing
- 可以理解为,你拍完图片是不是用P图软件修一下图,调个色
实现逻辑:
将摄像机渲染出来的RenderImage以RenderTexture关联给Shader,处理完成后再传回给脚本2个存储区
– 摄像机渲染完图像的图像以RenderTexture形式存储在source存储区
– Shader处理完的图像以RenderTexture形式存储在destination存储区- 摄像机渲染当前帧图像存储在source,显卡调用Shader处理完图片,利用
Graphics.Blit
转移到destination,覆盖上以帧的图像,摄像机允许添加多个后处理,上一个后处理结果保存在RenderTexture传入下一个后处理的source,执行顺序就是摄像机挂载的后处理组件的顺序
- 注意:
多个后处理组件也就意味着多个RenderTexture,存在性能开销,所以可以考虑,将多个后处理合并到一个后处理Shader中处理
下面可以获得对亮度、饱和度、对比度的后处理效果
Shader "Unlit/BrightnessSaturationContrast"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Brightness("Brightness", float) = 1
_Saturation("Saturation", float) = 1
_Contrast("Contrast", float) = 1
}
SubShader
{
Cull Off
ZTest Always
ZWrite Off
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
half _Brightness;
half _Saturation;
half _Contrast;
half4 frag (v2f_img i) : SV_Target
{
half4 renderTex = tex2D(_MainTex, i.uv);
half3 finalColor = renderTex.rgb * _Brightness;
half luminance = Luminance(finalColor);
finalColor = lerp(luminance, finalColor, _Saturation);
half3 grayColor = half3(0.5,0.5,0.5);
finalColor = lerp(grayColor, finalColor, _Contrast);
return half4(finalColor, 1);
}
ENDCG
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Camera))]
[ExecuteInEditMode]
public class BrightnessSaturationContrast : MonoBehaviour
{
public Shader postProcessingShader;
public float brightness = 1;
public float saturation = 1;
public float contrast = 1;
public Material _postProcessingMat;
private void OnEnable() {
_postProcessingMat = new Material(postProcessingShader);
Debug.Log("Start");
}
private void Update() {
brightness = Mathf.Clamp(brightness, 0, 2);
saturation = Mathf.Clamp(saturation, 0, 2);
contrast = Mathf.Clamp(contrast, 0, 2);
}
private void OnRenderImage(RenderTexture src, RenderTexture dest) {
if(postProcessingShader){
_postProcessingMat.SetFloat("_Brightness", brightness);
_postProcessingMat.SetFloat("_Saturation", saturation);
_postProcessingMat.SetFloat("_Contrast", contrast);
Graphics.Blit(src, dest, _postProcessingMat);
}else{
Graphics.Blit(src, dest);
}
}
}
PostProcessing插件
- 使用的HLSL语言,不需要出现在Shader下拉框下,可以将Shader定义在Hidden下
- 最终效果和上面的一样
Shader "Hidden/BSC_HLSL"
{
HLSLINCLUDE
#include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"
TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
half _Brightness;
half _Saturation;
half _Contrast;
float4 Frag(VaryingsDefault i) : SV_Target
{
float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
color.rgb *= _Brightness;
float luminance = dot(color.rgb, float3(0.2126729, 0.7151522, 0.0721750));
color.rgb = lerp(luminance, color.rgb, _Saturation);
half3 grayColor = half3(0.5, 0.5, 0.5);
color.rgb = lerp(grayColor, color.rgb, _Contrast);
return color;
}
ENDHLSL
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex VertDefault
#pragma fragment Frag
ENDHLSL
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;
[System.Serializable]
[PostProcess(typeof(BSCRenderer), PostProcessEvent.AfterStack, "Custom/BSC")]
public class BSC : PostProcessEffectSettings{
[Range(0f, 2f), Tooltip("Brightness effect intensity.")]
public FloatParameter Brightness = new FloatParameter { value = 1f };
[Range(0f, 2f), Tooltip("Saturation effect intensity.")]
public FloatParameter Saturation = new FloatParameter { value = 1f };
[Range(0f, 2f), Tooltip("Contrast effect intensity.")]
public FloatParameter Contrast = new FloatParameter { value = 1f };
}
public class BSCRenderer:PostProcessEffectRenderer<BSC>
{
public override void Render(PostProcessRenderContext context)
{
PropertySheet sheet = context.propertySheets.Get(Shader.Find("Hidden/BSC_HLSL"));
sheet.properties.SetFloat("_Brightness", settings.Brightness);
sheet.properties.SetFloat("_Saturation", settings.Saturation);
sheet.properties.SetFloat("_Contrast", settings.Contrast);
context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
}
}