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(); 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(); } } } }