雾效公式有好几种,看课本按需求选吧,这里用的线性的。
CS:
需要定义的参数 fogDensity雾的浓度 fogColor雾的颜色 fogStart雾的起始高度 fogEnd雾的终止高度
Shader中要对fogStart和fogEnd进行处理,让end - start 不小于0
设置一个4x4矩阵存储 TL TR BT BL 四个向量传到顶点着色器中让顶点着色器做判断
传参到材质,传相机当前的视角 * 投影矩阵和上面的4x4矩阵
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class wuxiaoCS : PostEffectsBase
{
private Material wuxiaoMaterial = null;
public Shader wuxiaoShader;
public Material material
{
get
{
wuxiaoMaterial = CheckShaderAndCreateMaterial(wuxiaoShader, wuxiaoMaterial);
return wuxiaoMaterial;
}
}
private Camera myCamera;
public Camera camera
{
get
{
if(myCamera == null)
{
myCamera = GetComponent<Camera>();
}
return myCamera;
}
}
private Transform myCameraTransform;
public Transform cameraTransform
{
get
{
if(myCameraTransform == null)
{
myCameraTransform = camera.transform;
}
return myCameraTransform;
}
}
//需要定义的参数
[Range(0.0f, 3.0f)]
public float fogDensity = 1.0f;
public Color fogColor = Color.white;
public float fogEnd = 2.0f;
public float fogStart = 0f;
private void OnEnable()
{
camera.depthTextureMode |= DepthTextureMode.Depth;
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if(material != null)
{
//返回单位矩阵
Matrix4x4 frustumCorners = Matrix4x4.identity;
float fov = camera.fieldOfView;
float near = camera.nearClipPlane;
float far = camera.farClipPlane;
float aspect = camera.aspect;
//aspect = 长/宽;
float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
Vector3 toRight = cameraTransform.right * halfHeight * aspect;
Vector3 toTop = cameraTransform.up * halfHeight;
Vector3 topRight = cameraTransform.forward * near + toTop + toRight;
float scale = topRight.magnitude / near;
topRight.Normalize();
topRight *= scale;
Vector3 topLeft = cameraTransform.forward * near + toTop + toRight;
topLeft.Normalize();
topLeft *= scale;
Vector3 bottomRight = cameraTransform.forward * near - toTop + toRight;
bottomRight.Normalize();
bottomRight *= scale;
Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
bottomLeft.Normalize();
bottomLeft *= scale;
frustumCorners.SetRow(0, bottomLeft);
frustumCorners.SetRow(1, bottomRight);
frustumCorners.SetRow(2, topRight);
frustumCorners.SetRow(3, topLeft);
material.SetMatrix("_FrustumCornersRay", frustumCorners);
material.SetMatrix("_ViewProjectionInverseMatrix", (camera.previousViewProjectionMatrix * camera.worldToCameraMatrix).inverse);
material.SetFloat("_FogDensity", fogDensity);
material.SetColor("_FogColor", fogColor);
material.SetFloat("_FogEnd", fogEnd);
material.SetFloat("_FogStart", fogStart);
Graphics.Blit(source, destination, material);
}
else
{
Graphics.Blit(source, destination);
}
}
}
shader:
_MainTex_TexelSize.y < 0
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unity Shaders Book/Chapter 13/Fog With Depth Texture" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_FogDensity ("Fog Density", Float) = 1.0
_FogColor ("Fog Color", Color) = (1, 1, 1, 1)
_FogStart ("Fog Start", Float) = 0.0
_FogEnd ("Fog End", Float) = 1.0
}
SubShader {
CGINCLUDE
#include "UnityCG.cginc"
float4x4 _FrustumCornersRay;
sampler2D _MainTex;
half4 _MainTex_TexelSize;
sampler2D _CameraDepthTexture;
half _FogDensity;
fixed4 _FogColor;
float _FogStart;
float _FogEnd;
struct v2f {
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
half2 uv_depth : TEXCOORD1;
//插值后的像素向量
float4 interpolatedRay : TEXCOORD2;
};
v2f vert(appdata_img v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.uv_depth = v.texcoord;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv_depth.y = 1 - o.uv_depth.y;
#endif
//判别顶点处于哪个分区
//顶点着色器里的值被传入片元着色器时会被进行一次插值计算
//所以只需要算出四个顶点
int index = 0;
if (v.texcoord.x < 0.5 && v.texcoord.y < 0.5) {
index = 0;
} else if (v.texcoord.x > 0.5 && v.texcoord.y < 0.5) {
index = 1;
} else if (v.texcoord.x > 0.5 && v.texcoord.y > 0.5) {
index = 2;
} else {
index = 3;
}
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
index = 3 - index;
#endif
//经插值后得到interpolatedRay传递给片元着色器
o.interpolatedRay = _FrustumCornersRay[index];
return o;
}
fixed4 frag(v2f i) : SV_Target {
//LinearEyeDepth 把深度纹理的采样结果转换到视角空间下的深度值
//Linear01Depth则返回一个范围在[0,1]的线性深度值
float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
//世界坐标计算 = 摄像机坐标 + linearDepth * 深度值
float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;
//雾效公式,(高度雾,参数是y
//这种写法如果y值越低,雾越浓,即便是y值超过了起始点
float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart);
//在后面再乘一个值把上面的影响消掉,但注意,雾的起始高度要足够低,
//否则会影响fog的值
fogDensity = saturate(fogDensity * _FogDensity);
fixed4 finalColor = tex2D(_MainTex, i.uv);
//根据雾效程度进行颜色插值混合
finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
return finalColor;
}
ENDCG
Pass {
ZTest Always Cull Off ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
FallBack Off
}
UnityShader中从顶点着色器到片元着色器的插值变换_顶点着色器 片元着色器 差值_达也酱的博客-CSDN博客
屏幕效果,同一深度要处理的点就四个,其余的像素进行插值
解疑答惑了这里
顶点着色器中定义uv坐标作为颜色输出,因为只有四个点,所以插值结果如下
代码效果: