【Unity Shaders】游戏性和画面特效

首先,还是添加一些新的Properties:Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_VignetteTex ("Vignette Texture", 2D) = "white" {}_ScanLineTex ("Scan Line Texture", 2D) = "white" {}_ScanLineTileAmount ("Scale Line Tile Amount", Float) = 4.0_NoiseTex ("Noise Texture", 2D) = "white" {}_NoiseXSpeed ("Noise X Speed", Float) = 100.0_NoiseYSpeed ("Noise Y Speed", Float) = 100.0_NightVisionColor ("Night Vision Color", Color) = (1, 1, 1, 1)_Contrast ("Contrast", Range(0, 4)) = 2_Brightness ("Brightness", Range(0, 2)) = 1_RandomValue ("Random Value", Float) = 0_Distortion ("Distortion", Float) = 0.2_Scale ("Scale (Zoom)", Float) = 0.8}块通信:SubShader {Pass {CGPROGRAM#pragma vertex vert_img#pragma fragment frag#include "UnityCG.cginc"uniform sampler2D _MainTex;uniform sampler2D _VignetteTex;uniform sampler2D _ScanLineTex;fixed _ScanLineTileAmount;uniform sampler2D _NoiseTex;fixed _NoiseXSpeed;fixed _NoiseYSpeed;fixed4 _NightVisionColor;fixed _Contrast;fixed _Brightness;fixed _RandomValue;fixed _Distortion;fixed _Scale;我们的特效还需要一个透镜变形(lens distortion)效果,来模拟从透镜中观察、图像边界由于透镜度数而发生变形的效果。在变量声明的下方添加如下代码:float2 barrelDistortion(float2 coord) {// Lens distortion algorithm// See float2 h = coord.xy – float2(0.5, 0.5);float r2 = h.x * h.x + h.y * h.y;float f = 1.0 + r2 * (_Distortion * sqrt(r2));return f * _Scale * h + 0.5;}解释:夜视效果实际和之前的老电影效果很像,都是把一些图层组合、模块化起来。最大的不同就是这里使用了一个透镜变形效果。上述算法是由SynthEyes的成员提供的,免费使用哦~第一行代码首先找到纹理的中心——float(0.5, 0.5)。一旦得到了图像中心,我们可以根据像素距离中心的远近对像素应用一个拉伸。具体分析可见本文最下方的相关链接。现在,我们到了整个Shader的关键部分。首先,在frag函数里添加如下代码来得到render texture和晕影纹理:fixed4 frag(v2f_img i) : COLOR {// Get the colors from the Render Texture and the uv’s// from the v2f_img structhalf2 distortedUV = barrelDistortion(i.uv);fixed4 renderTex = tex2D(_MainTex, distortedUV);fixed4 vignetteTex = tex2D(_VignetteTex, i.uv);解释:这三行代码很简单。在得到了变形后的UV坐标后,采样得到render texture中对应的像素,再按正常的UV得到晕影纹理的对应像素。最后,得到了底层图像像素renderTex和晕影图层的像素vignetteTex。下一步,我们需要处理扫描线和噪点纹理,通过UV坐标为它们添加合适的动画:// Process scan lines and noisehalf2 scanLinesUV = half2(i.uv.x * _ScanLineTileAmount, i.uv.y * _ScanLineTileAmount);fixed4 scanLineTex = tex2D(_ScanLineTex, scanLinesUV);half2 noiseUV = half2(i.uv.x + (_RandomValue * _SinTime.z * _NoiseXSpeed),i.uv.y + (_Time.x * _NoiseYSpeed));fixed4 noiseTex = tex2D(_NoiseTex, noiseUV);解释:这里跟之前老电影的纹理动画处理方式类似。对于扫描线纹理,之前我们说过,通过_ScanLineTileAmount可以调整画面上扫描线的宽窄和多少。_ScanLineTileAmount越大,条纹越密越细,反之越宽。对于噪点纹理,我们需要添加一个动态效果。在XY方向上处理方式稍有不同,这是为什么呢?我自己的理解是这样的。。。对于X方向,我们想要模拟的是一个小幅度的类似抖动的效果,因此用_SinTime作为因子。而对于Y方向,我们想要模拟向一个方向不断滚动的效果,因此使用_Time作为因子。最后,根据上述UV坐标可以得到扫描线纹理的像素scanLineTex和噪点纹理的像素noiseTex。最后一层图层是偏绿的颜色效果。我们仅仅需要处理render texture的光度值(Luminance),然后给它添加一个夜视颜色,,来得到最终形象的夜视效果:// Get the luminosity values from the render texture using the YIQ valuesfixed lum = dot(fixed3(0.299, 0.587, 0.114), renderTex.rgb);lum += _Brightness;fixed4 finalColor = (lum * 2) + _NightVisionColor;解释:最后一层图层是为整个画面添加绿色色调。首先也是通过YIQ得到当前的光度值lum,再加上_Brightness来调整亮度。最后,再加上_NightVisionColor(也就是绿色)。这里lum*2是为了不至于让整个画面太暗。最后,我们把所有的图层结合在一起,返回最终的像素值:// Final outputfinalColor = pow(finalColor, _Contrast);finalColor *= vignetteTex;finalColor *= scanLineTex * noiseTex;return finalColor;}

完整的脚本和Shader如下:

NightVisionEffect脚本:

using UnityEngine;using System.Collections;[ExecuteInEditMode]public class NightVisionEffect : MonoBehaviour {#region Variablespublic Shader nightVisionShader;public float contrast = 2.0f;public float brightness = 1.0f;public Color nightVisionColor = Color.white;public Texture2D vignetteTexture;public Texture2D scanLineTexture;public float scanLineTileAmount = 4.0f;public Texture2D nightVisionNoise;public float noiseXSpeed = 100.0f;public float noiseYSpeed = 100.0f;public float distortion = 0.2f;public float scale = 0.8f;private Material curMaterial;private float randomValue = 0.0f;#endregion#region Propertiespublic Material material {get {if (curMaterial == null) {curMaterial = new Material(nightVisionShader);curMaterial.hideFlags = HideFlags.HideAndDontSave;}return curMaterial;}}#endregion// Use this for initializationvoid Start () {if (SystemInfo.supportsImageEffects == false) {enabled = false;return;}if (nightVisionShader != null && nightVisionShader.isSupported == false) {enabled = false;}}void OnRenderImage (RenderTexture sourceTexture, RenderTexture destTexture){if (nightVisionShader != null) {material.SetFloat("_Contrast", contrast);material.SetFloat("_Brightness", brightness);material.SetColor("_NightVisionColor", nightVisionColor);material.SetFloat("_RandomValue", randomValue);material.SetFloat("_Distortion", distortion);material.SetFloat("_Scale", scale);if (vignetteTexture) {material.SetTexture("_VignetteTex", vignetteTexture);}if (scanLineTexture) {material.SetTexture("_ScanLineTex", scanLineTexture);material.SetFloat("_ScanLineTileAmount", scanLineTileAmount);}if (nightVisionNoise) {material.SetTexture("_NoiseTex", nightVisionNoise);material.SetFloat("_NoiseXSpeed", noiseXSpeed);material.SetFloat("_NoiseYSpeed", noiseYSpeed);}Graphics.Blit(sourceTexture, destTexture, material);} else {Graphics.Blit(sourceTexture, destTexture);}}// Update is called once per framevoid Update () {contrast = Mathf.Clamp(contrast, 0.0f, 4.0f);brightness = Mathf.Clamp(brightness, 0.0f, 2.0f);distortion = Mathf.Clamp(distortion, -1.0f, 1.0f);scale = Mathf.Clamp(scale, 0.0f, 3.0f);randomValue = Random.Range(-1.0f, 1.0f);}void OnDisable () {if (curMaterial != null) {DestroyImmediate(curMaterial);}}}NightVisionEffectShader如下:

就看你能不能战胜它。战胜了,你就是英雄,就是生活的强者。

【Unity Shaders】游戏性和画面特效

相关文章:

你感兴趣的文章:

标签云: