unity3d 实现夜视仪效果

说起夜视仪,肯定都会想到屏幕上发绿的游戏特效

夜视仪效果经常用在FPS(第一人称射击)游戏中,

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

感觉还不错

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

1.晕影贴图

给人一种正带着夜视仪的感觉

2.噪波贴图

产生雪花状噪波

3.扫描线贴图

增加夜视仪的真实感

先建立一个shader

先浏览一下变量:

_ScanLineTileTex; 扫描线效果的贴图

噪波贴图

基于两种颜色或材质的交互创建曲面的随机扰动

通过对两种颜色随机混合,生成噪波效果

 _NoiseTex; 噪波贴图

_VignetteTex;晕影贴图

_Contrast;对比度

颜色的鲜明程度

_Brightness;亮度

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

_distortion;桶形畸变的扭曲程度

_scale;屏幕放缩比例

_ScanLineTileAmount;扫描线数量(不是确切数量,指程度大小)

_NoiseXSpeed;噪波x方向速度

_NoiseYSpeed;噪波y方向速度

_NightVisionColor;夜视仪颜色

	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}

		_Contrast("Contrast", Range(0, 4)) = 2
		_Brightness ("Brightness", Range(0, 2)) = 1
		_NightVisionColor ("Night Vision Color", Color) = (1, 1, 1, 1)
		_RandomValue ("RandomValue", Float) = 0
		_distortion("distortion", Float) = 0.2
		_scale("scale", Float) = 0.8
		_VignetteTex("Vignette Texture", 2D) = "white" {}
		_ScanLineTileTex("Scan Line Tile Texture", 2D) = "white" {}
		_ScanLineTileAmount("Scan 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
	}
	SubSha

我们还要声明一下:

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

#pragma fragment frag

片元着色函数为frag

#pragma fragmentoption ARB_precision_hint_fastest

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

#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest

镜头桶形失真校正算法,产生桶形畸变效果

将矩形物体拍摄成四边向外凸形成桶形的影像,就称镜头具有负畸变,或桶形畸变

一会需要用此对uv进行变换

传入uv值float2 coord

传出扭曲的uv值

产生了镜头的感觉,增加真实感

			float2 barrelDistortion(float2 coord)
			{
				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;
			}

然后我们开始在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了

			fixed4 frag(v2f_img i/*像素信息*/) : COLOR// 片元着色函数
			{
				half2 distortedUV = barrelDistortion(i.uv);  //桶形畸变uv
				fixed4 renderTex = tex2D(_MainTex, distortedUV);
				fixed4 vignetteTex = tex2D(_VignetteTex, distortedUV); //晕影贴图

				//扫描线uv 可控扫描线数量
				half2 scanLinesUV = half2(i.uv.x * _ScanLineTileAmount, i.uv.y * _ScanLineTileAmount);//_ScanLineTileAmount大小无限制
				fixed4 scanLineTex = tex2D(_ScanLineTileTex, scanLinesUV);
				//噪波贴图uv
				half2 noiseUV = half2(i.uv.x + (_RandomValue * _SinTime.z * _NoiseXSpeed),i.uv.y + (_Time.x * _NoiseYSpeed));
				fixed4 noiseTex = tex2D(_NoiseTex, noiseUV);

				//lum = luminosity 亮度
				fixed 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;

				return finalColor;
			}

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

建立一个c#脚本

先赋予变量,与上面的shader的变量都差不多,

这就是一会要传入shader的值

<span style="font-size:12px;">	#region Variables
	public 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 float randomValue = 0.0f;
	private Material curMaterial;
	#endregion</span>

动态建立一个纹理

<span style="font-size:12px;">	#region Properties
	Material material
	{
		get
		{
			if(curMaterial == null)
			{
				curMaterial = new Material(nightVisionShader);
				curMaterial.hideFlags = HideFlags.HideAndDontSave;
			}
			return curMaterial;
		}
	}
	#endregion</span>

依旧需要 OnRenderImage()这个函数抓取摄像机的图像

然后我们把各种变量传入shader

通过 Graphics.Blit() 这个函数

可以经过shader的变换处理在输出到我们的显示器中

<span style="font-size:12px;">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("_ScanLineTileTex", 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);
		}
	}</span>

一切ok之后,在脚本调好各种值之后

让我们来看看效果

立马FPS了的感觉= =;

以下全部代码:

c#:

<span style="font-size:12px;">using UnityEngine;
using System.Collections;

public class night : MonoBehaviour
{
	#region Variables
	public 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 float randomValue = 0.0f;
	private Material curMaterial;
	#endregion

	#region Properties
	Material material
	{
		get
		{
			if(curMaterial == null)
			{
				curMaterial = new Material(nightVisionShader);
				curMaterial.hideFlags = HideFlags.HideAndDontSave;
			}
			return curMaterial;
		}
	}
	#endregion

	void Start()
	{
		if(!SystemInfo.supportsImageEffects)
		{
			enabled = false;
			return;
		}

		if(!nightVisionShader && !nightVisionShader.isSupported)
		{
			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("_ScanLineTileTex", 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);
		}
	}

	void Update()
	{
		contrast = Mathf.Clamp(contrast, 0f,4f);
		brightness = Mathf.Clamp(brightness, 0f, 2f);
		randomValue = Random.Range(-1f,1f);
		distortion = Mathf.Clamp(distortion, -1f,1f);
		scale = Mathf.Clamp(scale, 0f, 3f);
	}

	void OnDisable()
	{
		if(curMaterial)
		{
			DestroyImmediate(curMaterial);
		}
	}
}</span>

shader:

<span style="font-size:12px;">Shader "Custom/shaderTest" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}

		_Contrast("Contrast", Range(0, 4)) = 2
		_Brightness ("Brightness", Range(0, 2)) = 1
		_NightVisionColor ("Night Vision Color", Color) = (1, 1, 1, 1)
		_RandomValue ("RandomValue", Float) = 0
		_distortion("distortion", Float) = 0.2
		_scale("scale", Float) = 0.8
		_VignetteTex("Vignette Texture", 2D) = "white" {}
		_ScanLineTileTex("Scan Line Tile Texture", 2D) = "white" {}
		_ScanLineTileAmount("Scan 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
	}
	SubShader {
		Pass {
			Tags { "RenderType"="Opaque" }
			LOD 200
				CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest//使用这个标志可以fp16的对像素进行运算
#include "UnityCG.cginc"

				uniform sampler2D _MainTex;
			uniform sampler2D _ScanLineTileTex;//扫描线效果的贴图
			//噪波贴图基于两种颜色或材质的交互创建曲面的随机扰动
			//通过对两种颜色随机混合,生成噪波效果
			uniform sampler2D _NoiseTex;//噪波贴图
			uniform sampler2D _VignetteTex;//装饰图案,小插图,此处为晕影贴图
			fixed _Contrast;//对比度
			fixed _Brightness;//亮度
			fixed _RandomValue;//随机值,用在噪波贴图随机uv扰动
			fixed _distortion;//扭曲
			fixed _scale;//屏幕比例
			fixed _ScanLineTileAmount;//扫描线数量
			fixed _NoiseXSpeed;//噪波x方向速度
			fixed _NoiseYSpeed;//噪波y方向速度
			fixed4 _NightVisionColor;//夜视镜颜色

			struct Input {
				float2 uv_MainTex;
			};
			float2 barrelDistortion(float2 coord)
			{
				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;
			}

			fixed4 frag(v2f_img i/*像素信息*/) : COLOR// 片元着色函数
			{
				half2 distortedUV = barrelDistortion(i.uv);  //桶形畸变uv
				fixed4 renderTex = tex2D(_MainTex, distortedUV);
				fixed4 vignetteTex = tex2D(_VignetteTex, distortedUV); //晕影贴图

				//扫描线uv 可控扫描线数量
				half2 scanLinesUV = half2(i.uv.x * _ScanLineTileAmount, i.uv.y * _ScanLineTileAmount);//_ScanLineTileAmount大小无限制
				fixed4 scanLineTex = tex2D(_ScanLineTileTex, scanLinesUV);
				//噪波贴图uv
				half2 noiseUV = half2(i.uv.x + (_RandomValue * _SinTime.z * _NoiseXSpeed),i.uv.y + (_Time.x * _NoiseYSpeed));
				fixed4 noiseTex = tex2D(_NoiseTex, noiseUV);

				//lum = luminosity 亮度
				fixed 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;

				return finalColor;
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}  </span>

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

时间: 2024-08-08 05:18:14

unity3d 实现夜视仪效果的相关文章

Unity3d 震屏效果

unity3d 震屏效果,将此脚本绑定到主camera上,并调用shakeCamera();即可.代码如下 using UnityEngine; using System.Collections; public class SC_shakeCamera : MonoBehaviour {   private float shakeTime = 0.0f; private float fps= 20.0f; private float frameTime =0.0f; private float 

Unity-3D 粒子光圈效果

这一次要完成的是http://i-remember.fr/en 网站所示的白色圆圈效果. 首先,我们先来看一下它的效果: 一.网站效果展示 二.创建粒子 设置相关参数 把相机背景色调黑 三.编写脚本 1.新建脚本:ParticleRotate.cs,并将其拖到Paticle System中. 2.创建粒子数组,初始化.同时我们需要为记录每个粒子的初始角度,初始半径.考虑后续可能每个粒子会有更多属性,所以写了一个class来管理粒子属性 根据下图我们知道,需要随机生成角度以及半径,从而表示出某一个

Unity3D Shader落雪效果

Shader "Custom/Snow" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _RimColor("Rim Color", Color) = (1,1,1,1) _SnowPower ("Snow Power",range(0,1)) = 0.2//边缘强度 _SnowRang("Snow Range",rang

Unity3D引擎之Shader Forge应用

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解>电子工业出版社等. CSDN视频网址:http://edu.csdn.net/lecturer/144 本篇博客给读者介绍一个材质渲染的组件-Shader Forge,在材质渲染中可以起到事半功倍的效果,对于很多开发者不熟悉材质渲染的人来说,更容易上手,在应用时首先要对号入座,下面先把

android与fragment交互,fragment显示unity3d视图。

这两天刚刚接触Unity3d,之前一直是做android开发,对于Unity3d的开发有专门的人才,我主要涉及在Unity3d与android的交互,经过两天是实验终于完成了下面的效果: 本来想写几篇博客,来详细说明下Unity3d导出android Project然后再进行二次开发的过程,后来发现几篇博客,过程和我的类似,对于重复的过程我就不写了,大家参考他的博客就可以了.而且,包括了Unity3d调用android脚本,这一块我暂时还没有涉及. Unity3D游戏开发之Unity与Andro

Unity3D游戏开发之使用disunity提取Unity3D游戏资源

各位朋友,大家好,我是秦元培.今天博主想和分享的是使用disunity提取Unity3D游戏素材.这个工具呢,博主在Unity3D游戏开发之反编译AssetBundle提取游戏资源这篇文章中其实已经提到过了,不过因为有些朋友对如何使用这个工具依然存在问题,所以博主决定特地写一篇文章来讲解如何使用disunity来提取Unity3D游戏中的素材. 准备工作 disunity:负责对Unity3D的数据文件进行解包 Unity3D:负责将导出的数据文件显示出来 Bleander或者3DsMax:负责

Unity3D 中的灯光与渲染

最近仔细研究了Unity3D中的灯光以及渲染,有了全新的认识,在这里整理记录下来.博主所使用的是Unity3D 2017.3.1f1这个版本. 一.Unity3D中的灯光 Directional Light:平行光,用来模拟太阳发射的光. Point Light:点光源,用于模拟场景中的灯和其他本地光源. Spot Light:聚光灯,通常用于人造光源,如手电筒,汽车前灯和探照灯. Area Light:区域光,只能用于烘焙中. Reflection Group:反射探针,用于准确反射周围环境.

Unity Shader-后处理:Bloom全屏泛光

一.简介 今天来学习一下Bloom效果,Bloom效果有时候也叫Glow效果,中文一般叫做"全屏泛光",这是一种可以模拟出HDR的全屏后处理效果,但是实现原理与HDR相差很远,效果比HDR差一些,但是比HDR的性能要节省很多. 二.原理介绍 这里不得不提一下传说中的HDR,从接触引擎开始,就一群大牛们经常讨论到这个词,然而作为一个新手,一直对这个传说中的技术抱着"敬畏"的态度,不过如今逐渐熟悉了一些渲染相关的东西,贱贱地,也没有那么害怕这个技术了.今天就来学习一下H

chrome提示&quot;安装unity web player&quot;

网页浏览Unity3D制作的效果时,出现提示"安装unity web player".解决办法如下: →在浏览器中输入:chrome://flags/#enable-npapi 在NPAPI中,点击"启用".在Native  Client中,点击"启用". →在浏览器中输入:chrome://restart →依然出现提示:unity failed to download data file →清除缓存再刷新,解决问题