当前位置:   article > 正文

unity3d 实现夜视仪效果_unity night vision effset

unity night vision effset
说起夜视仪,肯定都会想到屏幕上发绿的游戏特效
夜视仪效果经常用在FPS(第一人称射击)游戏中,


先来看下我们的实现效果:




感觉还不错



本次shader需要用到三种贴图:

1.晕影贴图
给人一种正带着夜视仪的感觉



2.噪波贴图
产生雪花状噪波



3.扫描线贴图
增加夜视仪的真实感





先建立一个shader
先浏览一下变量:

_ScanLineTileTex; 扫描线效果的贴图

   
噪波贴图
基于两种颜色或材质的交互创建曲面的随机扰动
    
通过对两种颜色随机混合,生成噪波效果
        
 _NoiseTex; 噪波贴图
   
        
_VignetteTex;晕影贴图
   

_Contrast;对比度
  颜色的鲜明程度

        
_Brightness;亮度

            
_RandomValue;随机值,用在噪波贴图随机uv扰动
   

_distortion;桶形畸变的扭曲程度

        
_scale;屏幕放缩比例
   
        
_ScanLineTileAmount;扫描线数量(不是确切数量,指程度大小)
   


_NoiseXSpeed;噪波x方向速度
_NoiseYSpeed;噪波y方向速度
   
    
_NightVisionColor;夜视仪颜色


  1. Properties {
  2. _MainTex ("Base (RGB)", 2D) = "white" {}
  3. _Contrast("Contrast", Range(0, 4)) = 2
  4. _Brightness ("Brightness", Range(0, 2)) = 1
  5. _NightVisionColor ("Night Vision Color", Color) = (1, 1, 1, 1)
  6. _RandomValue ("RandomValue", Float) = 0
  7. _distortion("distortion", Float) = 0.2
  8. _scale("scale", Float) = 0.8
  9. _VignetteTex("Vignette Texture", 2D) = "white" {}
  10. _ScanLineTileTex("Scan Line Tile Texture", 2D) = "white" {}
  11. _ScanLineTileAmount("Scan Line Tile Amount", Float) = 4.0
  12. _NoiseTex("Noise Texture", 2D) = "white" {}
  13. _NoiseXSpeed("Noise X Speed", Float) = 100.0
  14. _NoiseYSpeed("Noise Y Speed", Float) = 100.0
  15. }
  16. SubSha


我们还要声明一下:

#pragma vertex vert_img    传入的像素信息为vert_img


#pragma fragment frag
    片元着色函数为frag


#pragma fragmentoption ARB_precision_hint_fastest 

片元着色选项。ARB_precision_hint_fastest使用这个标志可以fp16的对像素进行运算,加快渲染


  1. #pragma vertex vert_img
  2. #pragma fragment frag
  3. #pragma fragmentoption ARB_precision_hint_fastest




镜头桶形失真校正算法,产生桶形畸变效果
将矩形物体拍摄成四边向外凸形成桶形的影像,就称镜头具有负畸变,或桶形畸变

一会需要用此对uv进行变换
传入uv值float2 coord
传出扭曲的uv值
产生了镜头的感觉,增加真实感


  1. float2 barrelDistortion(float2 coord)
  2. {
  3. float2 h = coord.xy - float2(0.5, 0.5);
  4. float r2 = h.x * h.x + h.y * h.y;
  5. float f = 1.0 + r2 * (_distortion * sqrt(r2));
  6. return f * _scale * h + 0.5;
  7. }



然后我们开始在frag函数中对片元进行着色

从刚才的桶形畸变函数传出经过处理得uv值distortedUV
获得当前传入摄像头的像素信息renderTex

获取晕影贴图像素信息
vignetteTex = tex2D(_VignetteTex, distortedUV);    
    
        
扫描线uv 可控扫描线数量
        
scanLinesUV = half2(i.uv.x * _ScanLineTileAmount, i.uv.y * _ScanLineTileAmount);
获取扫描线贴图像素信息
scanLineTex = tex2D(_ScanLineTileTex, scanLinesUV);



噪波贴图uv
根据时间与随机值变换uv产生扰动效果
noiseUV = half2(i.uv.x + (_RandomValue * _SinTime.z * _NoiseXSpeed),i.uv.y + (_Time.x * _NoiseYSpeed));
获取噪波贴图像素信息
fixed4 noiseTex = tex2D(_NoiseTex, noiseUV);


lum 即 luminosity 亮度值
lum = dot (fixed3(0.299, 0.587, 0.114), renderTex.rgb);
lum += _Brightness;//加上可自控的亮度
使饱和度调为零,变成黑白效果,再与夜视镜颜色混合
fixed4 finalColor = (lum *2) + _NightVisionColor;


再与三种贴图颜色混合得到最终颜色值
finalColor = pow(finalColor, _Contrast);
finalColor *= vignetteTex;
finalColor *= scanLineTex * noiseTex;



shader就ok了


  1. fixed4 frag(v2f_img i/*像素信息*/) : COLOR// 片元着色函数
  2. {
  3. half2 distortedUV = barrelDistortion(i.uv); //桶形畸变uv
  4. fixed4 renderTex = tex2D(_MainTex, distortedUV);
  5. fixed4 vignetteTex = tex2D(_VignetteTex, distortedUV); //晕影贴图
  6. //扫描线uv 可控扫描线数量
  7. half2 scanLinesUV = half2(i.uv.x * _ScanLineTileAmount, i.uv.y * _ScanLineTileAmount);//_ScanLineTileAmount大小无限制
  8. fixed4 scanLineTex = tex2D(_ScanLineTileTex, scanLinesUV);
  9. //噪波贴图uv
  10. half2 noiseUV = half2(i.uv.x + (_RandomValue * _SinTime.z * _NoiseXSpeed),i.uv.y + (_Time.x * _NoiseYSpeed));
  11. fixed4 noiseTex = tex2D(_NoiseTex, noiseUV);
  12. //lum = luminosity 亮度
  13. fixed lum = dot (fixed3(0.299, 0.587, 0.114), renderTex.rgb);
  14. lum += _Brightness;//加上可自控的亮度
  15. //饱和度调为零,变成黑白效果,再与夜视镜颜色混合
  16. fixed4 finalColor = (lum *2) + _NightVisionColor;//
  17. finalColor = pow(finalColor, _Contrast);//对比度
  18. finalColor *= vignetteTex;//与晕影贴图混合
  19. finalColor *= scanLineTex * noiseTex;
  20. return finalColor;
  21. }




接下来看看放入摄像头中的c#脚本



建立一个c#脚本


先赋予变量,与上面的shader的变量都差不多,
这就是一会要传入shader的值


  1. <span style="font-size:12px;"> #region Variables
  2. public Shader nightVisionShader;
  3. public float contrast = 2.0f;
  4. public float brightness = 1.0f;
  5. public Color nightVisionColor = Color.white;
  6. public Texture2D vignetteTexture;
  7. public Texture2D scanLineTexture;
  8. public float scanLineTileAmount = 4.0f;
  9. public Texture2D nightVisionNoise;
  10. public float noiseXSpeed = 100.0f;
  11. public float noiseYSpeed = 100.0f;
  12. public float distortion = 0.2f;
  13. public float scale = 0.8f;
  14. private float randomValue = 0.0f;
  15. private Material curMaterial;
  16. #endregion</span>


动态建立一个纹理

  1. <span style="font-size:12px;"> #region Properties
  2. Material material
  3. {
  4. get
  5. {
  6. if(curMaterial == null)
  7. {
  8. curMaterial = new Material(nightVisionShader);
  9. curMaterial.hideFlags = HideFlags.HideAndDontSave;
  10. }
  11. return curMaterial;
  12. }
  13. }
  14. #endregion</span>

依旧需要 OnRenderImage()这个函数抓取摄像机的图像
然后我们把各种变量传入shader
通过 Graphics.Blit() 这个函数
可以经过shader的变换处理在输出到我们的显示器中



  1. <span style="font-size:12px;">void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
  2. {
  3. if(nightVisionShader != null)
  4. {
  5. material.SetFloat("_Contrast", contrast);
  6. material.SetFloat("_Brightness", brightness);
  7. material.SetColor("_NightVisionColor", nightVisionColor);
  8. material.SetFloat("_RandomValue", randomValue);
  9. material.SetFloat("_distortion", distortion);
  10. material.SetFloat("_scale",scale);
  11. if(vignetteTexture)
  12. {
  13. material.SetTexture("_VignetteTex", vignetteTexture);
  14. }
  15. if(scanLineTexture)
  16. {
  17. material.SetTexture("_ScanLineTileTex", scanLineTexture);
  18. material.SetFloat("_ScanLineTileAmount", scanLineTileAmount);
  19. }
  20. if(nightVisionNoise)
  21. {
  22. material.SetTexture("_NoiseTex", nightVisionNoise);
  23. material.SetFloat("_NoiseXSpeed", noiseXSpeed);
  24. material.SetFloat("_NoiseYSpeed", noiseYSpeed);
  25. }
  26. Graphics.Blit(sourceTexture, destTexture, material);
  27. }
  28. else
  29. {
  30. Graphics.Blit(sourceTexture, destTexture);
  31. }
  32. }</span>

一切ok之后,在脚本调好各种值之后
让我们来看看效果



立马FPS了的感觉= =;




以下全部代码

c#:


  1. <span style="font-size:12px;">using UnityEngine;
  2. using System.Collections;
  3. public class night : MonoBehaviour
  4. {
  5. #region Variables
  6. public Shader nightVisionShader;
  7. public float contrast = 2.0f;
  8. public float brightness = 1.0f;
  9. public Color nightVisionColor = Color.white;
  10. public Texture2D vignetteTexture;
  11. public Texture2D scanLineTexture;
  12. public float scanLineTileAmount = 4.0f;
  13. public Texture2D nightVisionNoise;
  14. public float noiseXSpeed = 100.0f;
  15. public float noiseYSpeed = 100.0f;
  16. public float distortion = 0.2f;
  17. public float scale = 0.8f;
  18. private float randomValue = 0.0f;
  19. private Material curMaterial;
  20. #endregion
  21. #region Properties
  22. Material material
  23. {
  24. get
  25. {
  26. if(curMaterial == null)
  27. {
  28. curMaterial = new Material(nightVisionShader);
  29. curMaterial.hideFlags = HideFlags.HideAndDontSave;
  30. }
  31. return curMaterial;
  32. }
  33. }
  34. #endregion
  35. void Start()
  36. {
  37. if(!SystemInfo.supportsImageEffects)
  38. {
  39. enabled = false;
  40. return;
  41. }
  42. if(!nightVisionShader && !nightVisionShader.isSupported)
  43. {
  44. enabled = false;
  45. }
  46. }
  47. void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
  48. {
  49. if(nightVisionShader != null)
  50. {
  51. material.SetFloat("_Contrast", contrast);
  52. material.SetFloat("_Brightness", brightness);
  53. material.SetColor("_NightVisionColor", nightVisionColor);
  54. material.SetFloat("_RandomValue", randomValue);
  55. material.SetFloat("_distortion", distortion);
  56. material.SetFloat("_scale",scale);
  57. if(vignetteTexture)
  58. {
  59. material.SetTexture("_VignetteTex", vignetteTexture);
  60. }
  61. if(scanLineTexture)
  62. {
  63. material.SetTexture("_ScanLineTileTex", scanLineTexture);
  64. material.SetFloat("_ScanLineTileAmount", scanLineTileAmount);
  65. }
  66. if(nightVisionNoise)
  67. {
  68. material.SetTexture("_NoiseTex", nightVisionNoise);
  69. material.SetFloat("_NoiseXSpeed", noiseXSpeed);
  70. material.SetFloat("_NoiseYSpeed", noiseYSpeed);
  71. }
  72. Graphics.Blit(sourceTexture, destTexture, material);
  73. }
  74. else
  75. {
  76. Graphics.Blit(sourceTexture, destTexture);
  77. }
  78. }
  79. void Update()
  80. {
  81. contrast = Mathf.Clamp(contrast, 0f,4f);
  82. brightness = Mathf.Clamp(brightness, 0f, 2f);
  83. randomValue = Random.Range(-1f,1f);
  84. distortion = Mathf.Clamp(distortion, -1f,1f);
  85. scale = Mathf.Clamp(scale, 0f, 3f);
  86. }
  87. void OnDisable()
  88. {
  89. if(curMaterial)
  90. {
  91. DestroyImmediate(curMaterial);
  92. }
  93. }
  94. }</span>
