Descripción general del posprocesamiento de la pantalla de Unity





Postprocesamiento


proceso

1. Agregue un script de posprocesamiento a la cámara, este script apunta a un material, y el sombreador que lleva el material es el sombreador de posprocesamiento
(muy bien, lo adivinó. El script de posprocesamiento es para la cámara) (el material se trae para que el material se pueda llevar Textura, el sombreador en sí no se lleva)
2. Escritura de sombreado


guión

1) Comprobación de viabilidad

Antes de cada posprocesamiento, verifique si se cumplen una serie de condiciones, como si la plataforma actual admite el uso de renderizado de texturas y efectos de pantalla, si admite el sombreador actual, etc. (al igual que el subshader, se debe considerar la compatibilidad de la plataforma )

Se han escrito varias funciones para verificar, como se muestra a continuación (en realidad, importe el siguiente código en Activos).Al
escribir el script de posprocesamiento, la parte de verificación de factibilidad puede llamar a la clase base
(este script no se comprende bien por el momento). ) , lea con más atención en el futuro y tome más notas)

La función de inicio se usa para hacer algunas comprobaciones por adelantado. Cuando algunos efectos necesitan más comprobaciones y configuraciones, puede sobrecargar (funciones con el mismo nombre) funciones de inicio, CheckSupport, CheckResources, etc.

using UnityEngine;
using System.Collections;

[ExecuteInEditMode] //编辑器状态下也可以执行脚本来查看效果
[RequireComponent (typeof(Camera))] //需要相机组件

//继承自基类 MonoBehaviour
public class PostEffectsBase : MonoBehaviour {
    
    	
	//函数
	// CheckResources函数用来检查各种资源和条件是否满足(为了提前检查,放在Start函数中)
	protected void CheckResources() {
    
    
		bool isSupported = CheckSupport(); //这个函数调用在下面
		
		if (isSupported == false) {
    
    
			NotSupported(); //也在下面
		}
	}
	
	//检查是否支持屏幕特效(image effects)和渲染纹理  
	protected bool CheckSupport() {
    
    
 
		
		if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false)
		//上面这两个语句显然就是真正作用部分
		 {
    
    
			Debug.LogWarning("This platform does not support image effects or render textures.");
			return false;
		}
		
		return true;
	}

	// 平台不支持时执行,但是这是什么意思?不执行此脚本吗?
	protected void NotSupported() {
    
    
		enabled = false;
	}
	
	// Called when start,main entrance
	protected void Start() {
    
    
		CheckResources();
	}

	//后处理不能光一个shade,r一定要有一个材质
	//最终效果为:没shader和shader不支持的,返回null
	//shader支持的,有材质的返回材质,没有的创建材质返回材质
	protected Material CheckShader_CreateMat(Shader shader, Material material) //接收参数 需要使用的shader,附带的材质
	{
    
    
		if (shader == null) //先检查有没有shader
		{
    
    
			return null;
		}
		
		if (shader.isSupported && material && material.shader == shader) //若支持该shader&&材质存在&&材质附带的shader为参数中的shader(就是摄像机面板里的shader)(有时候材质附带的shader带错了)
			return material;
		
		if (!shader.isSupported) {
    
    
			return null;
		}
		
		else  //即 shader支持,材质不存在/材质携带错误
		//虽然看不懂这里的语句,但是我知道这里的作用:创建临时材质并返回携带shader的材质
		{
    
    
			material = new Material(shader); //不懂
			material.hideFlags = HideFlags.DontSave; //不懂 DontSave很明显就是临时
			if (material)
				return material;
			else 
				return null;
		}
	}
}



2) Use la función OnRenderImage para obtener la textura de renderizado de la pantalla actual

La interfaz de posprocesamiento proporcionada por Unity es la función OnRenderImage , que se declara de la siguiente manera:

MonoBehaviour.OnRenderImage(RenderTexture src, RenderTextre dest)

//参数1表示源渲染纹理source, 参数2表示目标渲染纹理destination
//也就是这个函数接受src纹理,进行后处理后,输出为dest纹理
  • La función OnRenderImage se ejecutará después de que se ejecuten los sombreadores de todos los objetos (después de todo, es un procesamiento posterior )
  • Sin embargo, si necesita realizar un procesamiento posterior de la pantalla en el medio (como antes del pase transparente), puede agregar el atributo ImageEffectQpaque antes de la función OnRenderImage .
  • Si hay un bucle dentro de OnRenderImage , no se puede acceder a la textura de representación creada dentro del bucle fuera del bucle


3) Shader de procesamiento posterior llamando a Graphics.Blit

En la función OnRenderImage, usaremos la función Graphics.Blit para completar el procesamiento de la textura src, que se declara como una de las siguientes

Tenga en cuenta que aquí se crean directamente dos texturas y no es necesario crearlas por separado.
Tenga en cuenta que la declaración de la función se ejecuta inmediatamente.

public static void Blit(RenderTexture src, RenderTextre dest); //缺失材质,会直接传递,不会执行pass
public static void Blit(RenderTexture src, RenderTextre dest, Material mat, int pass = -1); //pass值默认-1吧?
public static void Blit(RenderTexture src,  Material mat, int pass = -1);

//参数Material mat 为材质,并不是所有的后处理都需要材质
//src会被传递给_MainTex,也就是shader中的MainTex就是渲染纹理
//int pass = -1 表示遍历后处理shader的所有Pass,若为其他索引值,则仅执行一个Pass(应该是调试用的)

Cuando el procesamiento posterior es complejo y diverso, puede ser necesario llamar a Graphics.Blit varias veces



Shader de posprocesamiento

Cabe señalar que el sombreador de posprocesamiento no necesita la estructura de datos de los datos de la aplicación
, pero el sombreador de vértices aún necesita que se pasen datos, y el posprocesamiento no necesita procesar vértices, por lo que la mayoría del sombreador de posprocesamiento los sombreadores de vértices son los siguientes:

v2f vert(appdata_img v) {
    
    
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);	
				o.uv = v.texcoord;
				return o;
			}

Si se requiere convolución, se requieren pasos adicionales:

 v2f vert (appdata_img v)
            {
    
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                half2 uv = v.texcoord;

                o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1,-1);
                o.uv[1] = uv + _MainTex_TexelSize.xy * half2( 0,-1);
                o.uv[2] = uv + _MainTex_TexelSize.xy * half2( 1,-1);
                o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1, 0);
                o.uv[4] = uv + _MainTex_TexelSize.xy * half2( 0, 0);
                o.uv[5] = uv + _MainTex_TexelSize.xy * half2( 1, 0);
                o.uv[6] = uv + _MainTex_TexelSize.xy * half2(-1, 1);
                o.uv[7] = uv + _MainTex_TexelSize.xy * half2( 0, 1);
                o.uv[8] = uv + _MainTex_TexelSize.xy * half2( 1, 1);

                return o;
            }





Ejemplo simple: ajuste el brillo, la saturación y el contraste de la pantalla



secuencia de comandos de la cámara web

using UnityEngine;
using System.Collections;

//这里冒号前的名称应与脚本名保持一致
//继承了上述检测脚本
public class B_S_C : PostEffectsBase {
    
    
	
	//shader和Mat的声明
	public Shader B_S_C_Shader;
	private Material B_S_C_Mat;
	
	public Material material {
    
      
		get {
    
    
			//这里用到的函数在 PostEffectsBase 里,进行可行性检验
			B_S_C_Mat = CheckShader_CreateMat(B_S_C_Shader, B_S_C_Mat);
			return B_S_C_Mat;
		}  
	}

	//这里的部分会显示到脚本面板中
	[Range(0.0f, 3.0f)]
	public float brightness = 1.0f;
	[Range(0.0f, 3.0f)]
	public float saturation = 1.0f;
	[Range(0.0f, 3.0f)]
	public float contrast = 1.0f;

	//还记得这个函数是干嘛的吗?
	void OnRenderImage(RenderTexture src, RenderTexture dest) {
    
    
		if (material != null) {
    
    
			//虽然这里是Mat的函数,但是其会直接作用到shader中的变量,与mat面板上的参数无关
			//所以其实在后处理shader中我们并不需要写properties,但Tex要写
			material.SetFloat("_Brightness", brightness);
			material.SetFloat("_Saturation", saturation);
			material.SetFloat("_Contrast", contrast);
			
			//这个记得吗?上面是改参,这一句是执行
			Graphics.Blit(src, dest, material);
		} 
		
		//没有材质就不进行处理了,说明前面出错了,我觉得debug一下会更好?
		else {
    
    
			Graphics.Blit(src, dest);
		}
	}
}



Sombreador

Shader "Unity Shaders Book/Chapter 12/Brightness Saturation And Contrast" {
    
    
	Properties 
	{
    
    
		_MainTex ("Base (RGB)", 2D) = "white" {
    
    } //MainTex不能省略
		//_Brightness ("Brightness", Float) = 1
		//_Saturation("Saturation", Float) = 1
		//_Contrast("Contrast", Float) = 1
	}
	SubShader 
	{
    
    
		Pass 
		{
    
      
			//这些设定是为了不让渲染纹理后面的对象干扰
			ZTest Always 
			Cull Off 
			ZWrite Off
			
			CGPROGRAM  
			#pragma vertex vert  
			#pragma fragment frag  
			  
			#include "UnityCG.cginc"  
			  
			sampler2D _MainTex;  
			half _Brightness;
			half _Saturation;
			half _Contrast;
			  
			struct v2f {
    
    
				float4 pos : SV_POSITION;
				half2 uv: TEXCOORD0;
			};
			  
			v2f vert(appdata_img v) {
    
    
				v2f o;
				
				o.pos = UnityObjectToClipPos(v.vertex);	
				o.uv = v.texcoord;
						 
				return o;
			}
		
			fixed4 frag(v2f i) : SV_Target {
    
    
				fixed4 renderTex = tex2D(_MainTex, i.uv);  
				  
				// 明度
				fixed3 finalColor = renderTex.rgb * _Brightness;
				
				// 饱和度,注意饱和度是怎么算的
				fixed luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
				fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
				finalColor = lerp(luminanceColor, finalColor, _Saturation);
				
				// 对比度
				fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
				finalColor = lerp(avgColor, finalColor, _Contrast);
				
				return fixed4(finalColor, renderTex.a);  
			}  
			  
			ENDCG
		}  
	}
	
	Fallback Off
}


Supongo que te gusta

Origin blog.csdn.net/dogman_/article/details/129638557
Recomendado
Clasificación