Files
2026-03-04 10:03:45 +08:00

296 lines
9.0 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace Artngame.SKYMASTER.PlanetCreator.Atmosphere
{
[RequireComponent(typeof(Camera))]
[ExecuteInEditMode]
public class AtmosphericScatter : MonoBehaviour
{
public bool enableVR;
[Range(0f, 1f)]
public float imageFXBlend = 1f;
public int downscale;
public float SCALE = 1000f;
private const int TRANSMITTANCE_WIDTH = 256;
private const int TRANSMITTANCE_HEIGHT = 64;
private const int TRANSMITTANCE_CHANNELS = 3;
private const int IRRADIANCE_WIDTH = 64;
private const int IRRADIANCE_HEIGHT = 16;
private const int IRRADIANCE_CHANNELS = 3;
private const int INSCATTER_WIDTH = 256;
private const int INSCATTER_HEIGHT = 128;
private const int INSCATTER_DEPTH = 32;
private const int INSCATTER_CHANNELS = 4;
public GameObject m_sun;
public Vector3 m_betaR = new Vector3(0.0058f, 0.0135f, 0.0331f);
public float m_mieG = 0.75f;
public float m_sunIntensity = 100f;
public ComputeShader m_writeData;
public Vector3 EarthPosition;
public float RG = 6360f;
public float RT = 6420f;
public float RL = 6421f;
public float HR = 8f;
public float HM = 1.2f;
private CommandBuffer lightingBuffer;
private Camera camera;
public float MinViewDistance = 3000f;
public RenderTexture m_transmittance;
public RenderTexture m_inscatter;
public RenderTexture m_irradiance;
public Material m_atmosphereImageEffect;
private Matrix4x4 left_world_from_view;
private Matrix4x4 right_world_from_view;
private Matrix4x4 left_screen_from_view;
private Matrix4x4 right_screen_from_view;
private Matrix4x4 left_view_from_screen;
private Matrix4x4 right_view_from_screen;
private void Start()
{
Application.runInBackground = false;
lightingBuffer = new CommandBuffer();
camera = GetComponent<Camera>();
if (imageFXBlend < 1f)
{
camera.AddCommandBuffer(CameraEvent.AfterImageEffects, lightingBuffer);
}
else
{
camera.AddCommandBuffer(CameraEvent.BeforeLighting, lightingBuffer);
}
camera.depthTextureMode = DepthTextureMode.DepthNormals;
CreateTextures();
CopyDataToTextures();
InitMaterial(m_atmosphereImageEffect);
UpdateMaterialTextures(m_atmosphereImageEffect);
}
private void CreateTextures()
{
m_transmittance = new RenderTexture(256, 64, 0, RenderTextureFormat.ARGBHalf)
{
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Bilinear,
enableRandomWrite = true
};
m_transmittance.Create();
m_inscatter = new RenderTexture(256, 128, 0, RenderTextureFormat.ARGBHalf)
{
volumeDepth = 32,
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Bilinear,
dimension = TextureDimension.Tex3D,
enableRandomWrite = true
};
m_inscatter.Create();
m_irradiance = new RenderTexture(64, 16, 0, RenderTextureFormat.ARGBHalf)
{
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Bilinear,
enableRandomWrite = true
};
m_irradiance.Create();
}
private void CopyDataToTextures()
{
string path = Application.streamingAssetsPath + "/Textures/transmittance.raw";
ComputeBuffer computeBuffer = new ComputeBuffer(16384, 12);
CBUtility.WriteIntoRenderTexture(m_transmittance, 3, path, computeBuffer, m_writeData);
computeBuffer.Release();
path = Application.streamingAssetsPath + "/Textures/inscatter.raw";
computeBuffer = new ComputeBuffer(1048576, 16);
CBUtility.WriteIntoRenderTexture(m_inscatter, 4, path, computeBuffer, m_writeData);
computeBuffer.Release();
path = Application.streamingAssetsPath + "/Textures/irradiance.raw";
computeBuffer = new ComputeBuffer(1024, 12);
CBUtility.WriteIntoRenderTexture(m_irradiance, 3, path, computeBuffer, m_writeData);
computeBuffer.Release();
}
private void LateUpdate()
{
UpdateMat(m_atmosphereImageEffect);
camera.farClipPlane = Mathf.Max(MinViewDistance, (base.transform.position - base.transform.position.normalized * (RG * SCALE / 3f)).magnitude);
UpdateRenderBuffer();
}
private void UpdateRenderBuffer()
{
lightingBuffer.Clear();
lightingBuffer.SetGlobalFloat("imageFXBlend", imageFXBlend);
Matrix4x4 projectionMatrix = camera.projectionMatrix;
Vector4 value = new Vector4(1f / projectionMatrix[0], 1f / projectionMatrix[5], 1f, 1f);
lightingBuffer.SetGlobalVector("_CamScreenDir", value);
Matrix4x4 inverse = (camera.projectionMatrix * camera.worldToCameraMatrix).inverse;
lightingBuffer.SetGlobalMatrix("_ViewProjectInverse", inverse);
Matrix4x4 inverse2 = camera.cameraToWorldMatrix.inverse;
lightingBuffer.SetGlobalMatrix("_CameraInv", inverse2);
lightingBuffer.SetGlobalMatrix("_ViewMatrix", camera.worldToCameraMatrix);
lightingBuffer.SetGlobalFloat("_FarPlane", camera.farClipPlane);
lightingBuffer.SetGlobalTexture("_CameraDepthNormalsTexture", BuiltinRenderTextureType.GBuffer2);
if (camera.stereoEnabled)
{
left_world_from_view = camera.GetStereoViewMatrix(Camera.StereoscopicEye.Left).inverse;
right_world_from_view = camera.GetStereoViewMatrix(Camera.StereoscopicEye.Right).inverse;
left_screen_from_view = camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left);
right_screen_from_view = camera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Right);
left_view_from_screen = GL.GetGPUProjectionMatrix(left_screen_from_view, renderIntoTexture: true).inverse;
right_view_from_screen = GL.GetGPUProjectionMatrix(right_screen_from_view, renderIntoTexture: true).inverse;
left_view_from_screen[1, 1] *= -1f;
right_view_from_screen[1, 1] *= -1f;
lightingBuffer.SetGlobalMatrix("_LeftWorldFromView", left_world_from_view);
lightingBuffer.SetGlobalMatrix("_RightWorldFromView", right_world_from_view);
lightingBuffer.SetGlobalMatrix("_LeftViewFromScreen", left_view_from_screen);
lightingBuffer.SetGlobalMatrix("_RightViewFromScreen", right_view_from_screen);
}
else
{
left_world_from_view = camera.cameraToWorldMatrix;
left_screen_from_view = camera.projectionMatrix;
left_view_from_screen = GL.GetGPUProjectionMatrix(left_screen_from_view, renderIntoTexture: true).inverse;
left_view_from_screen[1, 1] *= -1f;
lightingBuffer.SetGlobalMatrix("_LeftWorldFromView", left_world_from_view);
lightingBuffer.SetGlobalMatrix("_LeftViewFromScreen", left_view_from_screen);
}
RenderTargetIdentifier source = new RenderTargetIdentifier(BuiltinRenderTextureType.GBuffer0);
if (imageFXBlend < 1f)
{
source = new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget);
}
RenderTargetIdentifier dest = new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget);
int num = Shader.PropertyToID("_DownsampledTarget");
lightingBuffer.GetTemporaryRT(num, camera.pixelWidth / Mathf.Max(1, downscale), camera.pixelHeight / Mathf.Max(1, downscale), 0, FilterMode.Bilinear, RenderTextureFormat.ARGBFloat);
if (imageFXBlend < 1f)
{
lightingBuffer.SetGlobalFloat("invertY", 1f);
if (enableVR)
{
lightingBuffer.Blit(source, num);
}
}
else
{
lightingBuffer.SetGlobalFloat("invertY", 0f);
if (enableVR)
{
lightingBuffer.Blit(source, num, m_atmosphereImageEffect);
}
}
if (!enableVR)
{
lightingBuffer.Blit(source, num, m_atmosphereImageEffect);
}
if (imageFXBlend < 1f)
{
if (!enableVR)
{
lightingBuffer.SetGlobalFloat("invertY", 0f);
}
lightingBuffer.Blit(num, dest, m_atmosphereImageEffect);
}
else
{
lightingBuffer.Blit(num, dest);
}
lightingBuffer.ReleaseTemporaryRT(num);
}
private void UpdateMat(Material mat)
{
mat.SetVector("betaR", m_betaR / SCALE);
mat.SetFloat("mieG", m_mieG);
mat.SetVector("SUN_DIR", m_sun.transform.forward * -1f);
mat.SetFloat("SUN_INTENSITY", m_sunIntensity);
mat.SetVector("EARTH_POS", EarthPosition);
mat.SetVector("CAMERA_POS", base.transform.position);
mat.SetVector("betaMSca", Vector4.one * 0.004f / SCALE);
mat.SetVector("betaMEx", Vector4.one * 0.004f * 0.9f / SCALE);
mat.SetFloat("SCALE", SCALE);
mat.SetFloat("Rg", RG * SCALE);
mat.SetFloat("Rt", RT * SCALE);
mat.SetFloat("Rl", RL * SCALE);
mat.SetFloat("HR", HR * SCALE);
mat.SetFloat("HM", HM * SCALE);
}
private void UpdateMaterialTextures(Material mat)
{
mat.SetTexture("_Transmittance", m_transmittance);
mat.SetTexture("_Inscatter", m_inscatter);
mat.SetTexture("_Irradiance", m_irradiance);
}
private void InitMaterial(Material mat)
{
mat.SetFloat("M_PI", MathF.PI);
mat.SetFloat("SCALE", SCALE);
mat.SetFloat("Rg", 6360f * SCALE);
mat.SetFloat("Rt", 6420f * SCALE);
mat.SetFloat("Rl", 6421f * SCALE);
mat.SetFloat("RES_R", 32f);
mat.SetFloat("RES_MU", 128f);
mat.SetFloat("RES_MU_S", 32f);
mat.SetFloat("RES_NU", 8f);
mat.SetFloat("SUN_INTENSITY", m_sunIntensity);
mat.SetVector("SUN_DIR", m_sun.transform.forward * -1f);
}
private void OnDestroy()
{
if ((bool)m_transmittance)
{
m_irradiance.Release();
}
if ((bool)m_transmittance)
{
m_transmittance.Release();
}
if ((bool)m_inscatter)
{
m_inscatter.Release();
}
}
}
}