shader:

  1. <span style="font-size:12px;">Shader "Custom/shaderTest" {
  2. Properties {
  3. _MainTex ("Base (RGB)", 2D) = "white" {}
  4. _Contrast("Contrast", Range(0, 4)) = 2
  5. _Brightness ("Brightness", Range(0, 2)) = 1
  6. _NightVisionColor ("Night Vision Color", Color) = (1, 1, 1, 1)
  7. _RandomValue ("RandomValue", Float) = 0
  8. _distortion("distortion", Float) = 0.2
  9. _scale("scale", Float) = 0.8
  10. _VignetteTex("Vignette Texture", 2D) = "white" {}
  11. _ScanLineTileTex("Scan Line Tile Texture", 2D) = "white" {}
  12. _ScanLineTileAmount("Scan Line Tile Amount", Float) = 4.0
  13. _NoiseTex("Noise Texture", 2D) = "white" {}
  14. _NoiseXSpeed("Noise X Speed", Float) = 100.0
  15. _NoiseYSpeed("Noise Y Speed", Float) = 100.0
  16. }
  17. SubShader {
  18. Pass {
  19. Tags { "RenderType"="Opaque" }
  20. LOD 200
  21. CGPROGRAM
  22. #pragma vertex vert_img
  23. #pragma fragment frag
  24. #pragma fragmentoption ARB_precision_hint_fastest//使用这个标志可以fp16的对像素进行运算
  25. #include "UnityCG.cginc"
  26. uniform sampler2D _MainTex;
  27. uniform sampler2D _ScanLineTileTex;//扫描线效果的贴图
  28. //噪波贴图基于两种颜色或材质的交互创建曲面的随机扰动
  29. //通过对两种颜色随机混合,生成噪波效果
  30. uniform sampler2D _NoiseTex;//噪波贴图
  31. uniform sampler2D _VignetteTex;//装饰图案,小插图,此处为晕影贴图
  32. fixed _Contrast;//对比度
  33. fixed _Brightness;//亮度
  34. fixed _RandomValue;//随机值,用在噪波贴图随机uv扰动
  35. fixed _distortion;//扭曲
  36. fixed _scale;//屏幕比例
  37. fixed _ScanLineTileAmount;//扫描线数量
  38. fixed _NoiseXSpeed;//噪波x方向速度
  39. fixed _NoiseYSpeed;//噪波y方向速度
  40. fixed4 _NightVisionColor;//夜视镜颜色
  41. struct Input {
  42. float2 uv_MainTex;
  43. };
  44. float2 barrelDistortion(float2 coord)
  45. {
  46. float2 h = coord.xy - float2(0.5, 0.5);
  47. float r2 = h.x * h.x + h.y * h.y;
  48. float f = 1.0 + r2 * (_distortion * sqrt(r2));
  49. return f * _scale * h + 0.5;
  50. }
  51. fixed4 frag(v2f_img i/*像素信息*/) : COLOR// 片元着色函数
  52. {
  53. half2 distortedUV = barrelDistortion(i.uv); //桶形畸变uv
  54. fixed4 renderTex = tex2D(_MainTex, distortedUV);
  55. fixed4 vignetteTex = tex2D(_VignetteTex, distortedUV); //晕影贴图
  56. //扫描线uv 可控扫描线数量
  57. half2 scanLinesUV = half2(i.uv.x * _ScanLineTileAmount, i.uv.y * _ScanLineTileAmount);//_ScanLineTileAmount大小无限制
  58. fixed4 scanLineTex = tex2D(_ScanLineTileTex, scanLinesUV);
  59. //噪波贴图uv
  60. half2 noiseUV = half2(i.uv.x + (_RandomValue * _SinTime.z * _NoiseXSpeed),i.uv.y + (_Time.x * _NoiseYSpeed));
  61. fixed4 noiseTex = tex2D(_NoiseTex, noiseUV);
  62. //lum = luminosity 亮度
  63. fixed lum = dot (fixed3(0.299, 0.587, 0.114), renderTex.rgb);
  64. lum += _Brightness;//加上可自控的亮度
  65. //饱和度调为零,变成黑白效果,再与夜视镜颜色混合
  66. fixed4 finalColor = (lum *2) + _NightVisionColor;//
  67. finalColor = pow(finalColor, _Contrast);//对比度
  68. finalColor *= vignetteTex;//与晕影贴图混合
  69. finalColor *= scanLineTex * noiseTex;
  70. return finalColor;
  71. }
  72. ENDCG
  73. }
  74. }
  75. FallBack "Diffuse"
  76. } </span>




                                                                                                                                               ------------- by wolf96






声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/597843
推荐阅读
相关标签
  

闽ICP备14008679号