Unity Shader 学习笔记(25) 全局雾效
来源:互联网 发布:用php写一个简单的贴吧 编辑:程序博客网 时间:2024/06/05 05:51
Unity Shader 学习笔记(25) 全局雾效
参考书籍:《Unity Shader 入门精要》
3D数学 学习笔记(7) 视图、视锥、视场(Field of View)、裁切空间、屏幕空间
雾效(Fog)
实现方法:
- Unity内置雾效可以产生基于距离的线性或指数雾效。
- 自行编写雾效需要添加#pragma multi_compile_fog
指令,并使用相关宏。缺点是需要为所有物体添加渲染代码,实现效果有限。
- 根据深度纹理重建每个像素世界空间下位置,使用公式模拟雾效。
重建世界坐标
由世界空间下相机位置加上像素相对相机偏移量即可。 float worldPos = _WorldSpaceCameraPos + linearDepth * interpolatedRay;
- _WorldSpaceCameraPos:世界空间下相机位置,Unity内置变量。
- linearDepth:深度纹理的线性深度值。
- interpolatedRay:顶点着色器输出并插值后的射线,包含方向和距离。
interpolatedRay
实质是存了近裁切面的四个角的向量中最靠近的一个。在顶点着色器中,根据当前位置,选择对应的向量,做插值,最后传递给片元着色器得到interpolatedRay。
相关计算:aspect为宽高比。
雾的计算
颜色混合类似透明度混合:f为混合系数。 float3 afterFog = f * fogColor + (1 - f) * origColor;
雾效系数f的计算方法:z为距离(一般是点的高度)。
- 线性:f = (dmax - |z|) / (dmax - dmin)。d表示受雾影响的距离。
- 指数:f = e-d * |z|。d是控制浓度的参数。
- 指数的平方:f = e-(d - |z|)2。d是控制浓度的参数。
实现
FogWithDepthTexture类:
using UnityEngine;/// <summary>/// 雾效/// </summary>public class FogWithDepthTexture : PostEffectsBase{ private Camera targetCamera; public Camera TargetCamera { get { return targetCamera = targetCamera == null ? GetComponent<Camera>() : targetCamera; } } private Transform cameraTransform; public Transform CameraTransform { get { return cameraTransform = cameraTransform == null ? TargetCamera.transform : cameraTransform; } } [Range(0.0f, 3.0f)] public float fogDensity = 1.0f; // 雾的密度 public Color fogColor = Color.white; // 雾的颜色 public float fogStart = 0.0f; // 起始高度 public float fogEnd = 2.0f; // 终止高度 void OnEnable() { TargetCamera.depthTextureMode |= DepthTextureMode.Depth; } void OnRenderImage(RenderTexture src, RenderTexture dest) { if (TargetMaterial != null) { Matrix4x4 frustumCorners = Matrix4x4.identity; // 存近裁切平面的四个角 float fov = TargetCamera.fieldOfView; // 竖直方向视角范围(角度) float near = TargetCamera.nearClipPlane; // 近平面距离 float aspect = TargetCamera.aspect; // 宽高比 // 计算四个角对应的向量,存到frustumCorners float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad); Vector3 toRight = CameraTransform.right * halfHeight * aspect; Vector3 toTop = CameraTransform.up * halfHeight; Vector3 topLeft = CameraTransform.forward * near + toTop - toRight; float scale = topLeft.magnitude / near; topLeft.Normalize(); topLeft *= scale; ... // 同样方法计算其他三个角 frustumCorners.SetRow(0, bottomLeft); frustumCorners.SetRow(1, bottomRight); frustumCorners.SetRow(2, topRight); frustumCorners.SetRow(3, topLeft); TargetMaterial.SetMatrix("_FrustumCornersRay", frustumCorners); TargetMaterial.SetFloat("_FogDensity", fogDensity); TargetMaterial.SetColor("_FogColor", fogColor); TargetMaterial.SetFloat("_FogStart", fogStart); TargetMaterial.SetFloat("_FogEnd", fogEnd); } Graphics.Blit(src, dest, TargetMaterial); }}
Shader:
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 { ... struct v2f { float4 pos : SV_POSITION; half2 uv : TEXCOORD0; half2 uv_depth : TEXCOORD1; // 深度纹理 float4 interpolatedRay : TEXCOORD2; // 插值后的像素向量 }; v2f vert(appdata_img v) { ... // 靠近哪个角选哪个 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 o.interpolatedRay = _FrustumCornersRay[index]; return o; } fixed4 frag(v2f i) : SV_Target { // 采样然后得到视角空间的线性深度值 float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth)); float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz; // 世界空间相机相加 float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart); fogDensity = saturate(fogDensity * _FogDensity); // 限制在0~1 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 }}
- Unity Shader 学习笔记(25) 全局雾效
- Unity Shader 学习笔记(32) Unity中的Standard Shader
- Unity Shader 学习笔记(1) DrawCall
- Unity Shader 学习笔记(6) 漫反射
- Unity Shader 学习笔记(14) 阴影
- Shader学习笔记(七)Unity Shader Rim示例
- Unity Shader学习笔记(一) shader的基础结构
- Unity Shader 学习笔记(5)第一个简单Shader
- Shader学习笔记(一)认识Unity Shader,Unity Shader的基本结构
- Unity Shader 学习笔记(4)Unity Shader内置变量、函数,Shader Model
- Unity shader学习笔记 (四) 分解Shader
- Unity Shader学习笔记:简单的shader
- Unity Shader 学习笔记(28) 噪声纹理、消融效果、水波效果、噪声雾效
- UNITY SHADER学习笔记1(unity 5.6)
- UNITY SHADER学习笔记2(unity 5.6)
- Unity Shader学习笔记(五)
- Unity shader学习笔记 (二)
- Unity shader学习笔记 (三)
- Java之算法(1)
- 移动端适配
- windows 下运行QQ时,TXPlatform.exe运行报错0x0000142
- ubuntu 16.04 LTS
- Angular4 组件生命周期钩子
- Unity Shader 学习笔记(25) 全局雾效
- VMware虚拟机网络模式之桥接模式
- HDU 1711 Number Sequence(KMP)
- C++中多态总结
- CodeForce
- C. Pride (思路题目)
- (6) Hystrix熔断器实战
- 顺序图
- C#调试断点无效