Files
UltimateFishing2020/Assets/Scripts/Assembly-CSharp/VolumetricLightRenderer.cs
2026-03-04 10:03:45 +08:00

591 lines
17 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR;
[RequireComponent(typeof(Camera))]
public class VolumetricLightRenderer : MonoBehaviour
{
public enum VolumtericResolution
{
Full = 0,
Half = 1,
Quarter = 2
}
private static Mesh _pointLightMesh;
private static Mesh _spotLightMesh;
private static Material _lightMaterial;
private Camera _camera;
private CommandBuffer _preLightPass;
private Matrix4x4 _viewProj;
private Material _blitAddMaterial;
private Material _bilateralBlurMaterial;
private RenderTexture _volumeLightTexture;
private RenderTexture _halfVolumeLightTexture;
private RenderTexture _quarterVolumeLightTexture;
private static Texture _defaultSpotCookie;
private RenderTexture _halfDepthBuffer;
private RenderTexture _quarterDepthBuffer;
private VolumtericResolution _currentResolution = VolumtericResolution.Half;
private Texture2D _ditheringTexture;
private Texture3D _noiseTexture;
public VolumtericResolution Resolution = VolumtericResolution.Half;
public Texture DefaultSpotCookie;
public CommandBuffer GlobalCommandBuffer => _preLightPass;
public static event Action<VolumetricLightRenderer, Matrix4x4> PreRenderEvent;
public static Material GetLightMaterial()
{
return _lightMaterial;
}
public static Mesh GetPointLightMesh()
{
return _pointLightMesh;
}
public static Mesh GetSpotLightMesh()
{
return _spotLightMesh;
}
public RenderTexture GetVolumeLightBuffer()
{
if (Resolution == VolumtericResolution.Quarter)
{
return _quarterVolumeLightTexture;
}
if (Resolution == VolumtericResolution.Half)
{
return _halfVolumeLightTexture;
}
return _volumeLightTexture;
}
public RenderTexture GetVolumeLightDepthBuffer()
{
if (Resolution == VolumtericResolution.Quarter)
{
return _quarterDepthBuffer;
}
if (Resolution == VolumtericResolution.Half)
{
return _halfDepthBuffer;
}
return null;
}
public static Texture GetDefaultSpotCookie()
{
return _defaultSpotCookie;
}
private void Awake()
{
_camera = GetComponent<Camera>();
if (_camera.actualRenderingPath == RenderingPath.Forward)
{
_camera.depthTextureMode = DepthTextureMode.Depth;
}
_currentResolution = Resolution;
Shader shader = Shader.Find("Hidden/BlitAdd");
if (shader == null)
{
throw new Exception("Critical Error: \"Hidden/BlitAdd\" shader is missing. Make sure it is included in \"Always Included Shaders\" in ProjectSettings/Graphics.");
}
_blitAddMaterial = new Material(shader);
shader = Shader.Find("Hidden/BilateralBlur");
if (shader == null)
{
throw new Exception("Critical Error: \"Hidden/BilateralBlur\" shader is missing. Make sure it is included in \"Always Included Shaders\" in ProjectSettings/Graphics.");
}
_bilateralBlurMaterial = new Material(shader);
_preLightPass = new CommandBuffer();
_preLightPass.name = "PreLight";
ChangeResolution();
if (_pointLightMesh == null)
{
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
_pointLightMesh = obj.GetComponent<MeshFilter>().sharedMesh;
UnityEngine.Object.Destroy(obj);
}
if (_spotLightMesh == null)
{
_spotLightMesh = CreateSpotLightMesh();
}
if (_lightMaterial == null)
{
shader = Shader.Find("Sandbox/VolumetricLight");
if (shader == null)
{
throw new Exception("Critical Error: \"Sandbox/VolumetricLight\" shader is missing. Make sure it is included in \"Always Included Shaders\" in ProjectSettings/Graphics.");
}
_lightMaterial = new Material(shader);
}
if (_defaultSpotCookie == null)
{
_defaultSpotCookie = DefaultSpotCookie;
}
LoadNoise3dTexture();
GenerateDitherTexture();
}
private void OnEnable()
{
if (_camera.actualRenderingPath == RenderingPath.Forward)
{
_camera.AddCommandBuffer(CameraEvent.AfterDepthTexture, _preLightPass);
}
else
{
_camera.AddCommandBuffer(CameraEvent.BeforeLighting, _preLightPass);
}
}
private void OnDisable()
{
if (_camera.actualRenderingPath == RenderingPath.Forward)
{
_camera.RemoveCommandBuffer(CameraEvent.AfterDepthTexture, _preLightPass);
}
else
{
_camera.RemoveCommandBuffer(CameraEvent.BeforeLighting, _preLightPass);
}
}
private void ChangeResolution()
{
int pixelWidth = _camera.pixelWidth;
int pixelHeight = _camera.pixelHeight;
if (_volumeLightTexture != null)
{
UnityEngine.Object.Destroy(_volumeLightTexture);
}
_volumeLightTexture = new RenderTexture(pixelWidth, pixelHeight, 0, RenderTextureFormat.ARGBHalf);
_volumeLightTexture.name = "VolumeLightBuffer";
_volumeLightTexture.filterMode = FilterMode.Bilinear;
if (_halfDepthBuffer != null)
{
UnityEngine.Object.Destroy(_halfDepthBuffer);
}
if (_halfVolumeLightTexture != null)
{
UnityEngine.Object.Destroy(_halfVolumeLightTexture);
}
if (Resolution == VolumtericResolution.Half || Resolution == VolumtericResolution.Quarter)
{
_halfVolumeLightTexture = new RenderTexture(pixelWidth / 2, pixelHeight / 2, 0, RenderTextureFormat.ARGBHalf);
_halfVolumeLightTexture.name = "VolumeLightBufferHalf";
_halfVolumeLightTexture.filterMode = FilterMode.Bilinear;
_halfDepthBuffer = new RenderTexture(pixelWidth / 2, pixelHeight / 2, 0, RenderTextureFormat.RFloat);
_halfDepthBuffer.name = "VolumeLightHalfDepth";
_halfDepthBuffer.Create();
_halfDepthBuffer.filterMode = FilterMode.Point;
}
if (_quarterVolumeLightTexture != null)
{
UnityEngine.Object.Destroy(_quarterVolumeLightTexture);
}
if (_quarterDepthBuffer != null)
{
UnityEngine.Object.Destroy(_quarterDepthBuffer);
}
if (Resolution == VolumtericResolution.Quarter)
{
_quarterVolumeLightTexture = new RenderTexture(pixelWidth / 4, pixelHeight / 4, 0, RenderTextureFormat.ARGBHalf);
_quarterVolumeLightTexture.name = "VolumeLightBufferQuarter";
_quarterVolumeLightTexture.filterMode = FilterMode.Bilinear;
_quarterDepthBuffer = new RenderTexture(pixelWidth / 4, pixelHeight / 4, 0, RenderTextureFormat.RFloat);
_quarterDepthBuffer.name = "VolumeLightQuarterDepth";
_quarterDepthBuffer.Create();
_quarterDepthBuffer.filterMode = FilterMode.Point;
}
}
public void OnPreRender()
{
Matrix4x4 proj = Matrix4x4.Perspective(_camera.fieldOfView, _camera.aspect, 0.01f, _camera.farClipPlane);
if (XRSettings.enabled)
{
proj = Camera.current.projectionMatrix;
}
proj = GL.GetGPUProjectionMatrix(proj, renderIntoTexture: true);
_viewProj = proj * _camera.worldToCameraMatrix;
_preLightPass.Clear();
bool flag = SystemInfo.graphicsShaderLevel > 40;
if (Resolution == VolumtericResolution.Quarter)
{
Texture source = null;
_preLightPass.Blit(source, _halfDepthBuffer, _bilateralBlurMaterial, flag ? 4 : 10);
_preLightPass.Blit(source, _quarterDepthBuffer, _bilateralBlurMaterial, flag ? 6 : 11);
_preLightPass.SetRenderTarget(_quarterVolumeLightTexture);
}
else if (Resolution == VolumtericResolution.Half)
{
Texture source2 = null;
_preLightPass.Blit(source2, _halfDepthBuffer, _bilateralBlurMaterial, flag ? 4 : 10);
_preLightPass.SetRenderTarget(_halfVolumeLightTexture);
}
else
{
_preLightPass.SetRenderTarget(_volumeLightTexture);
}
_preLightPass.ClearRenderTarget(clearDepth: false, clearColor: true, new Color(0f, 0f, 0f, 1f));
UpdateMaterialParameters();
if (VolumetricLightRenderer.PreRenderEvent != null)
{
VolumetricLightRenderer.PreRenderEvent(this, _viewProj);
}
}
[ImageEffectOpaque]
public void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (Resolution == VolumtericResolution.Quarter)
{
RenderTexture temporary = RenderTexture.GetTemporary(_quarterDepthBuffer.width, _quarterDepthBuffer.height, 0, RenderTextureFormat.ARGBHalf);
temporary.filterMode = FilterMode.Bilinear;
Graphics.Blit(_quarterVolumeLightTexture, temporary, _bilateralBlurMaterial, 8);
Graphics.Blit(temporary, _quarterVolumeLightTexture, _bilateralBlurMaterial, 9);
Graphics.Blit(_quarterVolumeLightTexture, _volumeLightTexture, _bilateralBlurMaterial, 7);
RenderTexture.ReleaseTemporary(temporary);
}
else if (Resolution == VolumtericResolution.Half)
{
RenderTexture temporary2 = RenderTexture.GetTemporary(_halfVolumeLightTexture.width, _halfVolumeLightTexture.height, 0, RenderTextureFormat.ARGBHalf);
temporary2.filterMode = FilterMode.Bilinear;
Graphics.Blit(_halfVolumeLightTexture, temporary2, _bilateralBlurMaterial, 2);
Graphics.Blit(temporary2, _halfVolumeLightTexture, _bilateralBlurMaterial, 3);
Graphics.Blit(_halfVolumeLightTexture, _volumeLightTexture, _bilateralBlurMaterial, 5);
RenderTexture.ReleaseTemporary(temporary2);
}
else
{
RenderTexture temporary3 = RenderTexture.GetTemporary(_volumeLightTexture.width, _volumeLightTexture.height, 0, RenderTextureFormat.ARGBHalf);
temporary3.filterMode = FilterMode.Bilinear;
Graphics.Blit(_volumeLightTexture, temporary3, _bilateralBlurMaterial, 0);
Graphics.Blit(temporary3, _volumeLightTexture, _bilateralBlurMaterial, 1);
RenderTexture.ReleaseTemporary(temporary3);
}
_blitAddMaterial.SetTexture("_Source", source);
Graphics.Blit(_volumeLightTexture, destination, _blitAddMaterial, 0);
}
private void UpdateMaterialParameters()
{
_bilateralBlurMaterial.SetTexture("_HalfResDepthBuffer", _halfDepthBuffer);
_bilateralBlurMaterial.SetTexture("_HalfResColor", _halfVolumeLightTexture);
_bilateralBlurMaterial.SetTexture("_QuarterResDepthBuffer", _quarterDepthBuffer);
_bilateralBlurMaterial.SetTexture("_QuarterResColor", _quarterVolumeLightTexture);
Shader.SetGlobalTexture("_DitherTexture", _ditheringTexture);
Shader.SetGlobalTexture("_NoiseTexture", _noiseTexture);
}
private void Update()
{
if (_currentResolution != Resolution)
{
_currentResolution = Resolution;
ChangeResolution();
}
if (_volumeLightTexture.width != _camera.pixelWidth || _volumeLightTexture.height != _camera.pixelHeight)
{
ChangeResolution();
}
}
private void LoadNoise3dTexture()
{
TextAsset textAsset = Resources.Load("NoiseVolume") as TextAsset;
byte[] bytes = textAsset.bytes;
uint num = BitConverter.ToUInt32(textAsset.bytes, 12);
uint num2 = BitConverter.ToUInt32(textAsset.bytes, 16);
uint num3 = BitConverter.ToUInt32(textAsset.bytes, 20);
uint num4 = BitConverter.ToUInt32(textAsset.bytes, 24);
uint num5 = BitConverter.ToUInt32(textAsset.bytes, 80);
uint num6 = BitConverter.ToUInt32(textAsset.bytes, 88);
if (num6 == 0)
{
num6 = num3 / num2 * 8;
}
_noiseTexture = new Texture3D((int)num2, (int)num, (int)num4, TextureFormat.RGBA32, mipChain: false);
_noiseTexture.name = "3D Noise";
Color[] array = new Color[num2 * num * num4];
uint num7 = 128u;
if (textAsset.bytes[84] == 68 && textAsset.bytes[85] == 88 && textAsset.bytes[86] == 49 && textAsset.bytes[87] == 48 && (num5 & 4) != 0)
{
uint num8 = BitConverter.ToUInt32(textAsset.bytes, (int)num7);
if (num8 >= 60 && num8 <= 65)
{
num6 = 8u;
}
else if (num8 >= 48 && num8 <= 52)
{
num6 = 16u;
}
else if (num8 >= 27 && num8 <= 32)
{
num6 = 32u;
}
num7 += 20;
}
uint num9 = num6 / 8;
num3 = (num2 * num6 + 7) / 8;
for (int i = 0; i < num4; i++)
{
for (int j = 0; j < num; j++)
{
for (int k = 0; k < num2; k++)
{
float num10 = (float)(int)bytes[num7 + k * num9] / 255f;
array[k + j * num2 + i * num2 * num] = new Color(num10, num10, num10, num10);
}
num7 += num3;
}
}
_noiseTexture.SetPixels(array);
_noiseTexture.Apply();
}
private void GenerateDitherTexture()
{
if (!(_ditheringTexture != null))
{
int num = 8;
_ditheringTexture = new Texture2D(num, num, TextureFormat.Alpha8, mipChain: false, linear: true);
_ditheringTexture.filterMode = FilterMode.Point;
Color32[] array = new Color32[num * num];
int num2 = 0;
byte b = 3;
array[num2++] = new Color32(b, b, b, b);
b = 192;
array[num2++] = new Color32(b, b, b, b);
b = 51;
array[num2++] = new Color32(b, b, b, b);
b = 239;
array[num2++] = new Color32(b, b, b, b);
b = 15;
array[num2++] = new Color32(b, b, b, b);
b = 204;
array[num2++] = new Color32(b, b, b, b);
b = 62;
array[num2++] = new Color32(b, b, b, b);
b = 251;
array[num2++] = new Color32(b, b, b, b);
b = 129;
array[num2++] = new Color32(b, b, b, b);
b = 66;
array[num2++] = new Color32(b, b, b, b);
b = 176;
array[num2++] = new Color32(b, b, b, b);
b = 113;
array[num2++] = new Color32(b, b, b, b);
b = 141;
array[num2++] = new Color32(b, b, b, b);
b = 78;
array[num2++] = new Color32(b, b, b, b);
b = 188;
array[num2++] = new Color32(b, b, b, b);
b = 125;
array[num2++] = new Color32(b, b, b, b);
b = 35;
array[num2++] = new Color32(b, b, b, b);
b = 223;
array[num2++] = new Color32(b, b, b, b);
b = 19;
array[num2++] = new Color32(b, b, b, b);
b = 207;
array[num2++] = new Color32(b, b, b, b);
b = 47;
array[num2++] = new Color32(b, b, b, b);
b = 235;
array[num2++] = new Color32(b, b, b, b);
b = 31;
array[num2++] = new Color32(b, b, b, b);
b = 219;
array[num2++] = new Color32(b, b, b, b);
b = 160;
array[num2++] = new Color32(b, b, b, b);
b = 98;
array[num2++] = new Color32(b, b, b, b);
b = 145;
array[num2++] = new Color32(b, b, b, b);
b = 82;
array[num2++] = new Color32(b, b, b, b);
b = 172;
array[num2++] = new Color32(b, b, b, b);
b = 109;
array[num2++] = new Color32(b, b, b, b);
b = 156;
array[num2++] = new Color32(b, b, b, b);
b = 94;
array[num2++] = new Color32(b, b, b, b);
b = 11;
array[num2++] = new Color32(b, b, b, b);
b = 200;
array[num2++] = new Color32(b, b, b, b);
b = 58;
array[num2++] = new Color32(b, b, b, b);
b = 247;
array[num2++] = new Color32(b, b, b, b);
b = 7;
array[num2++] = new Color32(b, b, b, b);
b = 196;
array[num2++] = new Color32(b, b, b, b);
b = 54;
array[num2++] = new Color32(b, b, b, b);
b = 243;
array[num2++] = new Color32(b, b, b, b);
b = 137;
array[num2++] = new Color32(b, b, b, b);
b = 74;
array[num2++] = new Color32(b, b, b, b);
b = 184;
array[num2++] = new Color32(b, b, b, b);
b = 121;
array[num2++] = new Color32(b, b, b, b);
b = 133;
array[num2++] = new Color32(b, b, b, b);
b = 70;
array[num2++] = new Color32(b, b, b, b);
b = 180;
array[num2++] = new Color32(b, b, b, b);
b = 117;
array[num2++] = new Color32(b, b, b, b);
b = 43;
array[num2++] = new Color32(b, b, b, b);
b = 231;
array[num2++] = new Color32(b, b, b, b);
b = 27;
array[num2++] = new Color32(b, b, b, b);
b = 215;
array[num2++] = new Color32(b, b, b, b);
b = 39;
array[num2++] = new Color32(b, b, b, b);
b = 227;
array[num2++] = new Color32(b, b, b, b);
b = 23;
array[num2++] = new Color32(b, b, b, b);
b = 211;
array[num2++] = new Color32(b, b, b, b);
b = 168;
array[num2++] = new Color32(b, b, b, b);
b = 105;
array[num2++] = new Color32(b, b, b, b);
b = 153;
array[num2++] = new Color32(b, b, b, b);
b = 90;
array[num2++] = new Color32(b, b, b, b);
b = 164;
array[num2++] = new Color32(b, b, b, b);
b = 102;
array[num2++] = new Color32(b, b, b, b);
b = 149;
array[num2++] = new Color32(b, b, b, b);
b = 86;
array[num2++] = new Color32(b, b, b, b);
_ditheringTexture.SetPixels32(array);
_ditheringTexture.Apply();
}
}
private Mesh CreateSpotLightMesh()
{
Mesh mesh = new Mesh();
Vector3[] array = new Vector3[50];
Color32[] array2 = new Color32[50];
array[0] = new Vector3(0f, 0f, 0f);
array[1] = new Vector3(0f, 0f, 1f);
float num = 0f;
float num2 = MathF.PI / 8f;
float num3 = 0.9f;
for (int i = 0; i < 16; i++)
{
array[i + 2] = new Vector3((0f - Mathf.Cos(num)) * num3, Mathf.Sin(num) * num3, num3);
array2[i + 2] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
array[i + 2 + 16] = new Vector3(0f - Mathf.Cos(num), Mathf.Sin(num), 1f);
array2[i + 2 + 16] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 0);
array[i + 2 + 32] = new Vector3((0f - Mathf.Cos(num)) * num3, Mathf.Sin(num) * num3, 1f);
array2[i + 2 + 32] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
num += num2;
}
mesh.vertices = array;
mesh.colors32 = array2;
int[] array3 = new int[288];
int num4 = 0;
for (int j = 2; j < 17; j++)
{
array3[num4++] = 0;
array3[num4++] = j;
array3[num4++] = j + 1;
}
array3[num4++] = 0;
array3[num4++] = 17;
array3[num4++] = 2;
for (int k = 2; k < 17; k++)
{
array3[num4++] = k;
array3[num4++] = k + 16;
array3[num4++] = k + 1;
array3[num4++] = k + 1;
array3[num4++] = k + 16;
array3[num4++] = k + 16 + 1;
}
array3[num4++] = 2;
array3[num4++] = 17;
array3[num4++] = 18;
array3[num4++] = 18;
array3[num4++] = 17;
array3[num4++] = 33;
for (int l = 18; l < 33; l++)
{
array3[num4++] = l;
array3[num4++] = l + 16;
array3[num4++] = l + 1;
array3[num4++] = l + 1;
array3[num4++] = l + 16;
array3[num4++] = l + 16 + 1;
}
array3[num4++] = 18;
array3[num4++] = 33;
array3[num4++] = 34;
array3[num4++] = 34;
array3[num4++] = 33;
array3[num4++] = 49;
for (int m = 34; m < 49; m++)
{
array3[num4++] = 1;
array3[num4++] = m + 1;
array3[num4++] = m;
}
array3[num4++] = 1;
array3[num4++] = 34;
array3[num4++] = 49;
mesh.triangles = array3;
mesh.RecalculateBounds();
return mesh;
}
}