using System; using System.Runtime.InteropServices; using UnityEngine; [ExecuteInEditMode] [RequireComponent(typeof(Camera))] [AddComponentMenu("Image Effects/Sonic Ether/SEGI")] public class SEGI : MonoBehaviour { [Serializable] public enum VoxelResolution { low = 0x80, high = 0x100 } private enum RenderState { Voxelize = 0, Bounce = 1 } [StructLayout(LayoutKind.Sequential, Size = 1)] private struct Pass { public static int DiffuseTrace = 0; public static int BilateralBlur = 1; public static int BlendWithScene = 2; public static int TemporalBlend = 3; public static int SpecularTrace = 4; public static int GetCameraDepthTexture = 5; public static int GetWorldNormals = 6; public static int VisualizeGI = 7; public static int WriteBlack = 8; public static int VisualizeVoxels = 10; public static int BilateralUpsample = 11; } public struct SystemSupported { public bool hdrTextures; public bool rIntTextures; public bool dx11; public bool volumeTextures; public bool postShader; public bool sunDepthShader; public bool voxelizationShader; public bool tracingShader; public bool fullFunctionality { get { if (hdrTextures && rIntTextures && dx11 && volumeTextures && postShader && sunDepthShader && voxelizationShader) { return tracingShader; } return false; } } } private int updateGIcounter; public int updateGIevery = 1; public bool updateGI = true; public LayerMask giCullingMask = int.MaxValue; public float shadowSpaceSize = 50f; public Light sun; public Color skyColor; public float voxelSpaceSize = 25f; public bool useBilateralFiltering; [Range(0f, 2f)] public int innerOcclusionLayers = 1; [Range(0.01f, 1f)] public float temporalBlendWeight = 0.1f; public VoxelResolution voxelResolution = VoxelResolution.high; public bool visualizeSunDepthTexture; public bool visualizeGI; public bool visualizeVoxels; public bool halfResolution = true; public bool stochasticSampling = true; public bool infiniteBounces; public Transform followTransform; [Range(1f, 128f)] public int cones = 6; [Range(1f, 32f)] public int coneTraceSteps = 14; [Range(0.1f, 2f)] public float coneLength = 1f; [Range(0.5f, 6f)] public float coneWidth = 5.5f; [Range(0f, 4f)] public float occlusionStrength = 1f; [Range(0f, 4f)] public float nearOcclusionStrength = 0.5f; [Range(0.001f, 4f)] public float occlusionPower = 1.5f; [Range(0f, 4f)] public float coneTraceBias = 1f; [Range(0f, 4f)] public float nearLightGain = 1f; [Range(0f, 4f)] public float giGain = 1f; [Range(0f, 4f)] public float secondaryBounceGain = 1f; [Range(0f, 16f)] public float softSunlight; [Range(0f, 8f)] public float skyIntensity = 1f; public bool doReflections = true; [Range(12f, 128f)] public int reflectionSteps = 64; [Range(0.001f, 4f)] public float reflectionOcclusionPower = 1f; [Range(0f, 1f)] public float skyReflectionIntensity = 1f; public bool voxelAA; public bool gaussianMipFilter; [Range(0.1f, 4f)] public float farOcclusionStrength = 1f; [Range(0.1f, 4f)] public float farthestOcclusionStrength = 1f; [Range(3f, 16f)] public int secondaryCones = 6; [Range(0.1f, 4f)] public float secondaryOcclusionStrength = 1f; public bool sphericalSkylight; private object initChecker; private Material material; private Camera attachedCamera; private Transform shadowCamTransform; private Camera shadowCam; private GameObject shadowCamGameObject; private Texture2D[] blueNoise; private int sunShadowResolution = 256; private int prevSunShadowResolution; private Shader sunDepthShader; private float shadowSpaceDepthRatio = 10f; private int frameCounter; private RenderTexture sunDepthTexture; private RenderTexture previousGIResult; private RenderTexture previousCameraDepth; private RenderTexture integerVolume; private RenderTexture[] volumeTextures; private RenderTexture secondaryIrradianceVolume; private RenderTexture volumeTextureB; private RenderTexture activeVolume; private RenderTexture previousActiveVolume; private RenderTexture dummyVoxelTextureAAScaled; private RenderTexture dummyVoxelTextureFixed; private bool notReadyToRender; private Shader voxelizationShader; private Shader voxelTracingShader; private ComputeShader clearCompute; private ComputeShader transferIntsCompute; private ComputeShader mipFilterCompute; public int numMipLevels = 6; private Camera voxelCamera; private GameObject voxelCameraGO; private GameObject leftViewPoint; private GameObject topViewPoint; private Vector3 voxelSpaceOrigin; private Vector3 previousVoxelSpaceOrigin; private Vector3 voxelSpaceOriginDelta; private Quaternion rotationFront = new Quaternion(0f, 0f, 0f, 1f); private Quaternion rotationLeft = new Quaternion(0f, 0.7f, 0f, 0.7f); private Quaternion rotationTop = new Quaternion(0.7f, 0f, 0f, 0.7f); private int voxelFlipFlop; private RenderState renderState; public SystemSupported systemSupported; private CameraClearFlags prevFlags; private float voxelScaleFactor => (float)voxelResolution / 256f; public float vramUsage { get { long num = 0L; if (sunDepthTexture != null) { num += sunDepthTexture.width * sunDepthTexture.height * 16; } if (previousGIResult != null) { num += previousGIResult.width * previousGIResult.height * 16 * 4; } if (previousCameraDepth != null) { num += previousCameraDepth.width * previousCameraDepth.height * 32; } if (integerVolume != null) { num += integerVolume.width * integerVolume.height * integerVolume.volumeDepth * 32; } if (volumeTextures != null) { for (int i = 0; i < volumeTextures.Length; i++) { if (volumeTextures[i] != null) { num += volumeTextures[i].width * volumeTextures[i].height * volumeTextures[i].volumeDepth * 16 * 4; } } } if (secondaryIrradianceVolume != null) { num += secondaryIrradianceVolume.width * secondaryIrradianceVolume.height * secondaryIrradianceVolume.volumeDepth * 16 * 4; } if (volumeTextureB != null) { num += volumeTextureB.width * volumeTextureB.height * volumeTextureB.volumeDepth * 16 * 4; } if (dummyVoxelTextureAAScaled != null) { num += dummyVoxelTextureAAScaled.width * dummyVoxelTextureAAScaled.height * 8; } if (dummyVoxelTextureFixed != null) { num += dummyVoxelTextureFixed.width * dummyVoxelTextureFixed.height * 8; } return (float)num / 8388608f; } } private int mipFilterKernel { get { if (!gaussianMipFilter) { return 0; } return 1; } } private int dummyVoxelResolution => (int)voxelResolution * ((!voxelAA) ? 1 : 2); private int giRenderRes { get { if (!halfResolution) { return 1; } return 2; } } public void ApplyPreset(SEGIPreset preset) { voxelResolution = preset.voxelResolution; voxelAA = preset.voxelAA; innerOcclusionLayers = preset.innerOcclusionLayers; infiniteBounces = preset.infiniteBounces; temporalBlendWeight = preset.temporalBlendWeight; useBilateralFiltering = preset.useBilateralFiltering; halfResolution = preset.halfResolution; stochasticSampling = preset.stochasticSampling; doReflections = preset.doReflections; cones = preset.cones; coneTraceSteps = preset.coneTraceSteps; coneLength = preset.coneLength; coneWidth = preset.coneWidth; coneTraceBias = preset.coneTraceBias; occlusionStrength = preset.occlusionStrength; nearOcclusionStrength = preset.nearOcclusionStrength; occlusionPower = preset.occlusionPower; nearLightGain = preset.nearLightGain; giGain = preset.giGain; secondaryBounceGain = preset.secondaryBounceGain; reflectionSteps = preset.reflectionSteps; reflectionOcclusionPower = preset.reflectionOcclusionPower; skyReflectionIntensity = preset.skyReflectionIntensity; gaussianMipFilter = preset.gaussianMipFilter; farOcclusionStrength = preset.farOcclusionStrength; farthestOcclusionStrength = preset.farthestOcclusionStrength; secondaryCones = preset.secondaryCones; secondaryOcclusionStrength = preset.secondaryOcclusionStrength; } private void Start() { InitCheck(); if (Camera.main != null) { _ = Application.isPlaying; } } private void InitCheck() { if (initChecker == null) { Init(); } } private void CreateVolumeTextures() { volumeTextures = new RenderTexture[numMipLevels]; for (int i = 0; i < numMipLevels; i++) { if ((bool)volumeTextures[i]) { volumeTextures[i].DiscardContents(); volumeTextures[i].Release(); UnityEngine.Object.DestroyImmediate(volumeTextures[i]); } int num = (int)voxelResolution / Mathf.RoundToInt(Mathf.Pow(2f, i)); volumeTextures[i] = new RenderTexture(num, num, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); volumeTextures[i].isVolume = true; volumeTextures[i].volumeDepth = num; volumeTextures[i].enableRandomWrite = true; volumeTextures[i].filterMode = FilterMode.Bilinear; volumeTextures[i].autoGenerateMips = false; volumeTextures[i].useMipMap = false; volumeTextures[i].Create(); volumeTextures[i].hideFlags = HideFlags.HideAndDontSave; } if ((bool)volumeTextureB) { volumeTextureB.DiscardContents(); volumeTextureB.Release(); UnityEngine.Object.DestroyImmediate(volumeTextureB); } volumeTextureB = new RenderTexture((int)voxelResolution, (int)voxelResolution, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); volumeTextureB.isVolume = true; volumeTextureB.volumeDepth = (int)voxelResolution; volumeTextureB.enableRandomWrite = true; volumeTextureB.filterMode = FilterMode.Bilinear; volumeTextureB.autoGenerateMips = false; volumeTextureB.useMipMap = false; volumeTextureB.Create(); volumeTextureB.hideFlags = HideFlags.HideAndDontSave; if ((bool)secondaryIrradianceVolume) { secondaryIrradianceVolume.DiscardContents(); secondaryIrradianceVolume.Release(); UnityEngine.Object.DestroyImmediate(secondaryIrradianceVolume); } secondaryIrradianceVolume = new RenderTexture((int)voxelResolution, (int)voxelResolution, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); secondaryIrradianceVolume.isVolume = true; secondaryIrradianceVolume.volumeDepth = (int)voxelResolution; secondaryIrradianceVolume.enableRandomWrite = true; secondaryIrradianceVolume.filterMode = FilterMode.Point; secondaryIrradianceVolume.autoGenerateMips = false; secondaryIrradianceVolume.useMipMap = false; secondaryIrradianceVolume.antiAliasing = 1; secondaryIrradianceVolume.Create(); secondaryIrradianceVolume.hideFlags = HideFlags.HideAndDontSave; if ((bool)integerVolume) { integerVolume.DiscardContents(); integerVolume.Release(); UnityEngine.Object.DestroyImmediate(integerVolume); } integerVolume = new RenderTexture((int)voxelResolution, (int)voxelResolution, 0, RenderTextureFormat.RInt, RenderTextureReadWrite.Linear); integerVolume.isVolume = true; integerVolume.volumeDepth = (int)voxelResolution; integerVolume.enableRandomWrite = true; integerVolume.filterMode = FilterMode.Point; integerVolume.Create(); integerVolume.hideFlags = HideFlags.HideAndDontSave; ResizeDummyTexture(); } private void ResizeDummyTexture() { if ((bool)dummyVoxelTextureAAScaled) { dummyVoxelTextureAAScaled.DiscardContents(); dummyVoxelTextureAAScaled.Release(); UnityEngine.Object.DestroyImmediate(dummyVoxelTextureAAScaled); } dummyVoxelTextureAAScaled = new RenderTexture(dummyVoxelResolution, dummyVoxelResolution, 0, RenderTextureFormat.R8); dummyVoxelTextureAAScaled.Create(); dummyVoxelTextureAAScaled.hideFlags = HideFlags.HideAndDontSave; if ((bool)dummyVoxelTextureFixed) { dummyVoxelTextureFixed.DiscardContents(); dummyVoxelTextureFixed.Release(); UnityEngine.Object.DestroyImmediate(dummyVoxelTextureFixed); } dummyVoxelTextureFixed = new RenderTexture((int)voxelResolution, (int)voxelResolution, 0, RenderTextureFormat.R8); dummyVoxelTextureFixed.Create(); dummyVoxelTextureFixed.hideFlags = HideFlags.HideAndDontSave; } private void Init() { sunDepthShader = Shader.Find("Hidden/SEGIRenderSunDepth"); clearCompute = Resources.Load("SEGIClear") as ComputeShader; transferIntsCompute = Resources.Load("SEGITransferInts") as ComputeShader; mipFilterCompute = Resources.Load("SEGIMipFilter") as ComputeShader; voxelizationShader = Shader.Find("Hidden/SEGIVoxelizeScene"); voxelTracingShader = Shader.Find("Hidden/SEGITraceScene"); material = new Material(Shader.Find("Hidden/SEGI")); material.hideFlags = HideFlags.HideAndDontSave; attachedCamera = GetComponent(); attachedCamera.depthTextureMode |= DepthTextureMode.Depth; attachedCamera.depthTextureMode |= DepthTextureMode.MotionVectors; GameObject gameObject = GameObject.Find("SEGI_SHADOWCAM"); if (!gameObject) { shadowCamGameObject = new GameObject("SEGI_SHADOWCAM"); shadowCam = shadowCamGameObject.AddComponent(); shadowCamGameObject.hideFlags = HideFlags.HideAndDontSave; shadowCam.enabled = false; shadowCam.depth = attachedCamera.depth - 1f; shadowCam.orthographic = true; shadowCam.orthographicSize = shadowSpaceSize; shadowCam.clearFlags = CameraClearFlags.Color; shadowCam.backgroundColor = new Color(0f, 0f, 0f, 1f); shadowCam.farClipPlane = shadowSpaceSize * 2f * shadowSpaceDepthRatio; shadowCam.cullingMask = giCullingMask; shadowCam.useOcclusionCulling = false; shadowCamTransform = shadowCamGameObject.transform; } else { shadowCamGameObject = gameObject; shadowCam = gameObject.GetComponent(); shadowCamTransform = shadowCamGameObject.transform; } GameObject gameObject2 = GameObject.Find("SEGI_VOXEL_CAMERA"); if ((bool)gameObject2) { UnityEngine.Object.DestroyImmediate(gameObject2); } voxelCameraGO = new GameObject("SEGI_VOXEL_CAMERA"); voxelCameraGO.hideFlags = HideFlags.HideAndDontSave; voxelCamera = voxelCameraGO.AddComponent(); voxelCamera.enabled = false; voxelCamera.orthographic = true; voxelCamera.orthographicSize = voxelSpaceSize * 0.5f; voxelCamera.nearClipPlane = 0f; voxelCamera.farClipPlane = voxelSpaceSize; voxelCamera.depth = -2f; voxelCamera.renderingPath = RenderingPath.Forward; voxelCamera.clearFlags = CameraClearFlags.Color; voxelCamera.backgroundColor = Color.black; voxelCamera.useOcclusionCulling = false; GameObject gameObject3 = GameObject.Find("SEGI_LEFT_VOXEL_VIEW"); if ((bool)gameObject3) { UnityEngine.Object.DestroyImmediate(gameObject3); } leftViewPoint = new GameObject("SEGI_LEFT_VOXEL_VIEW"); leftViewPoint.hideFlags = HideFlags.HideAndDontSave; GameObject gameObject4 = GameObject.Find("SEGI_TOP_VOXEL_VIEW"); if ((bool)gameObject4) { UnityEngine.Object.DestroyImmediate(gameObject4); } topViewPoint = new GameObject("SEGI_TOP_VOXEL_VIEW"); topViewPoint.hideFlags = HideFlags.HideAndDontSave; blueNoise = null; blueNoise = new Texture2D[64]; for (int i = 0; i < 64; i++) { string text = "LDR_RGBA_" + i; Texture2D texture2D = Resources.Load("Noise Textures/" + text) as Texture2D; if (texture2D == null) { Debug.LogWarning("Unable to find noise texture \"Assets/SEGI/Resources/Noise Textures/" + text + "\" for SEGI!"); } blueNoise[i] = texture2D; } if ((bool)sunDepthTexture) { sunDepthTexture.DiscardContents(); sunDepthTexture.Release(); UnityEngine.Object.DestroyImmediate(sunDepthTexture); } sunDepthTexture = new RenderTexture(sunShadowResolution, sunShadowResolution, 16, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear); sunDepthTexture.wrapMode = TextureWrapMode.Clamp; sunDepthTexture.filterMode = FilterMode.Point; sunDepthTexture.Create(); sunDepthTexture.hideFlags = HideFlags.HideAndDontSave; CreateVolumeTextures(); initChecker = new object(); } private void CheckSupport() { systemSupported.hdrTextures = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf); systemSupported.rIntTextures = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RInt); systemSupported.dx11 = SystemInfo.graphicsShaderLevel >= 50 && SystemInfo.supportsComputeShaders; systemSupported.volumeTextures = SystemInfo.supports3DTextures; systemSupported.postShader = material.shader.isSupported; systemSupported.sunDepthShader = sunDepthShader.isSupported; systemSupported.voxelizationShader = voxelizationShader.isSupported; systemSupported.tracingShader = voxelTracingShader.isSupported; if (!systemSupported.fullFunctionality) { Debug.LogWarning("SEGI is not supported on the current platform. Check for shader compile errors in SEGI/Resources"); base.enabled = false; } } private void OnDrawGizmosSelected() { Color color = Gizmos.color; Gizmos.color = new Color(1f, 0.25f, 0f, 0.5f); Gizmos.DrawCube(voxelSpaceOrigin, new Vector3(voxelSpaceSize, voxelSpaceSize, voxelSpaceSize)); Gizmos.color = new Color(1f, 0f, 0f, 0.1f); Gizmos.color = color; } private void CleanupTexture(ref RenderTexture texture) { texture.DiscardContents(); UnityEngine.Object.DestroyImmediate(texture); } private void CleanupTextures() { CleanupTexture(ref sunDepthTexture); CleanupTexture(ref previousGIResult); CleanupTexture(ref previousCameraDepth); CleanupTexture(ref integerVolume); for (int i = 0; i < volumeTextures.Length; i++) { CleanupTexture(ref volumeTextures[i]); } CleanupTexture(ref secondaryIrradianceVolume); CleanupTexture(ref volumeTextureB); CleanupTexture(ref dummyVoxelTextureAAScaled); CleanupTexture(ref dummyVoxelTextureFixed); } private void Cleanup() { UnityEngine.Object.DestroyImmediate(material); UnityEngine.Object.DestroyImmediate(voxelCameraGO); UnityEngine.Object.DestroyImmediate(leftViewPoint); UnityEngine.Object.DestroyImmediate(topViewPoint); UnityEngine.Object.DestroyImmediate(shadowCamGameObject); initChecker = null; CleanupTextures(); } private void OnEnable() { InitCheck(); ResizeRenderTextures(); CheckSupport(); } private void OnDisable() { Cleanup(); } private void ResizeRenderTextures() { if ((bool)previousGIResult) { previousGIResult.DiscardContents(); previousGIResult.Release(); UnityEngine.Object.DestroyImmediate(previousGIResult); } int width = ((attachedCamera.pixelWidth == 0) ? 2 : attachedCamera.pixelWidth); int height = ((attachedCamera.pixelHeight == 0) ? 2 : attachedCamera.pixelHeight); previousGIResult = new RenderTexture(width, height, 0, RenderTextureFormat.ARGBHalf); previousGIResult.wrapMode = TextureWrapMode.Clamp; previousGIResult.filterMode = FilterMode.Bilinear; previousGIResult.useMipMap = true; previousGIResult.autoGenerateMips = false; previousGIResult.Create(); previousGIResult.hideFlags = HideFlags.HideAndDontSave; if ((bool)previousCameraDepth) { previousCameraDepth.DiscardContents(); previousCameraDepth.Release(); UnityEngine.Object.DestroyImmediate(previousCameraDepth); } previousCameraDepth = new RenderTexture(width, height, 0, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear); previousCameraDepth.wrapMode = TextureWrapMode.Clamp; previousCameraDepth.filterMode = FilterMode.Bilinear; previousCameraDepth.Create(); previousCameraDepth.hideFlags = HideFlags.HideAndDontSave; } private void ResizeSunShadowBuffer() { if ((bool)sunDepthTexture) { sunDepthTexture.DiscardContents(); sunDepthTexture.Release(); UnityEngine.Object.DestroyImmediate(sunDepthTexture); } sunDepthTexture = new RenderTexture(sunShadowResolution, sunShadowResolution, 16, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear); sunDepthTexture.wrapMode = TextureWrapMode.Clamp; sunDepthTexture.filterMode = FilterMode.Point; sunDepthTexture.Create(); sunDepthTexture.hideFlags = HideFlags.HideAndDontSave; } private void Update() { if (notReadyToRender) { return; } if (previousGIResult == null) { ResizeRenderTextures(); } if (previousGIResult.width != attachedCamera.pixelWidth || previousGIResult.height != attachedCamera.pixelHeight) { ResizeRenderTextures(); } if (sunShadowResolution != prevSunShadowResolution) { ResizeSunShadowBuffer(); } prevSunShadowResolution = sunShadowResolution; if (volumeTextures[0].width != (int)voxelResolution) { if (voxelResolution == VoxelResolution.low) { numMipLevels = 5; } if (voxelResolution == VoxelResolution.high) { numMipLevels = 6; } CreateVolumeTextures(); } if (dummyVoxelTextureAAScaled.width != dummyVoxelResolution) { ResizeDummyTexture(); } } private Matrix4x4 TransformViewMatrix(Matrix4x4 mat) { if (SystemInfo.usesReversedZBuffer) { mat[2, 0] = 0f - mat[2, 0]; mat[2, 1] = 0f - mat[2, 1]; mat[2, 2] = 0f - mat[2, 2]; mat[2, 3] = 0f - mat[2, 3]; } return mat; } private void OnPreRender() { InitCheck(); if (notReadyToRender) { return; } updateGIcounter++; if (!updateGI || (updateGIevery > 1 && updateGIcounter < updateGIevery && Time.fixedTime > 1f)) { return; } updateGIcounter = 0; RenderTexture active = RenderTexture.active; Shader.SetGlobalInt("SEGIVoxelAA", voxelAA ? 1 : 0); if (renderState == RenderState.Voxelize) { activeVolume = ((voxelFlipFlop == 0) ? volumeTextures[0] : volumeTextureB); previousActiveVolume = ((voxelFlipFlop == 0) ? volumeTextureB : volumeTextures[0]); float num = voxelSpaceSize / 8f; Vector3 vector = ((!followTransform) ? (base.transform.position + base.transform.forward * voxelSpaceSize / 4f) : followTransform.position); voxelSpaceOrigin = new Vector3(Mathf.Round(vector.x / num) * num, Mathf.Round(vector.y / num) * num, Mathf.Round(vector.z / num) * num); voxelSpaceOriginDelta = voxelSpaceOrigin - previousVoxelSpaceOrigin; Shader.SetGlobalVector("SEGIVoxelSpaceOriginDelta", voxelSpaceOriginDelta / voxelSpaceSize); previousVoxelSpaceOrigin = voxelSpaceOrigin; voxelCamera.enabled = false; voxelCamera.orthographic = true; voxelCamera.orthographicSize = voxelSpaceSize * 0.5f; voxelCamera.nearClipPlane = 0f; voxelCamera.farClipPlane = voxelSpaceSize; voxelCamera.depth = -2f; voxelCamera.renderingPath = RenderingPath.Forward; voxelCamera.clearFlags = CameraClearFlags.Color; voxelCamera.backgroundColor = Color.black; voxelCamera.cullingMask = giCullingMask; voxelCameraGO.transform.position = voxelSpaceOrigin - Vector3.forward * voxelSpaceSize * 0.5f; voxelCameraGO.transform.rotation = rotationFront; leftViewPoint.transform.position = voxelSpaceOrigin + Vector3.left * voxelSpaceSize * 0.5f; leftViewPoint.transform.rotation = rotationLeft; topViewPoint.transform.position = voxelSpaceOrigin + Vector3.up * voxelSpaceSize * 0.5f; topViewPoint.transform.rotation = rotationTop; Shader.SetGlobalMatrix("WorldToCamera", attachedCamera.worldToCameraMatrix); Shader.SetGlobalMatrix("SEGIVoxelViewFront", TransformViewMatrix(voxelCamera.transform.worldToLocalMatrix)); Shader.SetGlobalMatrix("SEGIVoxelViewLeft", TransformViewMatrix(leftViewPoint.transform.worldToLocalMatrix)); Shader.SetGlobalMatrix("SEGIVoxelViewTop", TransformViewMatrix(topViewPoint.transform.worldToLocalMatrix)); Shader.SetGlobalMatrix("SEGIWorldToVoxel", voxelCamera.worldToCameraMatrix); Shader.SetGlobalMatrix("SEGIVoxelProjection", voxelCamera.projectionMatrix); Shader.SetGlobalMatrix("SEGIVoxelProjectionInverse", voxelCamera.projectionMatrix.inverse); Shader.SetGlobalInt("SEGIVoxelResolution", (int)voxelResolution); Matrix4x4 value = shadowCam.projectionMatrix * shadowCam.worldToCameraMatrix * voxelCamera.cameraToWorldMatrix; Shader.SetGlobalMatrix("SEGIVoxelToGIProjection", value); Shader.SetGlobalVector("SEGISunlightVector", sun ? Vector3.Normalize(sun.transform.forward) : Vector3.up); Shader.SetGlobalColor("GISunColor", (sun == null) ? Color.black : new Color(Mathf.Pow(sun.color.r, 2.2f), Mathf.Pow(sun.color.g, 2.2f), Mathf.Pow(sun.color.b, 2.2f), Mathf.Pow(sun.intensity, 2.2f))); Shader.SetGlobalColor("SEGISkyColor", new Color(Mathf.Pow(skyColor.r * skyIntensity * 0.5f, 2.2f), Mathf.Pow(skyColor.g * skyIntensity * 0.5f, 2.2f), Mathf.Pow(skyColor.b * skyIntensity * 0.5f, 2.2f), Mathf.Pow(skyColor.a, 2.2f))); Shader.SetGlobalFloat("GIGain", giGain); Shader.SetGlobalFloat("SEGISecondaryBounceGain", infiniteBounces ? secondaryBounceGain : 0f); Shader.SetGlobalFloat("SEGISoftSunlight", softSunlight); Shader.SetGlobalInt("SEGISphericalSkylight", sphericalSkylight ? 1 : 0); Shader.SetGlobalInt("SEGIInnerOcclusionLayers", innerOcclusionLayers); if (sun != null) { shadowCam.cullingMask = giCullingMask; Vector3 position = voxelSpaceOrigin + Vector3.Normalize(-sun.transform.forward) * shadowSpaceSize * 0.5f * shadowSpaceDepthRatio; shadowCamTransform.position = position; shadowCamTransform.LookAt(voxelSpaceOrigin, Vector3.up); shadowCam.renderingPath = RenderingPath.Forward; shadowCam.depthTextureMode |= DepthTextureMode.None; shadowCam.orthographicSize = shadowSpaceSize; shadowCam.farClipPlane = shadowSpaceSize * 2f * shadowSpaceDepthRatio; Graphics.SetRenderTarget(sunDepthTexture); shadowCam.SetTargetBuffers(sunDepthTexture.colorBuffer, sunDepthTexture.depthBuffer); shadowCam.RenderWithShader(sunDepthShader, ""); Shader.SetGlobalTexture("SEGISunDepth", sunDepthTexture); } clearCompute.SetTexture(0, "RG0", integerVolume); clearCompute.SetInt("Res", (int)voxelResolution); clearCompute.Dispatch(0, (int)voxelResolution / 16, (int)voxelResolution / 16, 1); Graphics.SetRandomWriteTarget(1, integerVolume); voxelCamera.targetTexture = dummyVoxelTextureAAScaled; voxelCamera.RenderWithShader(voxelizationShader, ""); Graphics.ClearRandomWriteTargets(); transferIntsCompute.SetTexture(0, "Result", activeVolume); transferIntsCompute.SetTexture(0, "PrevResult", previousActiveVolume); transferIntsCompute.SetTexture(0, "RG0", integerVolume); transferIntsCompute.SetInt("VoxelAA", voxelAA ? 1 : 0); transferIntsCompute.SetInt("Resolution", (int)voxelResolution); transferIntsCompute.SetVector("VoxelOriginDelta", voxelSpaceOriginDelta / voxelSpaceSize * (float)voxelResolution); transferIntsCompute.Dispatch(0, (int)voxelResolution / 16, (int)voxelResolution / 16, 1); Shader.SetGlobalTexture("SEGIVolumeLevel0", activeVolume); if (voxelResolution == VoxelResolution.low) { numMipLevels = 5; } if (voxelResolution == VoxelResolution.high) { numMipLevels = 6; } for (int i = 0; i < numMipLevels - 1; i++) { if (i + 1 < volumeTextures.Length) { RenderTexture texture = volumeTextures[i]; if (i == 0) { texture = activeVolume; } int num2 = (int)voxelResolution / Mathf.RoundToInt(Mathf.Pow(2f, (float)i + 1f)); mipFilterCompute.SetInt("destinationRes", num2); mipFilterCompute.SetTexture(mipFilterKernel, "Source", texture); mipFilterCompute.SetTexture(mipFilterKernel, "Destination", volumeTextures[i + 1]); mipFilterCompute.Dispatch(mipFilterKernel, num2 / 8, num2 / 8, 1); Shader.SetGlobalTexture("SEGIVolumeLevel" + (i + 1), volumeTextures[i + 1]); } } voxelFlipFlop++; voxelFlipFlop %= 2; if (infiniteBounces) { renderState = RenderState.Bounce; } } else if (renderState == RenderState.Bounce) { clearCompute.SetTexture(0, "RG0", integerVolume); clearCompute.Dispatch(0, (int)voxelResolution / 16, (int)voxelResolution / 16, 1); Shader.SetGlobalInt("SEGISecondaryCones", secondaryCones); Shader.SetGlobalFloat("SEGISecondaryOcclusionStrength", secondaryOcclusionStrength); Graphics.SetRandomWriteTarget(1, integerVolume); voxelCamera.targetTexture = dummyVoxelTextureFixed; voxelCamera.RenderWithShader(voxelTracingShader, ""); Graphics.ClearRandomWriteTargets(); transferIntsCompute.SetTexture(1, "Result", secondaryIrradianceVolume); transferIntsCompute.SetTexture(1, "RG0", integerVolume); transferIntsCompute.SetInt("Resolution", (int)voxelResolution); transferIntsCompute.Dispatch(1, (int)voxelResolution / 16, (int)voxelResolution / 16, 1); Shader.SetGlobalTexture("SEGIVolumeTexture1", secondaryIrradianceVolume); renderState = RenderState.Voxelize; } RenderTexture.active = active; } [ImageEffectOpaque] private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (notReadyToRender) { Graphics.Blit(source, destination); return; } Shader.SetGlobalFloat("SEGIVoxelScaleFactor", voxelScaleFactor); material.SetMatrix("CameraToWorld", attachedCamera.cameraToWorldMatrix); material.SetMatrix("WorldToCamera", attachedCamera.worldToCameraMatrix); material.SetMatrix("ProjectionMatrixInverse", attachedCamera.projectionMatrix.inverse); material.SetMatrix("ProjectionMatrix", attachedCamera.projectionMatrix); material.SetInt("FrameSwitch", frameCounter); Shader.SetGlobalInt("SEGIFrameSwitch", frameCounter); material.SetVector("CameraPosition", base.transform.position); material.SetFloat("DeltaTime", Time.deltaTime); material.SetInt("StochasticSampling", stochasticSampling ? 1 : 0); material.SetInt("TraceDirections", cones); material.SetInt("TraceSteps", coneTraceSteps); material.SetFloat("TraceLength", coneLength); material.SetFloat("ConeSize", coneWidth); material.SetFloat("OcclusionStrength", occlusionStrength); material.SetFloat("OcclusionPower", occlusionPower); material.SetFloat("ConeTraceBias", coneTraceBias); material.SetFloat("GIGain", giGain); material.SetFloat("NearLightGain", nearLightGain); material.SetFloat("NearOcclusionStrength", nearOcclusionStrength); material.SetInt("DoReflections", doReflections ? 1 : 0); material.SetInt("HalfResolution", halfResolution ? 1 : 0); material.SetInt("ReflectionSteps", reflectionSteps); material.SetFloat("ReflectionOcclusionPower", reflectionOcclusionPower); material.SetFloat("SkyReflectionIntensity", skyReflectionIntensity); material.SetFloat("FarOcclusionStrength", farOcclusionStrength); material.SetFloat("FarthestOcclusionStrength", farthestOcclusionStrength); material.SetTexture("NoiseTexture", blueNoise[frameCounter % 64]); material.SetFloat("BlendWeight", temporalBlendWeight); if (visualizeVoxels) { Graphics.Blit(source, destination, material, Pass.VisualizeVoxels); return; } RenderTexture temporary = RenderTexture.GetTemporary(source.width / giRenderRes, source.height / giRenderRes, 0, RenderTextureFormat.ARGBHalf); RenderTexture temporary2 = RenderTexture.GetTemporary(source.width / giRenderRes, source.height / giRenderRes, 0, RenderTextureFormat.ARGBHalf); RenderTexture renderTexture = null; if (doReflections) { renderTexture = RenderTexture.GetTemporary(source.width, source.height, 0, RenderTextureFormat.ARGBHalf); } RenderTexture temporary3 = RenderTexture.GetTemporary(source.width / giRenderRes, source.height / giRenderRes, 0, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear); temporary3.filterMode = FilterMode.Point; RenderTexture temporary4 = RenderTexture.GetTemporary(source.width / giRenderRes, source.height / giRenderRes, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); temporary4.filterMode = FilterMode.Point; Graphics.Blit(source, temporary3, material, Pass.GetCameraDepthTexture); material.SetTexture("CurrentDepth", temporary3); Graphics.Blit(source, temporary4, material, Pass.GetWorldNormals); material.SetTexture("CurrentNormal", temporary4); material.SetTexture("PreviousGITexture", previousGIResult); Shader.SetGlobalTexture("PreviousGITexture", previousGIResult); material.SetTexture("PreviousDepth", previousCameraDepth); Graphics.Blit(source, temporary2, material, Pass.DiffuseTrace); if (doReflections) { Graphics.Blit(source, renderTexture, material, Pass.SpecularTrace); material.SetTexture("Reflections", renderTexture); } if (useBilateralFiltering) { material.SetVector("Kernel", new Vector2(0f, 1f)); Graphics.Blit(temporary2, temporary, material, Pass.BilateralBlur); material.SetVector("Kernel", new Vector2(1f, 0f)); Graphics.Blit(temporary, temporary2, material, Pass.BilateralBlur); material.SetVector("Kernel", new Vector2(0f, 1f)); Graphics.Blit(temporary2, temporary, material, Pass.BilateralBlur); material.SetVector("Kernel", new Vector2(1f, 0f)); Graphics.Blit(temporary, temporary2, material, Pass.BilateralBlur); } if (giRenderRes == 2) { RenderTexture.ReleaseTemporary(temporary); RenderTexture temporary5 = RenderTexture.GetTemporary(source.width, source.height, 0, RenderTextureFormat.ARGBHalf); RenderTexture temporary6 = RenderTexture.GetTemporary(source.width, source.height, 0, RenderTextureFormat.ARGBHalf); temporary2.filterMode = FilterMode.Point; Graphics.Blit(temporary2, temporary6); RenderTexture.ReleaseTemporary(temporary2); temporary6.filterMode = FilterMode.Point; temporary5.filterMode = FilterMode.Point; material.SetVector("Kernel", new Vector2(1f, 0f)); Graphics.Blit(temporary6, temporary5, material, Pass.BilateralUpsample); material.SetVector("Kernel", new Vector2(0f, 1f)); if (temporalBlendWeight < 1f) { Graphics.Blit(temporary5, temporary6); Graphics.Blit(temporary6, temporary5, material, Pass.TemporalBlend); Graphics.Blit(temporary5, previousGIResult); Graphics.Blit(source, previousCameraDepth, material, Pass.GetCameraDepthTexture); } material.SetTexture("GITexture", temporary5); Graphics.Blit(source, destination, material, visualizeGI ? Pass.VisualizeGI : Pass.BlendWithScene); RenderTexture.ReleaseTemporary(temporary5); RenderTexture.ReleaseTemporary(temporary6); } else { if (temporalBlendWeight < 1f) { Graphics.Blit(temporary2, temporary, material, Pass.TemporalBlend); Graphics.Blit(temporary, previousGIResult); Graphics.Blit(source, previousCameraDepth, material, Pass.GetCameraDepthTexture); } material.SetTexture("GITexture", (temporalBlendWeight < 1f) ? temporary : temporary2); Graphics.Blit(source, destination, material, visualizeGI ? Pass.VisualizeGI : Pass.BlendWithScene); RenderTexture.ReleaseTemporary(temporary); RenderTexture.ReleaseTemporary(temporary2); } RenderTexture.ReleaseTemporary(temporary3); RenderTexture.ReleaseTemporary(temporary4); if (visualizeSunDepthTexture) { Graphics.Blit(sunDepthTexture, destination); } if (doReflections) { RenderTexture.ReleaseTemporary(renderTexture); } material.SetMatrix("ProjectionPrev", attachedCamera.projectionMatrix); material.SetMatrix("ProjectionPrevInverse", attachedCamera.projectionMatrix.inverse); material.SetMatrix("WorldToCameraPrev", attachedCamera.worldToCameraMatrix); material.SetMatrix("CameraToWorldPrev", attachedCamera.cameraToWorldMatrix); material.SetVector("CameraPositionPrev", base.transform.position); frameCounter = (frameCounter + 1) % 64; } }