1820 lines
73 KiB
C#
1820 lines
73 KiB
C#
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
//using Unity.Mathematics;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.SceneManagement;
|
|||
|
using UnityEngine.Rendering;
|
|||
|
using UnityEngine.Experimental.Rendering;
|
|||
|
using UnityEngine.Rendering.Universal;
|
|||
|
using UnityEngine.XR;
|
|||
|
using Unity.Profiling;
|
|||
|
#if UNITY_EDITOR
|
|||
|
using UnityEditor;
|
|||
|
#endif
|
|||
|
|
|||
|
class VolumeRenderingUtils //Importing some functions from HDRP to have simular terms
|
|||
|
{
|
|||
|
public static float MeanFreePathFromExtinction(float extinction)
|
|||
|
{
|
|||
|
return 1.0f / extinction;
|
|||
|
}
|
|||
|
|
|||
|
public static float ExtinctionFromMeanFreePath(float meanFreePath)
|
|||
|
{
|
|||
|
return 1.0f / meanFreePath;
|
|||
|
}
|
|||
|
|
|||
|
public static Vector3 AbsorptionFromExtinctionAndScattering(float extinction, Vector3 scattering)
|
|||
|
{
|
|||
|
return new Vector3(extinction, extinction, extinction) - scattering;
|
|||
|
}
|
|||
|
|
|||
|
public static Vector3 ScatteringFromExtinctionAndAlbedo(float extinction, Vector3 albedo)
|
|||
|
{
|
|||
|
return extinction * albedo;
|
|||
|
}
|
|||
|
|
|||
|
public static Vector3 AlbedoFromMeanFreePathAndScattering(float meanFreePath, Vector3 scattering)
|
|||
|
{
|
|||
|
return meanFreePath * scattering;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//TODO: Add semi dynamic lighting which is generated in the clipmap and not previously baked out. Will need smarter clipmap gen to avoid hitching.
|
|||
|
//Add cascading clipmaps to have higher detail up close and include father clipping without exploding memory.
|
|||
|
//Convert this to a render feature. This should remove the need for the platform switcher too because that would be handled by the quality settings pipeline asset instead
|
|||
|
|
|||
|
|
|||
|
//[RequireComponent(typeof( Camera ) )]
|
|||
|
[ExecuteInEditMode]
|
|||
|
public class VolumetricRendering : MonoBehaviour
|
|||
|
{
|
|||
|
|
|||
|
#region variables
|
|||
|
static ProfilingSampler profileUpdateFunc = new ProfilingSampler("VolumetricRendering.UpdateFunc");
|
|||
|
static ProfilingSampler profileUpdateClipmap = new ProfilingSampler("VolumetricRendering.UpdateClipmap");
|
|||
|
|
|||
|
public float tempOffset = 0;
|
|||
|
Texture3D BlackTex; //Temp texture for
|
|||
|
Color clearColor = new Color(0.0f, 0.0f, 0.0f, 0f);
|
|||
|
|
|||
|
static VolumetricRendering lastClipmapUpdate;
|
|||
|
static VolumetricRendering lastBlur;
|
|||
|
static VolumetricRendering lastFroxelFog;
|
|||
|
static VolumetricRendering lastFroxelIntegrate;
|
|||
|
|
|||
|
|
|||
|
public Camera cam; //Main camera to base settings on
|
|||
|
private Camera activeCam;
|
|||
|
private UniversalAdditionalCameraData activeCamData;
|
|||
|
// Prevent script from trying to initialize itself twice
|
|||
|
bool hasInitialized;
|
|||
|
|
|||
|
// Sometimes, the volumetric register gets filled after the volumetric script initializes.
|
|||
|
// This means that the clipmaps will be empty until the player moves far enough to trigger
|
|||
|
// a clipmap update. Instead, set a bool that triggers the clipmaps to try to update every
|
|||
|
// frame until the volumtric registry contains >0 volumes
|
|||
|
bool VolumetricRegisterEmpty;
|
|||
|
|
|||
|
[HideInInspector] public bool VolumetricRegisterForceRefresh = false;
|
|||
|
|
|||
|
|
|||
|
// Debug counter to print a message every x frames
|
|||
|
int debugHeartBeatCount = 30;
|
|||
|
int debugHeartBeat = 0;
|
|||
|
|
|||
|
public VolumetricData volumetricData;
|
|||
|
[Range(0, 1)]
|
|||
|
public float reprojectionAmount = 0.95f;
|
|||
|
// [Tooltip("Does a final blur pass on the rendered fog")]
|
|||
|
// public bool FroxelBlur = false;
|
|||
|
|
|||
|
[HideInInspector]
|
|||
|
public enum BlurType {None, Gaussian};
|
|||
|
public BlurType FroxelBlur = BlurType.None;
|
|||
|
[Range(0, 1)]
|
|||
|
public float SliceDistributionUniformity = 0.5f;
|
|||
|
|
|||
|
[HideInInspector] public bool enableEditorPreview = false;
|
|||
|
//public Texture skytex;
|
|||
|
//[Header("Volumetric camera settings")]
|
|||
|
//[Tooltip("Near Clip plane")]
|
|||
|
//public float near = 1;
|
|||
|
//[Tooltip("Far Clip plane")]
|
|||
|
//public float far = 40;
|
|||
|
//[Tooltip("Resolution")]
|
|||
|
//public int FroxelWidthResolution = 128;
|
|||
|
//[Tooltip("Resolution")]
|
|||
|
//public int FroxelHeightResolution = 128;
|
|||
|
//[Tooltip("Resolution")]
|
|||
|
//public int FroxelDepthResolution = 64;
|
|||
|
////[Tooltip("Controls the bias of the froxel dispution. A value of 1 is linear. ")]
|
|||
|
////public float FroxelDispution;
|
|||
|
|
|||
|
//[Header("Prebaked clipmap settings")]
|
|||
|
//[Tooltip("Textile resolution per unit")]
|
|||
|
//public int ClipMapResolution = 128;
|
|||
|
//[Tooltip("Size of clipmap in units")]
|
|||
|
//public float ClipmapScale = 80;
|
|||
|
//[Tooltip("Distance (m) from previous sampling point to trigger resampling clipmap")]
|
|||
|
//public float ClipmapResampleThreshold = 1;
|
|||
|
|
|||
|
|
|||
|
Vector3 ClipmapTransform; //Have this follow the camera and resample when the camera moves enough
|
|||
|
Vector3 ClipmapCurrentPos; //chached location of previous sample point
|
|||
|
|
|||
|
private ComputeBuffer participatingMediaSphereBuffer;
|
|||
|
|
|||
|
[StructLayout(LayoutKind.Sequential)]
|
|||
|
struct MediaSphere
|
|||
|
{
|
|||
|
public Vector3 CenterPosition;
|
|||
|
public float LocalExtinction;
|
|||
|
public float LocalFalloff;
|
|||
|
public float LocalRange;
|
|||
|
}
|
|||
|
|
|||
|
private const int MediaSphereStride = (3 + 1 + 1 + 1) * sizeof(float);
|
|||
|
int MediaCount;
|
|||
|
|
|||
|
|
|||
|
//public Matrix4x4 randomatrix;
|
|||
|
|
|||
|
//Required shaders
|
|||
|
[SerializeField, HideInInspector] ComputeShader FroxelFogCompute;
|
|||
|
[SerializeField, HideInInspector] ComputeShader FroxelIntegrationCompute;
|
|||
|
[SerializeField, HideInInspector] ComputeShader FroxelLocalFogCompute;
|
|||
|
[SerializeField, HideInInspector] ComputeShader ClipmapCompute;
|
|||
|
[SerializeField, HideInInspector] ComputeShader BlurCompute;
|
|||
|
|
|||
|
//Texture buffers
|
|||
|
RenderTexture ClipmapBufferA; //Sampling and combining baked maps asynchronously
|
|||
|
RenderTexture ClipmapBufferB; //Sampling and combining baked maps asynchronously
|
|||
|
RenderTexture ClipmapBufferC; //Sampling and combining baked maps asynchronously
|
|||
|
RenderTexture ClipmapBufferD; //Sampling and combining baked maps asynchronously //TODO: get rid of this extra buffer and bool
|
|||
|
bool FlipClipBufferNear = true;
|
|||
|
bool FlipClipBufferFar = true;
|
|||
|
|
|||
|
|
|||
|
RenderTexture FroxelBufferA; //Single froxel projection use for scattering and history reprojection
|
|||
|
RenderTexture FroxelBufferB; //for history reprojection
|
|||
|
|
|||
|
RenderTexture IntegrationBuffer; //Integration and stereo reprojection
|
|||
|
// RenderTexture IntegrationBufferB; //Integration and stereo reprojection
|
|||
|
RenderTexture BlurBuffer; //blur
|
|||
|
RenderTexture BlurBufferB; //blur
|
|||
|
|
|||
|
RenderTexture VolumetricResult;
|
|||
|
|
|||
|
// This is a sequence of 7 equidistant numbers from 1/14 to 13/14.
|
|||
|
// Each of them is the centroid of the interval of length 2/14.
|
|||
|
// They've been rearranged in a sequence of pairs {small, large}, s.t. (small + large) = 1.
|
|||
|
// That way, the running average position is close to 0.5.
|
|||
|
// | 6 | 2 | 4 | 1 | 5 | 3 | 7 |
|
|||
|
// | | | | o | | | |
|
|||
|
// | | o | | x | | | |
|
|||
|
// | | x | | x | | o | |
|
|||
|
// | | x | o | x | | x | |
|
|||
|
// | | x | x | x | o | x | |
|
|||
|
// | o | x | x | x | x | x | |
|
|||
|
// | x | x | x | x | x | x | o |
|
|||
|
// | x | x | x | x | x | x | x |
|
|||
|
float[] m_zSeq = { 7.0f / 14.0f, 3.0f / 14.0f, 11.0f / 14.0f, 5.0f / 14.0f, 9.0f / 14.0f, 1.0f / 14.0f, 13.0f / 14.0f };
|
|||
|
|
|||
|
|
|||
|
// Ref: https://en.wikipedia.org/wiki/Close-packing_of_equal_spheres
|
|||
|
// The returned {x, y} coordinates (and all spheres) are all within the (-0.5, 0.5)^2 range.
|
|||
|
// The pattern has been rotated by 15 degrees to maximize the resolution along X and Y:
|
|||
|
// https://www.desmos.com/calculator/kcpfvltz7c
|
|||
|
static void GetHexagonalClosePackedSpheres7(Vector2[] coords)
|
|||
|
{
|
|||
|
|
|||
|
float r = 0.17054068870105443882f;
|
|||
|
float d = 2 * r;
|
|||
|
float s = r * Mathf.Sqrt(3);
|
|||
|
|
|||
|
// Try to keep the weighted average as close to the center (0.5) as possible.
|
|||
|
// (7)(5) ( )( ) ( )( ) ( )( ) ( )( ) ( )(o) ( )(x) (o)(x) (x)(x)
|
|||
|
// (2)(1)(3) ( )(o)( ) (o)(x)( ) (x)(x)(o) (x)(x)(x) (x)(x)(x) (x)(x)(x) (x)(x)(x) (x)(x)(x)
|
|||
|
// (4)(6) ( )( ) ( )( ) ( )( ) (o)( ) (x)( ) (x)(o) (x)(x) (x)(x)
|
|||
|
coords[0] = new Vector2(0, 0);
|
|||
|
coords[1] = new Vector2(-d, 0);
|
|||
|
coords[2] = new Vector2(d, 0);
|
|||
|
coords[3] = new Vector2(-r, -s);
|
|||
|
coords[4] = new Vector2(r, s);
|
|||
|
coords[5] = new Vector2(r, -s);
|
|||
|
coords[6] = new Vector2(-r, s);
|
|||
|
|
|||
|
// Rotate the sampling pattern by 15 degrees.
|
|||
|
const float cos15 = 0.96592582628906828675f;
|
|||
|
const float sin15 = 0.25881904510252076235f;
|
|||
|
|
|||
|
for (int i = 0; i < 7; i++)
|
|||
|
{
|
|||
|
Vector2 coord = coords[i];
|
|||
|
|
|||
|
coords[i].x = coord.x * cos15 - coord.y * sin15;
|
|||
|
coords[i].y = coord.x * sin15 + coord.y * cos15;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Vector2[] m_xySeq = new Vector2[7];
|
|||
|
|
|||
|
//camera.aspect no longer returns the XR aspect ratio but rather the final viewport's. Rather worthless now.
|
|||
|
float CamAspectRatio;
|
|||
|
//camera.fieldOfView is unreliable because the physical camera toggle will return the incorrect fov.
|
|||
|
// float CamFieldOfView = XRSettings.vi
|
|||
|
|
|||
|
|
|||
|
//Unity implemented their own cookie method, so we'll just tie into that system instead. This is no longer needed.
|
|||
|
/// Dynamic Light Projection///
|
|||
|
// [SerializeField, HideInInspector] List<Light> Lights; // TODO: Make this a smart dynamic list not living here
|
|||
|
// public struct LightObject
|
|||
|
// {
|
|||
|
// public Matrix4x4 LightProjectionMatrix;
|
|||
|
// public Vector3 LightPosition;
|
|||
|
// public Vector4 LightColor;
|
|||
|
// public int LightCookie; //TODO: Add general light cookie system to render engine
|
|||
|
// }
|
|||
|
|
|||
|
//Figure out how much data is in the struct above
|
|||
|
// int LightObjectStride = sizeof(float) * 4 * 4 + sizeof(float) * 3 + sizeof(float) * 4 + sizeof(int);
|
|||
|
// Texture2DArray LightProjectionTextures; // TODO: Make this a smart dynamic list pulling from light cookies
|
|||
|
// private static List<LightObject> LightObjects;
|
|||
|
// ComputeBuffer LightBuffer;
|
|||
|
|
|||
|
/// END Dynamic Light Projection///
|
|||
|
///
|
|||
|
|
|||
|
// public Texture2D BlueNoise; //Temp ref
|
|||
|
|
|||
|
//AABB
|
|||
|
|
|||
|
//Stored compute shader IDs and numbers
|
|||
|
|
|||
|
protected int ScatteringKernel = 0;
|
|||
|
protected int IntegrateKernel = 0;
|
|||
|
protected int BlurKernelX = 0;
|
|||
|
protected int BlurKernelY = 0;
|
|||
|
|
|||
|
Matrix4x4 matScaleBias;
|
|||
|
Vector3 ThreadsToDispatch;
|
|||
|
|
|||
|
//Stored shader variable name IDs
|
|||
|
|
|||
|
// Constants so the VolumetricConstant script can access the names
|
|||
|
// The texture/buffers associated with each name will get set
|
|||
|
// as shader globals just before the camera associated with this
|
|||
|
// script renders by the render pipeline, so only that camera uses
|
|||
|
// the volumetrics rendered by this script.
|
|||
|
public const string resultTextureName = "_VolumetricResult";
|
|||
|
public const string shaderCBName = "VolumetricsCB";
|
|||
|
public const string volumetricKWName = "_VOLUMETRICS_ENABLED";
|
|||
|
|
|||
|
int ID_VolumetricResult = Shader.PropertyToID(resultTextureName);
|
|||
|
int ID_VolumetricsCB = Shader.PropertyToID(shaderCBName); // not actually used now since this script doesn't set the constant buffer as the global
|
|||
|
|
|||
|
int ID_Result = Shader.PropertyToID("Result");
|
|||
|
int ID_InLightingTexture = Shader.PropertyToID("InLightingTexture");
|
|||
|
int ID_InTex = Shader.PropertyToID("InTex");
|
|||
|
int ID_LightProjectionTextureArray = Shader.PropertyToID("LightProjectionTextureArray");
|
|||
|
int ID_VolumetricClipmapTexture = Shader.PropertyToID("_VolumetricClipmapTexture");
|
|||
|
int ID_VolumetricClipmapTexture2 = Shader.PropertyToID("_VolumetricClipmapTexture2");
|
|||
|
int ID_PreResult = Shader.PropertyToID("PreResult");
|
|||
|
int ID_VolumeMap = Shader.PropertyToID("VolumeMap");
|
|||
|
int ID_PreviousFrameLighting = Shader.PropertyToID("PreviousFrameLighting");
|
|||
|
int ID_HistoryBuffer = Shader.PropertyToID("HistoryBuffer");
|
|||
|
int ID_LeftEyeMatrix = Shader.PropertyToID("LeftEyeMatrix");
|
|||
|
int ID_RightEyeMatrix = Shader.PropertyToID("RightEyeMatrix");
|
|||
|
int ID_ClipmapScale0 = Shader.PropertyToID("ClipmapScale");
|
|||
|
int ID_ClipmapScale1 = Shader.PropertyToID("_ClipmapScale");
|
|||
|
int ID_ClipmapScale2 = Shader.PropertyToID("_ClipmapScale2");
|
|||
|
int ID_ClipmapWorldPosition = Shader.PropertyToID("ClipmapWorldPosition");
|
|||
|
int ID_VBufferUnitDepthTexelSpacing = Shader.PropertyToID("_VBufferUnitDepthTexelSpacing");
|
|||
|
int ID_VolZBufferParams = Shader.PropertyToID("_VolZBufferParams");
|
|||
|
int ID_GlobalExtinction = Shader.PropertyToID("_GlobalExtinction");
|
|||
|
int ID_StaticLightMultiplier = Shader.PropertyToID("_StaticLightMultiplier");
|
|||
|
int ID_GlobalScattering = Shader.PropertyToID("_GlobalScattering");
|
|||
|
int ID_VolumeWorldSize = Shader.PropertyToID("VolumeWorldSize");
|
|||
|
int ID_VolumeWorldPosition = Shader.PropertyToID("VolumeWorldPosition");
|
|||
|
|
|||
|
private int ID_media_sphere_buffer_length = Shader.PropertyToID("media_sphere_buffer_length");
|
|||
|
private int ID_media_sphere_buffer = Shader.PropertyToID("media_sphere_buffer");
|
|||
|
|
|||
|
int ID_ClipMapGenKern;
|
|||
|
int ID_ClipMapClearKern;
|
|||
|
int ID_ClipMapHeightKern;
|
|||
|
|
|||
|
//Froxel Ids
|
|||
|
int PerFrameConstBufferID = Shader.PropertyToID("PerFrameCB");
|
|||
|
|
|||
|
//int CameraProjectionMatrixID = Shader.PropertyToID("CameraProjectionMatrix");
|
|||
|
//int TransposedCameraProjectionMatrixID = Shader.PropertyToID("TransposedCameraProjectionMatrix");
|
|||
|
//int inverseCameraProjectionMatrixID = Shader.PropertyToID("inverseCameraProjectionMatrix");
|
|||
|
int PreviousFrameMatrixID = Shader.PropertyToID("PreviousFrameMatrix");
|
|||
|
//int Camera2WorldID = Shader.PropertyToID("Camera2World");
|
|||
|
//int CameraPositionID = Shader.PropertyToID("CameraPosition");
|
|||
|
//Clipmap IDs
|
|||
|
//int CameraMotionVectorID = Shader.PropertyToID("CameraMotionVector");
|
|||
|
//int ClipmapTextureID = Shader.PropertyToID("_ClipmapTexture");
|
|||
|
//int ClipmapTextureID2 = Shader.PropertyToID("_VolumetricClipmapTexture"); //TODO: Make these two the same name
|
|||
|
|
|||
|
int ClipmapScaleID = Shader.PropertyToID("_ClipmapScale");
|
|||
|
int ClipmapTransformID = Shader.PropertyToID("_ClipmapPosition");
|
|||
|
|
|||
|
// int LightObjectsID = Shader.PropertyToID("LightObjects");
|
|||
|
|
|||
|
//Temp Jitter stuff
|
|||
|
int tempjitter = 0; //TEMP jitter switcher thing
|
|||
|
[Header("Extra variables"), Range(0, 1)]
|
|||
|
float[] jitters = new float[2] { 0.0f, 0.5f };
|
|||
|
|
|||
|
//GlobalKeyword VolumetricsKW;
|
|||
|
//Previous view matrix data
|
|||
|
|
|||
|
Matrix4x4 PreviousFrameMatrix = Matrix4x4.identity;
|
|||
|
Matrix4x4 LeftEyeMatrix;
|
|||
|
Matrix4x4 RightEyeMatrix;
|
|||
|
Vector3 PreviousCameraPosition;
|
|||
|
Vector3 previousPos;
|
|||
|
Quaternion previousQuat;
|
|||
|
Vector4 VolZBufferParams;
|
|||
|
|
|||
|
float ZPlaneTexelSpacing;
|
|||
|
//float Extinction;
|
|||
|
//Color ExtinctionColor;
|
|||
|
|
|||
|
//General fog settings
|
|||
|
// [HideInInspector]
|
|||
|
[Header("Base values that are overridden by Volumes")]
|
|||
|
public Color albedo = Color.white;
|
|||
|
// public Color extinctionTint = Color.white;
|
|||
|
public float meanFreePath = 15.0f;
|
|||
|
public float StaticLightMultiplier = 1.0f;
|
|||
|
|
|||
|
private ComputeBuffer ShaderConstantBuffer;
|
|||
|
private ComputeBuffer ComputePerFrameConstantBuffer;
|
|||
|
private ComputeBuffer StepAddPerFrameConstantBuffer;
|
|||
|
|
|||
|
[StructLayout(LayoutKind.Sequential)]
|
|||
|
struct ShaderConstants
|
|||
|
{
|
|||
|
public Matrix4x4 TransposedCameraProjectionMatrix;
|
|||
|
public Matrix4x4 CameraProjectionMatrix;
|
|||
|
public Vector4 _VBufferDistanceEncodingParams;
|
|||
|
public Vector4 _VolumetricResultDim;
|
|||
|
public Vector3 _VolCameraPos;
|
|||
|
}
|
|||
|
public const int ShaderConstantsCount = 43;
|
|||
|
public const int ShaderConstantsSize = ShaderConstantsCount * sizeof(float);
|
|||
|
|
|||
|
|
|||
|
[StructLayout(LayoutKind.Sequential)]
|
|||
|
struct ScatteringPerFrameConstants
|
|||
|
{
|
|||
|
public Matrix4x4 _VBufferCoordToViewDirWS;
|
|||
|
public Matrix4x4 _PrevViewProjMatrix;
|
|||
|
public Matrix4x4 _ViewMatrix;
|
|||
|
public Matrix4x4 TransposedCameraProjectionMatrix;
|
|||
|
public Matrix4x4 CameraProjectionMatrix;
|
|||
|
public Vector4 _VBufferDistanceEncodingParams;
|
|||
|
public Vector4 _VBufferDistanceDecodingParams;
|
|||
|
public Vector4 SeqOffset;
|
|||
|
public Vector4 CameraPosition;
|
|||
|
public Vector4 CameraMotionVector;
|
|||
|
}
|
|||
|
|
|||
|
private const int ScatterPerFrameCount = 100;
|
|||
|
|
|||
|
|
|||
|
[StructLayout(LayoutKind.Sequential)]
|
|||
|
struct StepAddPerFrameConstants
|
|||
|
{
|
|||
|
public Vector4 _VBufferDistanceDecodingParams;
|
|||
|
public Vector3 SeqOffset;
|
|||
|
}
|
|||
|
|
|||
|
private const int StepAddPerFrameCount = 7;
|
|||
|
|
|||
|
private static float[] VolStructToArray<T>(T rawData, int count, int size) where T : struct
|
|||
|
{
|
|||
|
var pinnedRawData = GCHandle.Alloc(rawData, GCHandleType.Pinned);
|
|||
|
try
|
|||
|
{
|
|||
|
var pinnedRawDataPtr = pinnedRawData.AddrOfPinnedObject();
|
|||
|
float[] data = new float[size];
|
|||
|
Marshal.Copy(pinnedRawDataPtr, data, 0, count);
|
|||
|
return data;
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
pinnedRawData.Free();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
private void Awake()
|
|||
|
{
|
|||
|
#if UNITY_EDITOR
|
|||
|
|
|||
|
if (Application.isPlaying || activeCam == null)
|
|||
|
{
|
|||
|
activeCam = cam;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//Debug.Log("Volumetric Editor On Awake");
|
|||
|
activeCam = SceneView.lastActiveSceneView.camera;
|
|||
|
}
|
|||
|
#else
|
|||
|
activeCam = cam;
|
|||
|
activeCamData = cam.GetComponent<UniversalAdditionalCameraData>();
|
|||
|
if (activeCam.usePhysicalProperties == true) Debug.LogError("Physical camera is not properlly supportted by Unity and WILL mess up XR calulations like voulmetrics and LoDs");
|
|||
|
// cam = GetComponent<Camera>();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void Start() {
|
|||
|
//#if !UNITY_EDITOR
|
|||
|
Intialize();
|
|||
|
//#endif
|
|||
|
}
|
|||
|
|
|||
|
// bool createdLightProjectionTexture = false;
|
|||
|
// void CheckCookieList()
|
|||
|
// {
|
|||
|
// if (LightProjectionTextures != null) return;
|
|||
|
// LightProjectionTextures = new Texture2DArray(1, 1, 1, TextureFormat.RGBA32, false);
|
|||
|
// LightProjectionTextures.hideFlags = HideFlags.DontSave;
|
|||
|
// LightProjectionTextures.name = activeCam.name + " Volumetric Light Cookies";
|
|||
|
// createdLightProjectionTexture = true;
|
|||
|
// //Debug.Log("Made blank cookie sheet");
|
|||
|
// }
|
|||
|
|
|||
|
//void dedbugRTC()
|
|||
|
//{
|
|||
|
// RenderTexture.active = (RenderTexture)skytex;
|
|||
|
// GL.Clear(true, true, Color.yellow);
|
|||
|
// RenderTexture.active = null;
|
|||
|
|
|||
|
//}
|
|||
|
//void SetSkyTexture(Texture cubemap)
|
|||
|
//{
|
|||
|
// // cam.RenderToCubemap((Cubemap)cubemap);
|
|||
|
// // dedbugRTC();
|
|||
|
// Shader.SetGlobalTexture("_SkyTexture", cubemap);
|
|||
|
//}
|
|||
|
|
|||
|
bool VerifyVolumetricRegisters()
|
|||
|
{
|
|||
|
//Add realtime light check here too
|
|||
|
if (VolumetricRegisters.volumetricAreas.Count > 0) //brute force check
|
|||
|
// if (VolumetricRegisters.volumetricAreas.Count > 0)
|
|||
|
{
|
|||
|
Debug.Log(VolumetricRegisters.volumetricAreas.Count + " Volumes ready to render");
|
|||
|
return true;
|
|||
|
}
|
|||
|
Debug.Log("No Volumetric volumes in " + SceneManager.GetActiveScene().name + ". Disabling froxel rendering.");
|
|||
|
this.enabled = false;
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
void CheckOverrideVolumes() //TODO: Is there a better way to do this?
|
|||
|
{
|
|||
|
//UniversalRenderPipeline.UpdateVolumeFramework(activeCam, activeCamData);
|
|||
|
|
|||
|
var stack = VolumeManager.instance.stack;
|
|||
|
|
|||
|
var Volumetrics = stack.GetComponent<Volumetrics>();
|
|||
|
if (Volumetrics != null)
|
|||
|
Volumetrics.PushFogShaderParameters();
|
|||
|
}
|
|||
|
|
|||
|
void IntializeBlur(RenderTextureDescriptor rtdiscrpt)
|
|||
|
{
|
|||
|
BlurBuffer = new RenderTexture(rtdiscrpt);
|
|||
|
BlurBuffer.name = activeCam.name + "_BlurBuffer";
|
|||
|
BlurBuffer.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat;
|
|||
|
BlurBuffer.enableRandomWrite = true;
|
|||
|
BlurBuffer.Create();
|
|||
|
Clear3DTexture(BlurBuffer);
|
|||
|
|
|||
|
|
|||
|
BlurBufferB = new RenderTexture(rtdiscrpt);
|
|||
|
BlurBuffer.name = activeCam.name + "_BlurBufferB";
|
|||
|
BlurBufferB.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat;
|
|||
|
BlurBufferB.enableRandomWrite = true;
|
|||
|
BlurBufferB.Create();
|
|||
|
Clear3DTexture(BlurBufferB);
|
|||
|
|
|||
|
BlurKernelX = BlurCompute.FindKernel("VolBlurX");
|
|||
|
BlurKernelY = BlurCompute.FindKernel("VolBlurY");
|
|||
|
}
|
|||
|
|
|||
|
void Intialize()
|
|||
|
{
|
|||
|
if (hasInitialized)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
if (cam == null)
|
|||
|
{
|
|||
|
Debug.LogWarning("Volumetric Rendering Script with no camera assigned, disabling");
|
|||
|
this.enabled = false;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
AssemblyReloadEvents.beforeAssemblyReload += CleanupOnReload;
|
|||
|
#endif
|
|||
|
activeCam = cam;
|
|||
|
activeCamData = activeCam?.GetComponent<UniversalAdditionalCameraData>();
|
|||
|
#if UNITY_EDITOR
|
|||
|
if (!Application.isPlaying && !enableEditorPreview)
|
|||
|
{
|
|||
|
//Debug.Log("Intialize disabled volumetrics");
|
|||
|
disable();
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif
|
|||
|
if (activeCamData == null)
|
|||
|
{
|
|||
|
activeCam = null;
|
|||
|
Debug.LogWarning("Volumetric Rendering: Assigned camera is missing a Universal Additional Camera Data component, disabling");
|
|||
|
this.enabled = false;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//Debug.Log("Volumetric Renderer Initialized");
|
|||
|
//DebugPrintTextureIDs();
|
|||
|
ShaderConstantBuffer = new ComputeBuffer(1, ShaderConstantsSize, ComputeBufferType.Constant);
|
|||
|
ComputePerFrameConstantBuffer = new ComputeBuffer(1, ScatterPerFrameCount * sizeof(float), ComputeBufferType.Constant);
|
|||
|
StepAddPerFrameConstantBuffer = new ComputeBuffer(1, StepAddPerFrameCount * sizeof(float), ComputeBufferType.Constant);
|
|||
|
int mediaCount = VolumetricRegisters.VolumetricMediaEntities.Count;
|
|||
|
MediaCount = Math.Max(mediaCount, 1);
|
|||
|
participatingMediaSphereBuffer = new ComputeBuffer(MediaCount, MediaSphereStride, ComputeBufferType.Structured);
|
|||
|
|
|||
|
|
|||
|
//activeCameraState = activeCam.isActiveAndEnabled;
|
|||
|
CheckOverrideVolumes();
|
|||
|
// if (VerifyVolumetricRegisters() == false) return; //Check registers to see if there's anything to render. If not, then disable system. TODO: Remove this
|
|||
|
// CheckCookieList();
|
|||
|
|
|||
|
|
|||
|
// SetSkyTexture( skytex);
|
|||
|
|
|||
|
//Making prescaled matrix
|
|||
|
matScaleBias = Matrix4x4.identity;
|
|||
|
matScaleBias.m00 = -0.5f;
|
|||
|
matScaleBias.m11 = -0.5f;
|
|||
|
matScaleBias.m22 = 0.5f;
|
|||
|
matScaleBias.m03 = 0.5f;
|
|||
|
matScaleBias.m13 = 0.5f;
|
|||
|
matScaleBias.m23 = 0.5f;
|
|||
|
|
|||
|
//Create 3D Render Texture 1
|
|||
|
RenderTextureDescriptor rtdiscrpt = new RenderTextureDescriptor();
|
|||
|
rtdiscrpt.enableRandomWrite = true;
|
|||
|
rtdiscrpt.dimension = TextureDimension.Tex3D;
|
|||
|
rtdiscrpt.width = volumetricData.FroxelWidthResolution;
|
|||
|
rtdiscrpt.height = volumetricData.FroxelHeightResolution;
|
|||
|
rtdiscrpt.volumeDepth = volumetricData.FroxelDepthResolution;
|
|||
|
rtdiscrpt.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat;
|
|||
|
rtdiscrpt.msaaSamples = 1;
|
|||
|
|
|||
|
FroxelBufferA = new RenderTexture(rtdiscrpt);
|
|||
|
FroxelBufferA.name = activeCam.name + "_FroxelBufferA";
|
|||
|
|
|||
|
FroxelBufferA.Create();
|
|||
|
|
|||
|
//Ugh... extra android buffer mess. Can I use a custom RT double buffer instead?
|
|||
|
FroxelBufferB = new RenderTexture(rtdiscrpt);
|
|||
|
FroxelBufferB.name = activeCam.name + "_FroxelBufferB";
|
|||
|
FroxelBufferB.Create();
|
|||
|
|
|||
|
rtdiscrpt.width = volumetricData.FroxelWidthResolution * 2; // Make double wide texture for stereo use. Make smarter for non VR use case?
|
|||
|
IntegrationBuffer = new RenderTexture(rtdiscrpt);
|
|||
|
IntegrationBuffer.name = activeCam.name + "_IntegrationBuffer";
|
|||
|
// IntegrationBuffer.format = RenderTextureFormat.ARGB32;
|
|||
|
IntegrationBuffer.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat;
|
|||
|
IntegrationBuffer.filterMode = FilterMode.Trilinear;
|
|||
|
IntegrationBuffer.enableRandomWrite = true;
|
|||
|
IntegrationBuffer.Create();
|
|||
|
|
|||
|
//IntegrationBufferB = new RenderTexture(rtdiscrpt);
|
|||
|
//IntegrationBufferB.format = RenderTextureFormat.ARGB32;
|
|||
|
//IntegrationBufferB.enableRandomWrite = true;
|
|||
|
//IntegrationBufferB.Create();
|
|||
|
|
|||
|
//Extinction = VolumeRenderingUtils.ExtinctionFromMeanFreePath(meanFreePath);
|
|||
|
//ExtinctionColor = albedo * Extinction;
|
|||
|
|
|||
|
if (FroxelBlur == BlurType.Gaussian) IntializeBlur(rtdiscrpt);
|
|||
|
|
|||
|
// LightObjects = new List<LightObject>();
|
|||
|
|
|||
|
ScatteringKernel = FroxelFogCompute.FindKernel("Scatter");
|
|||
|
|
|||
|
ZPlaneTexelSpacing = ComputZPlaneTexelSpacing(1, activeCam.fieldOfView, volumetricData.FroxelHeightResolution);
|
|||
|
|
|||
|
|
|||
|
//UpdateClipmap(Clipmap.Far);
|
|||
|
// FroxelFogCompute.SetTexture(ScatteringKernel, ClipmapTextureID, ClipmapBufferA);
|
|||
|
// temp light cookie array. TODO: Make dynamic. Add to lighting engine too.
|
|||
|
// FroxelFogCompute.SetTexture(FogFroxelKernel, "BlueNoise", BlueNoise); // temp light cookie array. TODO: Make dynamic. Add to lighting engine too.
|
|||
|
|
|||
|
///Second compute pass setup
|
|||
|
|
|||
|
IntegrateKernel = FroxelIntegrationCompute.FindKernel("StepAdd");
|
|||
|
|
|||
|
|
|||
|
//Make view projection matricies
|
|||
|
|
|||
|
Matrix4x4 CenterProjectionMatrix = matScaleBias * Matrix4x4.Perspective(activeCam.fieldOfView, CamAspectRatio, volumetricData.near, volumetricData.far);
|
|||
|
Matrix4x4 LeftProjectionMatrix = matScaleBias * Matrix4x4.Perspective(activeCam.fieldOfView, CamAspectRatio, volumetricData.near, volumetricData.far) * Matrix4x4.Translate(new Vector3(activeCam.stereoSeparation * 0.5f, 0, 0)); //temp ipd scaler. Combine factors when confirmed
|
|||
|
Matrix4x4 RightProjectionMatrix = matScaleBias * Matrix4x4.Perspective(activeCam.fieldOfView, CamAspectRatio, volumetricData.near, volumetricData.far) * Matrix4x4.Translate(new Vector3(-activeCam.stereoSeparation * 0.5f, 0, 0));
|
|||
|
|
|||
|
|
|||
|
Matrix4x4 CenterProjectionMatrixInverse = CenterProjectionMatrix.inverse;
|
|||
|
LeftEyeMatrix = LeftProjectionMatrix * CenterProjectionMatrixInverse;
|
|||
|
RightEyeMatrix = RightProjectionMatrix * CenterProjectionMatrixInverse;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//Global Variable setup
|
|||
|
|
|||
|
if (FroxelBlur == BlurType.Gaussian)
|
|||
|
{
|
|||
|
//Shader.SetGlobalTexture(ID_VolumetricResult, BlurBufferB);
|
|||
|
VolumetricResult = BlurBufferB;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//FroxelFogCompute.SetTexture(ScatteringKernel, ID_VolumetricResult, IntegrationBuffer);
|
|||
|
//Shader.SetGlobalTexture(ID_VolumetricResult, IntegrationBuffer);
|
|||
|
VolumetricResult = IntegrationBuffer;
|
|||
|
}
|
|||
|
|
|||
|
ThreadsToDispatch = new Vector3(
|
|||
|
Mathf.Max(Mathf.CeilToInt(volumetricData.FroxelWidthResolution / 4.0f), 1.0f),
|
|||
|
Mathf.Max(Mathf.CeilToInt(volumetricData.FroxelHeightResolution / 4.0f), 1.0f),
|
|||
|
Mathf.Max(Mathf.CeilToInt(volumetricData.FroxelDepthResolution / 4.0f), 1.0f)
|
|||
|
);
|
|||
|
|
|||
|
// ComputZPlaneTexelSpacing(1.0f, vFoV, parameters.resolution.y);
|
|||
|
|
|||
|
// Unused as far as I can tell, declared in the VolumetricCore but not actually used
|
|||
|
//Shader.SetGlobalVector("_VolumePlaneSettings", new Vector4(volumetricData.near, volumetricData.far, volumetricData.far - volumetricData.near, volumetricData.near * volumetricData.far));
|
|||
|
|
|||
|
VolZBufferParams = new Vector4();
|
|||
|
VolZBufferParams.x = 1.0f - volumetricData.far / volumetricData.near;
|
|||
|
VolZBufferParams.y = volumetricData.far / volumetricData.near;
|
|||
|
VolZBufferParams.z = VolZBufferParams.x / volumetricData.far;
|
|||
|
VolZBufferParams.w = VolZBufferParams.y / volumetricData.far;
|
|||
|
|
|||
|
|
|||
|
ID_ClipMapGenKern = ClipmapCompute.FindKernel("ClipMapGen");
|
|||
|
ID_ClipMapClearKern = ClipmapCompute.FindKernel("ClipMapClear");
|
|||
|
ID_ClipMapHeightKern = ClipmapCompute.FindKernel("ClipMapHeight");
|
|||
|
|
|||
|
//Debug.Log("Dispatching " + ThreadsToDispatch);
|
|||
|
|
|||
|
SkyManager.CheckSky();
|
|||
|
|
|||
|
Clear3DTexture(FroxelBufferA);
|
|||
|
Clear3DTexture(FroxelBufferB);
|
|||
|
Clear3DTexture(IntegrationBuffer);
|
|||
|
|
|||
|
SetVariables();
|
|||
|
SetupClipmap();
|
|||
|
UpdateClipmaps();
|
|||
|
SetFroxelFogUniforms(true);
|
|||
|
SetFroxelIntegrationUniforms(true);
|
|||
|
SetBlurUniforms(true);
|
|||
|
|
|||
|
hasInitialized = true;
|
|||
|
VolumetricRegisters.RegisterVolumetricRenderer(this);
|
|||
|
//RenderPipelineManager.beginCameraRendering += UpdatePreRender;
|
|||
|
}
|
|||
|
|
|||
|
void SetFroxelFogUniforms(bool forceUpdate = false)
|
|||
|
{
|
|||
|
if (lastFroxelFog != this || forceUpdate)
|
|||
|
{
|
|||
|
FroxelFogCompute.SetFloat(ID_VBufferUnitDepthTexelSpacing, ZPlaneTexelSpacing);
|
|||
|
FroxelFogCompute.SetFloat(ID_ClipmapScale1, volumetricData.ClipmapScale);
|
|||
|
FroxelFogCompute.SetFloat(ID_ClipmapScale2, volumetricData.ClipmapScale2);
|
|||
|
//FroxelFogCompute.SetFloat(ID_GlobalExtinction, Extinction);
|
|||
|
//FroxelFogCompute.SetFloat(ID_StaticLightMultiplier, StaticLightMultiplier);
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_Result, FroxelBufferA);
|
|||
|
// CheckCookieList();
|
|||
|
// FroxelFogCompute.SetTexture(ScatteringKernel, ID_LightProjectionTextureArray, LightProjectionTextures);
|
|||
|
FroxelFogCompute.SetConstantBuffer(PerFrameConstBufferID, StepAddPerFrameConstantBuffer, 0, StepAddPerFrameCount * sizeof(float));
|
|||
|
lastFroxelFog = this;
|
|||
|
}
|
|||
|
if (lastClipmapUpdate != this || forceUpdate)
|
|||
|
{
|
|||
|
FroxelFogCompute.SetFloat(ClipmapScaleID, volumetricData.ClipmapScale);
|
|||
|
FroxelFogCompute.SetVector(ClipmapTransformID, ClipmapTransform);
|
|||
|
if (FlipClipBufferNear)
|
|||
|
{
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_VolumetricClipmapTexture, ClipmapBufferB);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_VolumetricClipmapTexture, ClipmapBufferA);
|
|||
|
}
|
|||
|
if (FlipClipBufferFar)
|
|||
|
{
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_VolumetricClipmapTexture2, ClipmapBufferC);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_VolumetricClipmapTexture2, ClipmapBufferD);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void SetFroxelIntegrationUniforms(bool forceUpdate = false)
|
|||
|
{
|
|||
|
if (lastFroxelIntegrate != this || forceUpdate)
|
|||
|
{
|
|||
|
FroxelIntegrationCompute.SetMatrix(ID_LeftEyeMatrix, LeftEyeMatrix);
|
|||
|
FroxelIntegrationCompute.SetMatrix(ID_RightEyeMatrix, RightEyeMatrix);
|
|||
|
FroxelIntegrationCompute.SetVector(ID_VolZBufferParams, VolZBufferParams);
|
|||
|
//FroxelIntegrationCompute.SetVector(ID_GlobalScattering, ExtinctionColor);
|
|||
|
FroxelIntegrationCompute.SetTexture(IntegrateKernel, ID_Result, IntegrationBuffer);
|
|||
|
FroxelIntegrationCompute.SetTexture(IntegrateKernel, ID_InLightingTexture, FroxelBufferA);
|
|||
|
FroxelIntegrationCompute.SetConstantBuffer(PerFrameConstBufferID, StepAddPerFrameConstantBuffer, 0, StepAddPerFrameCount * sizeof(float));
|
|||
|
lastFroxelIntegrate = this;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void SetBlurUniforms(bool forceUpdate = false)
|
|||
|
{
|
|||
|
if (FroxelBlur == BlurType.Gaussian && (lastBlur != this || forceUpdate))
|
|||
|
{
|
|||
|
BlurCompute.SetTexture(BlurKernelX, ID_InTex, IntegrationBuffer);
|
|||
|
BlurCompute.SetTexture(BlurKernelX, ID_Result, BlurBuffer);
|
|||
|
BlurCompute.SetTexture(BlurKernelY, ID_InTex, BlurBuffer);
|
|||
|
BlurCompute.SetTexture(BlurKernelY, ID_Result, BlurBufferB);
|
|||
|
lastBlur = this;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ClearAllBuffers()
|
|||
|
{
|
|||
|
ClearClipmap(ClipmapBufferA);
|
|||
|
ClearClipmap(ClipmapBufferB);
|
|||
|
ClearClipmap(ClipmapBufferC);
|
|||
|
ClearClipmap(ClipmapBufferD);
|
|||
|
|
|||
|
Clear3DTexture(FroxelBufferA);
|
|||
|
Clear3DTexture(FroxelBufferB);
|
|||
|
Clear3DTexture(IntegrationBuffer);
|
|||
|
}
|
|||
|
|
|||
|
// void UpdateLights()
|
|||
|
// {
|
|||
|
// LightObjects.Clear(); //clear and rebuild for now. TODO: Make a smarter constructor
|
|||
|
// if (LightBuffer != null) LightBuffer.Release();
|
|||
|
//
|
|||
|
// for (int i = 0; i < Lights.Count; i++)
|
|||
|
// {
|
|||
|
// LightObject lightObject = new LightObject();
|
|||
|
// lightObject.LightPosition = Lights[i].transform.position;
|
|||
|
// lightObject.LightColor = new Color(
|
|||
|
// Lights[i].color.r * Lights[i].intensity,
|
|||
|
// Lights[i].color.g * Lights[i].intensity,
|
|||
|
// Lights[i].color.b * Lights[i].intensity,
|
|||
|
// Lights[i].color.a);
|
|||
|
// lightObject.LightProjectionMatrix = matScaleBias
|
|||
|
// * Matrix4x4.Perspective(Lights[i].spotAngle, 1, 0.1f, Lights[i].range)
|
|||
|
// * Matrix4x4.Rotate(Lights[i].transform.rotation).inverse;
|
|||
|
//
|
|||
|
// LightObjects.Add(lightObject);
|
|||
|
// }
|
|||
|
// LightBuffer = new ComputeBuffer(LightObjects.Count, LightObjectStride);
|
|||
|
// LightBuffer.SetData(LightObjects);
|
|||
|
// FroxelFogCompute.SetBuffer(ScatteringKernel, LightObjectsID, LightBuffer);
|
|||
|
// }
|
|||
|
|
|||
|
|
|||
|
#region Clipmap funtions
|
|||
|
void SetupClipmap()
|
|||
|
{
|
|||
|
|
|||
|
RenderTextureDescriptor ClipRTdiscrpt = new RenderTextureDescriptor();
|
|||
|
ClipRTdiscrpt.enableRandomWrite = true;
|
|||
|
ClipRTdiscrpt.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
|
|||
|
ClipRTdiscrpt.width = volumetricData.ClipMapResolution;
|
|||
|
ClipRTdiscrpt.height = volumetricData.ClipMapResolution;
|
|||
|
ClipRTdiscrpt.volumeDepth = volumetricData.ClipMapResolution;
|
|||
|
ClipRTdiscrpt.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R16G16B16A16_SFloat;
|
|||
|
ClipRTdiscrpt.msaaSamples = 1;
|
|||
|
|
|||
|
ClipmapBufferA = new RenderTexture(ClipRTdiscrpt);
|
|||
|
ClipmapBufferA.name = activeCam.name + "_ClipmapBufferA";
|
|||
|
ClipmapBufferA.Create();
|
|||
|
ClipmapBufferB = new RenderTexture(ClipRTdiscrpt);
|
|||
|
ClipmapBufferB.name = activeCam.name + "_ClipmapBufferB";
|
|||
|
ClipmapBufferB.Create();
|
|||
|
ClipmapBufferC = new RenderTexture(ClipRTdiscrpt);
|
|||
|
ClipmapBufferC.name = activeCam.name + "_ClipmapBufferC";
|
|||
|
ClipmapBufferC.Create();
|
|||
|
ClipmapBufferD = new RenderTexture(ClipRTdiscrpt);
|
|||
|
ClipmapBufferD.name = activeCam.name + "_ClipmapBufferD";
|
|||
|
ClipmapBufferD.Create();
|
|||
|
|
|||
|
////TODO: Loop through and remove one of the buffers
|
|||
|
|
|||
|
ClearClipmap(ClipmapBufferA);
|
|||
|
ClearClipmap(ClipmapBufferB);
|
|||
|
ClearClipmap(ClipmapBufferC);
|
|||
|
ClearClipmap(ClipmapBufferD);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void ClearClipmap(RenderTexture buffer)
|
|||
|
{
|
|||
|
int clipMapDispatchNum = Mathf.Max(volumetricData.ClipMapResolution / 4, 1);
|
|||
|
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapClearKern, ID_Result, buffer);
|
|||
|
ClipmapCompute.Dispatch(ID_ClipMapClearKern, clipMapDispatchNum, clipMapDispatchNum, clipMapDispatchNum);
|
|||
|
}
|
|||
|
|
|||
|
bool ClipFar = false;
|
|||
|
void CheckClipmap() //Check distance from previous sample and recalulate if over threshold. TODO: make it resample chunks
|
|||
|
{
|
|||
|
|
|||
|
if (Vector3.Distance(ClipmapCurrentPos, activeCam.transform.position) > volumetricData.ClipmapResampleThreshold || VolumetricRegisterEmpty || VolumetricRegisterForceRefresh)
|
|||
|
{
|
|||
|
//TODO: seperate the frames where this is rendered
|
|||
|
UpdateClipmaps();
|
|||
|
//if (ClipFar == false) UpdateClipmap(Clipmap.Near);
|
|||
|
//else {
|
|||
|
// UpdateClipmap(Clipmap.Far);
|
|||
|
// ClipFar = false;
|
|||
|
// };
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void UpdateClipmaps()
|
|||
|
{
|
|||
|
//Debug.Log("Clipmap Update: " + activeCam.transform.position);
|
|||
|
if (VolumetricRegisters.volumetricAreas.Count == 0)
|
|||
|
{
|
|||
|
VolumetricRegisterEmpty = true;
|
|||
|
return;
|
|||
|
}
|
|||
|
else if (VolumetricRegisterEmpty)
|
|||
|
{
|
|||
|
VolumetricRegisterEmpty = false;
|
|||
|
}
|
|||
|
UpdateClipmap(Clipmap.Near);
|
|||
|
UpdateClipmap(Clipmap.Far);
|
|||
|
if (VolumetricRegisterForceRefresh) VolumetricRegisterForceRefresh = false;
|
|||
|
}
|
|||
|
|
|||
|
public enum Clipmap { Near,Far};
|
|||
|
|
|||
|
|
|||
|
public void UpdateClipmap(Clipmap clipmap)
|
|||
|
{
|
|||
|
ClipmapTransform = activeCam.transform.position;
|
|||
|
|
|||
|
float farscale = volumetricData.ClipmapScale2;
|
|||
|
|
|||
|
RenderTexture BufferA;
|
|||
|
RenderTexture BufferB;
|
|||
|
//TODO: bake out variables at start to avoid extra math per clip gen
|
|||
|
|
|||
|
//ClipmapCompute.SetFloat(ID_GlobalExtinction, Extinction);
|
|||
|
|
|||
|
if (clipmap == Clipmap.Near)
|
|||
|
{
|
|||
|
BufferA = ClipmapBufferB;
|
|||
|
BufferB = ClipmapBufferA;
|
|||
|
ClipmapCompute.SetFloat(ID_ClipmapScale0, volumetricData.ClipmapScale);
|
|||
|
ClipmapCompute.SetVector(ID_ClipmapWorldPosition, ClipmapTransform - (0.5f * volumetricData.ClipmapScale * Vector3.one));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
BufferA = ClipmapBufferC;
|
|||
|
BufferB = ClipmapBufferD;
|
|||
|
|
|||
|
ClipmapCompute.SetFloat(ID_ClipmapScale0, volumetricData.ClipmapScale2);
|
|||
|
ClipmapCompute.SetVector(ID_ClipmapWorldPosition, ClipmapTransform - (0.5f * volumetricData.ClipmapScale2 * Vector3.one));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//Clipmap variables
|
|||
|
//ClipmapCompute.SetVector("ClipmapWorldPosition", ClipmapTransform - (0.5f * volumetricData.ClipmapScale * Vector3.one));
|
|||
|
// ClipmapCompute.SetFloat("ClipmapScale", volumetricData.ClipmapScale);
|
|||
|
|
|||
|
bool FlipClipBuffer = false;
|
|||
|
//Clear previous capture
|
|||
|
int clipMapDispatchNum = Mathf.Max(volumetricData.ClipMapResolution / 4, 1);
|
|||
|
// ClipmapCompute.SetVector("clearColor", RenderSettings.ambientProbe.Evaluate);
|
|||
|
|
|||
|
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapClearKern, ID_Result, BufferA);
|
|||
|
//Debug.Log("Dispatching 0");
|
|||
|
ClipmapCompute.Dispatch(ID_ClipMapClearKern, clipMapDispatchNum, clipMapDispatchNum, clipMapDispatchNum);
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapClearKern, ID_Result, BufferB);
|
|||
|
//Debug.Log("Dispatching 1");
|
|||
|
ClipmapCompute.Dispatch(ID_ClipMapClearKern, clipMapDispatchNum, clipMapDispatchNum, clipMapDispatchNum);
|
|||
|
|
|||
|
//ClipmapCompute.SetFloat("VolumeDensity", 0); //
|
|||
|
|
|||
|
//Loop through bake texture volumes and put into clipmap //TODO: Add pass for static unbaked elements
|
|||
|
//Debug.Log("VolumetricRegisters.volumetricAreas.Count: " + VolumetricRegisters.volumetricAreas.Count);
|
|||
|
for (int i = 0; i < VolumetricRegisters.volumetricAreas.Count; i++)
|
|||
|
{
|
|||
|
FlipClipBuffer = !FlipClipBuffer;
|
|||
|
|
|||
|
if (FlipClipBuffer)
|
|||
|
{
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapGenKern, ID_PreResult, BufferB);
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapGenKern, ID_Result, BufferA);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapGenKern, ID_PreResult, BufferA);
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapGenKern, ID_Result, BufferB);
|
|||
|
}
|
|||
|
|
|||
|
//Volumetric variables
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapGenKern, ID_VolumeMap, VolumetricRegisters.volumetricAreas[i].bakedTexture);
|
|||
|
ClipmapCompute.SetVector(ID_VolumeWorldSize, VolumetricRegisters.volumetricAreas[i].NormalizedScale);
|
|||
|
ClipmapCompute.SetVector(ID_VolumeWorldPosition, VolumetricRegisters.volumetricAreas[i].Corner);
|
|||
|
//Debug.Log("Dispatching 2");
|
|||
|
ClipmapCompute.Dispatch(ID_ClipMapGenKern, clipMapDispatchNum, clipMapDispatchNum, clipMapDispatchNum);
|
|||
|
}
|
|||
|
|
|||
|
//Height Densitiy
|
|||
|
|
|||
|
//FlipClipBuffer = !FlipClipBuffer;
|
|||
|
|
|||
|
//if (FlipClipBuffer)
|
|||
|
//{
|
|||
|
// ClipmapCompute.SetTexture(HeightClipmapKernal, "PreResult", BufferB);
|
|||
|
// ClipmapCompute.SetTexture(HeightClipmapKernal, "Result", BufferA);
|
|||
|
//}
|
|||
|
//else
|
|||
|
//{
|
|||
|
// ClipmapCompute.SetTexture(HeightClipmapKernal, "PreResult", BufferA);
|
|||
|
// ClipmapCompute.SetTexture(HeightClipmapKernal, "Result", BufferB);
|
|||
|
//}
|
|||
|
|
|||
|
////Volumetric variables
|
|||
|
////ClipmapCompute.SetTexture(HeightClipmapKernal, "VolumeMap", VolumetricRegisters.volumetricAreas[i].bakedTexture);
|
|||
|
////ClipmapCompute.SetVector("VolumeWorldSize", VolumetricRegisters.volumetricAreas[i].NormalizedScale);
|
|||
|
////ClipmapCompute.SetVector("VolumeWorldPosition", VolumetricRegisters.volumetricAreas[i].Corner);
|
|||
|
|
|||
|
//ClipmapCompute.Dispatch(HeightClipmapKernal, clipMapDispatchNum, clipMapDispatchNum, clipMapDispatchNum);
|
|||
|
|
|||
|
//End Height Densitiy
|
|||
|
|
|||
|
if (FlipClipBuffer)
|
|||
|
{
|
|||
|
SetClipmap(BufferA, volumetricData.ClipmapScale, ClipmapTransform, clipmap);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SetClipmap(BufferB, volumetricData.ClipmapScale, ClipmapTransform, clipmap);
|
|||
|
}
|
|||
|
|
|||
|
switch (clipmap)
|
|||
|
{
|
|||
|
case Clipmap.Near:
|
|||
|
FlipClipBufferNear = FlipClipBuffer;
|
|||
|
break;
|
|||
|
case Clipmap.Far:
|
|||
|
FlipClipBufferFar = FlipClipBuffer;
|
|||
|
break;
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ClipmapCurrentPos = ClipmapTransform; //Set History
|
|||
|
lastClipmapUpdate = this;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void SetClipmap(RenderTexture ClipmapTexture, float ClipmapScale, Vector3 ClipmapTransform, Clipmap clipmap)
|
|||
|
{
|
|||
|
FroxelFogCompute.SetFloat(ClipmapScaleID, ClipmapScale);
|
|||
|
FroxelFogCompute.SetVector(ClipmapTransformID, ClipmapTransform);
|
|||
|
|
|||
|
if (clipmap == Clipmap.Far)
|
|||
|
{
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_VolumetricClipmapTexture2, ClipmapTexture);
|
|||
|
// Debug.Log("Added clipmap far :" + ClipmapTexture.name);
|
|||
|
}
|
|||
|
else
|
|||
|
{ //TODO COMBINE THESE
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_VolumetricClipmapTexture, ClipmapTexture); //Set clipmap for
|
|||
|
//FroxelFogCompute.SetTexture(ScatteringKernel, ClipmapTextureID, ClipmapTexture); //Set clipmap for
|
|||
|
}
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
bool FlopIntegralBuffer = false;
|
|||
|
void FlopIntegralBuffers(){
|
|||
|
|
|||
|
FlopIntegralBuffer = !FlopIntegralBuffer;
|
|||
|
|
|||
|
if (FlopIntegralBuffer)
|
|||
|
{
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_PreviousFrameLighting, FroxelBufferA);
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_Result, FroxelBufferB);
|
|||
|
FroxelIntegrationCompute.SetTexture(IntegrateKernel, ID_InLightingTexture, FroxelBufferB);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_PreviousFrameLighting, FroxelBufferB);
|
|||
|
FroxelFogCompute.SetTexture(ScatteringKernel, ID_Result, FroxelBufferA);
|
|||
|
FroxelIntegrationCompute.SetTexture(IntegrateKernel, ID_InLightingTexture, FroxelBufferA);
|
|||
|
}
|
|||
|
|
|||
|
FroxelIntegrationCompute.SetTexture(IntegrateKernel, ID_HistoryBuffer, IntegrationBuffer);
|
|||
|
FroxelIntegrationCompute.SetTexture(IntegrateKernel, ID_Result, IntegrationBuffer);
|
|||
|
}
|
|||
|
|
|||
|
Matrix4x4 PrevViewProjMatrix = Matrix4x4.identity;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public void SetVariables()
|
|||
|
{
|
|||
|
//Global multiplier for static lights
|
|||
|
//ScatteringFromExtinctionAndAlbedo
|
|||
|
//THESE ARE GLOBAL VARIABLES. THEY NEED TO STAY GLOBAL
|
|||
|
|
|||
|
// The volumetrics script should be in charge of setting these,
|
|||
|
// if there's no volume component then all volumetric
|
|||
|
// scripts will use the last camera to be enabled's values
|
|||
|
// Not ideal, but for now it should be fine
|
|||
|
|
|||
|
if (!Volumetrics.hasSetGlobals) // Added check so volumetric rendering scripts don't overwrite the volumetrics scripts values
|
|||
|
{
|
|||
|
float extinction = VolumeRenderingUtils.ExtinctionFromMeanFreePath(meanFreePath);
|
|||
|
Shader.SetGlobalFloat(ID_GlobalExtinction, extinction); //ExtinctionFromMeanFreePath
|
|||
|
Shader.SetGlobalFloat(ID_StaticLightMultiplier, StaticLightMultiplier); //Global multiplier for static lights
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
float GetAspectRatio()
|
|||
|
{
|
|||
|
if (activeCam.stereoTargetEye == StereoTargetEyeMask.None) return activeCam.aspect;
|
|||
|
return XRSettings.eyeTextureHeight == 0 ? activeCam.aspect : (float)XRSettings.eyeTextureHeight / (float)XRSettings.eyeTextureWidth;
|
|||
|
}
|
|||
|
|
|||
|
// void Update()
|
|||
|
// {
|
|||
|
//#if UNITY_EDITOR
|
|||
|
// if (Application.isPlaying)
|
|||
|
// {
|
|||
|
// UpdateFunc();
|
|||
|
// }
|
|||
|
//#else
|
|||
|
// UpdateFunc();
|
|||
|
//#endif
|
|||
|
// }
|
|||
|
|
|||
|
void UpdatePreRender(ScriptableRenderContext ctxt, Camera cam1)
|
|||
|
{
|
|||
|
if (activeCam == cam1) UpdateFunc();
|
|||
|
}
|
|||
|
|
|||
|
void UpdateFunc()
|
|||
|
{
|
|||
|
using (new ProfilingScope(null, profileUpdateFunc))
|
|||
|
{
|
|||
|
if (!hasInitialized)
|
|||
|
{
|
|||
|
//Debug.LogWarning("Volumetric Rendering: Volumetrics trying to render without initializing");
|
|||
|
return;
|
|||
|
}
|
|||
|
if (activeCam == null)
|
|||
|
{
|
|||
|
Debug.LogError("Volumetric Rendering: Active camera destroyed or de-assigned, disabling");
|
|||
|
this.enabled = false;
|
|||
|
return;
|
|||
|
}
|
|||
|
#if UNITY_EDITOR
|
|||
|
if ((Application.isPlaying && !activeCam.isActiveAndEnabled && !enableEditorPreview))
|
|||
|
#else
|
|||
|
if (!activeCam.isActiveAndEnabled)
|
|||
|
#endif
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
CheckOverrideVolumes();
|
|||
|
//camera.aspect no longer returns the correct value & this workaround only works when XR is fully intialized otherwise it returns 0 and divs by 0; >W<
|
|||
|
//bleh
|
|||
|
CamAspectRatio = GetAspectRatio();
|
|||
|
|
|||
|
Matrix4x4 projectionMatrix = Matrix4x4.Perspective(activeCam.fieldOfView, CamAspectRatio, activeCam.nearClipPlane, volumetricData.far) * Matrix4x4.Rotate(activeCam.transform.rotation).inverse;
|
|||
|
projectionMatrix = matScaleBias * projectionMatrix;
|
|||
|
|
|||
|
//Previous frame's matrix//!!!!!!!!!
|
|||
|
FroxelFogCompute.SetMatrix(PreviousFrameMatrixID, PreviousFrameMatrix);///
|
|||
|
// FroxelFogCompute.SetMatrix(PreviousFrameMatrixID, PreviousFrameMatrix );///
|
|||
|
// var controller = hdCamera.volumeStack.GetComponent<Fog>(); //TODO: Link with controller
|
|||
|
// UpdateLights();
|
|||
|
|
|||
|
CheckClipmap(); // UpdateClipmap();
|
|||
|
|
|||
|
SetFroxelFogUniforms();
|
|||
|
SetFroxelIntegrationUniforms();
|
|||
|
SetBlurUniforms();
|
|||
|
|
|||
|
FlopIntegralBuffers();
|
|||
|
// Matrix4x4 lightMatrix = matScaleBias * Matrix4x4.Perspective(LightPosition.spotAngle, 1, 0.1f, LightPosition.range) * Matrix4x4.Rotate(LightPosition.transform.rotation).inverse;
|
|||
|
VBufferParameters vbuff = new VBufferParameters(
|
|||
|
new Vector3Int(volumetricData.FroxelWidthResolution, volumetricData.FroxelWidthResolution, volumetricData.FroxelDepthResolution),
|
|||
|
volumetricData.far,
|
|||
|
activeCam.nearClipPlane,
|
|||
|
activeCam.farClipPlane,
|
|||
|
activeCam.fieldOfView,
|
|||
|
SliceDistributionUniformity);
|
|||
|
|
|||
|
// Vector2Int sharedBufferSize = new Vector2Int(volumetricData.FroxelWidthResolution, volumetricData.FroxelHeightResolution); //Taking scaler functuion from HDRP for reprojection
|
|||
|
// Shader.SetGlobalVector("_VBufferSharedUvScaleAndLimit", vbuff.ComputeUvScaleAndLimit(sharedBufferSize) ); //Just assuming same scale
|
|||
|
|
|||
|
Vector4 vres = new Vector4(volumetricData.FroxelWidthResolution, volumetricData.FroxelHeightResolution, 1.0f / volumetricData.FroxelWidthResolution, 1.0f / volumetricData.FroxelHeightResolution);
|
|||
|
//Vector4 vres = new Vector4(cam.pixelWidth, cam.pixelHeight, 1.0f / cam.pixelWidth, cam.pixelHeight);
|
|||
|
|
|||
|
Matrix4x4 PixelCoordToViewDirWS = ComputePixelCoordToWorldSpaceViewDirectionMatrix(activeCam, vres);
|
|||
|
|
|||
|
GetHexagonalClosePackedSpheres7(m_xySeq);
|
|||
|
int sampleIndex = Time.renderedFrameCount % 7;
|
|||
|
Vector3 seqOffset = new Vector3(m_xySeq[sampleIndex].x, m_xySeq[sampleIndex].y, m_zSeq[sampleIndex]);
|
|||
|
|
|||
|
Span<ShaderConstants> shaderConsts = stackalloc ShaderConstants[1];
|
|||
|
shaderConsts[0].TransposedCameraProjectionMatrix = projectionMatrix.transpose;
|
|||
|
shaderConsts[0].CameraProjectionMatrix = projectionMatrix;
|
|||
|
shaderConsts[0]._VBufferDistanceEncodingParams = vbuff.depthEncodingParams;
|
|||
|
shaderConsts[0]._VolumetricResultDim = new Vector3(FroxelBlur != BlurType.Gaussian ? volumetricData.FroxelWidthResolution * 2 : volumetricData.FroxelWidthResolution,
|
|||
|
volumetricData.FroxelHeightResolution, volumetricData.FroxelDepthResolution);
|
|||
|
shaderConsts[0]._VolCameraPos = activeCam.transform.position;
|
|||
|
if (ShaderConstantBuffer == null)
|
|||
|
{
|
|||
|
ShaderConstantBuffer = new ComputeBuffer(ShaderConstantsCount, sizeof(float), ComputeBufferType.Constant);
|
|||
|
//Shader.SetGlobalConstantBuffer(ID_VolumetricsCB, ShaderConstantBuffer, 0, ShaderConstantsSize);
|
|||
|
//Debug.Log("Created New Compute Buffer");
|
|||
|
}
|
|||
|
ShaderConstantBuffer.SetData<ShaderConstants>(shaderConsts);
|
|||
|
|
|||
|
|
|||
|
Span<StepAddPerFrameConstants> stepAddConst = stackalloc StepAddPerFrameConstants[1];
|
|||
|
stepAddConst[0] = new StepAddPerFrameConstants();
|
|||
|
stepAddConst[0]._VBufferDistanceDecodingParams = vbuff.depthDecodingParams;
|
|||
|
stepAddConst[0].SeqOffset = seqOffset;
|
|||
|
if (StepAddPerFrameConstantBuffer == null)
|
|||
|
{
|
|||
|
StepAddPerFrameConstantBuffer = new ComputeBuffer(1, StepAddPerFrameCount * sizeof(float), ComputeBufferType.Constant);
|
|||
|
//Shader.SetGlobalConstantBuffer(PerFrameConstBufferID, StepAddPerFrameConstantBuffer, 0, StepAddPerFrameCount * sizeof(float));
|
|||
|
//Debug.Log("Created New Compute Buffer");
|
|||
|
}
|
|||
|
StepAddPerFrameConstantBuffer.SetData<StepAddPerFrameConstants>(stepAddConst);
|
|||
|
|
|||
|
Span<ScatteringPerFrameConstants> VolScatteringCB = stackalloc ScatteringPerFrameConstants[1];
|
|||
|
VolScatteringCB[0] = new ScatteringPerFrameConstants()
|
|||
|
{
|
|||
|
_VBufferCoordToViewDirWS = PixelCoordToViewDirWS,
|
|||
|
_PrevViewProjMatrix = PrevViewProjMatrix,
|
|||
|
_ViewMatrix = activeCam.worldToCameraMatrix,
|
|||
|
TransposedCameraProjectionMatrix = projectionMatrix.transpose,
|
|||
|
CameraProjectionMatrix = projectionMatrix,
|
|||
|
_VBufferDistanceEncodingParams = vbuff.depthEncodingParams,
|
|||
|
_VBufferDistanceDecodingParams = vbuff.depthDecodingParams,
|
|||
|
SeqOffset = seqOffset,
|
|||
|
CameraPosition = activeCam.transform.position,
|
|||
|
CameraMotionVector = activeCam.transform.position - PreviousCameraPosition
|
|||
|
};
|
|||
|
//float[] VolScatteringCBArray = VolStructToArray(VolScatteringCB, PerFrameConstantsCount, PerFrameConstantsSize);
|
|||
|
//Debug.Log(VolScatteringCB._VBufferCoordToViewDirWS);
|
|||
|
//Debug.Log(VolScatteringCBArray[4] + " " + VolScatteringCBArray[5] + " " + VolScatteringCBArray[6] + " " + VolScatteringCBArray[7]);
|
|||
|
if (ComputePerFrameConstantBuffer == null)
|
|||
|
{
|
|||
|
ComputePerFrameConstantBuffer = new ComputeBuffer(1, ScatterPerFrameCount * sizeof(float), ComputeBufferType.Constant);
|
|||
|
//Debug.Log("Created New Compute Buffer");
|
|||
|
}
|
|||
|
ComputePerFrameConstantBuffer.SetData<ScatteringPerFrameConstants>(VolScatteringCB);
|
|||
|
FroxelFogCompute.SetConstantBuffer(PerFrameConstBufferID, ComputePerFrameConstantBuffer, 0, ScatterPerFrameCount * sizeof(float));
|
|||
|
|
|||
|
/*
|
|||
|
int mediaCount = VolumetricRegisters.VolumetricMediaEntities.Count;
|
|||
|
int maxCount = Math.Max(mediaCount, 1);
|
|||
|
|
|||
|
if (object.ReferenceEquals(participatingMediaSphereBuffer, null) || participatingMediaSphereBuffer == null)
|
|||
|
{
|
|||
|
participatingMediaSphereBuffer = new ComputeBuffer(maxCount, MediaSphereStride, ComputeBufferType.Structured);
|
|||
|
//Debug.Log("Created New Compute Buffer");
|
|||
|
}
|
|||
|
else if (maxCount > MediaCount)
|
|||
|
{
|
|||
|
participatingMediaSphereBuffer.Release();
|
|||
|
participatingMediaSphereBuffer = new ComputeBuffer(maxCount, MediaSphereStride, ComputeBufferType.Structured);
|
|||
|
MediaCount = maxCount;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
MediaSphere[] mediadata = new MediaSphere[maxCount];
|
|||
|
|
|||
|
if (mediaCount < 1)
|
|||
|
{
|
|||
|
//mediadata[0].CenterPosition = Vector3.zero;
|
|||
|
//mediadata[0].LocalExtinction = 0;
|
|||
|
//mediadata[0].LocalRange = 0;
|
|||
|
//mediadata[0].LocalFalloff = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for (int i = 0; i < mediadata.Length; i++)
|
|||
|
{
|
|||
|
//TODO: generalize the strut between the classes so we don't have to recast it here
|
|||
|
mediadata[i].CenterPosition = VolumetricRegisters.VolumetricMediaEntities[i].gameObject.transform.position;
|
|||
|
mediadata[i].LocalExtinction = VolumetricRegisters.VolumetricMediaEntities[i].LocalExtinction();
|
|||
|
mediadata[i].LocalRange = VolumetricRegisters.VolumetricMediaEntities[i].Scale.magnitude; // temp mag
|
|||
|
mediadata[i].LocalFalloff = VolumetricRegisters.VolumetricMediaEntities[i].falloffDistance;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (participatingMediaSphereBuffer != null)
|
|||
|
{
|
|||
|
participatingMediaSphereBuffer.SetData(mediadata);
|
|||
|
FroxelFogCompute.SetBuffer(ScatteringKernel, ID_media_sphere_buffer, participatingMediaSphereBuffer);
|
|||
|
FroxelFogCompute.SetFloat(ID_media_sphere_buffer_length, mediaCount);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
if (VolumetricConstantBuffer != null && projectionMatrix != null && activeCam != null && vbuff.depthEncodingParams != null)
|
|||
|
{
|
|||
|
VolumetricConstants vConst = new VolumetricConstants();
|
|||
|
vConst.CameraProjectionMatrix = projectionMatrix.transpose;
|
|||
|
vConst.TransposedCameraProjectionMatrix = projectionMatrix;
|
|||
|
vConst._VBufferDistanceEncodingParams = vbuff.depthEncodingParams;
|
|||
|
vConst._VolCameraPos = activeCam.transform.position;
|
|||
|
float[] vConstArray = VolStructToArray(vConst);
|
|||
|
VolumetricConstantBuffer.SetData(vConstArray);
|
|||
|
Shader.SetGlobalConstantBuffer("VolumetricCB", VolumetricConstantBuffer, 0, VolCBCount * sizeof(float));
|
|||
|
}
|
|||
|
*/
|
|||
|
PreviousFrameMatrix = projectionMatrix;
|
|||
|
PreviousCameraPosition = activeCam.transform.position;
|
|||
|
////MATRIX
|
|||
|
///
|
|||
|
///camera.projectionMatrix is ALSO broken and returns the final viewport's projection rather than the center XR projection.
|
|||
|
///cam.GetStereoProjectionMatrix returns the skewed XR projection matrix per eye. Just doing our own calulation
|
|||
|
var gpuProj = GL.GetGPUProjectionMatrix(Matrix4x4.Perspective(activeCam.fieldOfView, CamAspectRatio, activeCam.nearClipPlane, 100000f), true);
|
|||
|
PrevViewProjMatrix = gpuProj * activeCam.worldToCameraMatrix;
|
|||
|
//Debug.Log("Dispatching 3");
|
|||
|
FroxelFogCompute.Dispatch(ScatteringKernel, (int)ThreadsToDispatch.x, (int)ThreadsToDispatch.y, (int)ThreadsToDispatch.z);
|
|||
|
// FroxelStackingCompute.DispatchIndirect
|
|||
|
//CONVERT TO DISPATCH INDIRECT to avoid CPU callback?
|
|||
|
//Debug.Log("Dispatching 4");
|
|||
|
FroxelIntegrationCompute.Dispatch(IntegrateKernel, (int)ThreadsToDispatch.x * 2, (int)ThreadsToDispatch.y, (int)ThreadsToDispatch.z); //x2 for stereo
|
|||
|
|
|||
|
if (FroxelBlur == BlurType.Gaussian)
|
|||
|
{
|
|||
|
BlurCompute.Dispatch(BlurKernelX, (int)ThreadsToDispatch.x * 2, (int)ThreadsToDispatch.y, (int)ThreadsToDispatch.z); // Final blur
|
|||
|
BlurCompute.Dispatch(BlurKernelY, (int)ThreadsToDispatch.x * 2, (int)ThreadsToDispatch.y, (int)ThreadsToDispatch.z); // Final blur
|
|||
|
}
|
|||
|
/* Give the shader constant buffer and volumetric render texture to the
|
|||
|
* additional camera data so that on render the camera can set them as
|
|||
|
* globals
|
|||
|
*/
|
|||
|
SetCameraData();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//Coping the parms from HDRP to get the log encoded depth.
|
|||
|
struct VBufferParameters
|
|||
|
{
|
|||
|
public Vector3Int viewportSize;
|
|||
|
public Vector4 depthEncodingParams;
|
|||
|
public Vector4 depthDecodingParams;
|
|||
|
|
|||
|
public VBufferParameters(Vector3Int viewportResolution, float depthExtent, float camNear, float camFar, float camVFoV, float sliceDistributionUniformity)
|
|||
|
{
|
|||
|
viewportSize = viewportResolution;
|
|||
|
|
|||
|
// The V-Buffer is sphere-capped, while the camera frustum is not.
|
|||
|
// We always start from the near plane of the camera.
|
|||
|
|
|||
|
float aspectRatio = viewportResolution.x / (float)viewportResolution.y;
|
|||
|
float farPlaneHeight = 2.0f * Mathf.Tan(0.5f * camVFoV) * camFar;
|
|||
|
float farPlaneWidth = farPlaneHeight * aspectRatio;
|
|||
|
float farPlaneMaxDim = Mathf.Max(farPlaneWidth, farPlaneHeight);
|
|||
|
float farPlaneDist = Mathf.Sqrt(camFar * camFar + 0.25f * farPlaneMaxDim * farPlaneMaxDim);
|
|||
|
|
|||
|
float nearDist = camNear;
|
|||
|
float farDist = Mathf.Min(nearDist + depthExtent, farPlaneDist);
|
|||
|
|
|||
|
float c = 2 - 2 * sliceDistributionUniformity; // remap [0, 1] -> [2, 0]
|
|||
|
c = Mathf.Max(c, 0.001f); // Avoid NaNs
|
|||
|
|
|||
|
depthEncodingParams = ComputeLogarithmicDepthEncodingParams(nearDist, farDist, c);
|
|||
|
depthDecodingParams = ComputeLogarithmicDepthDecodingParams(nearDist, farDist, c);
|
|||
|
}
|
|||
|
|
|||
|
internal Vector4 ComputeUvScaleAndLimit(Vector2Int bufferSize)
|
|||
|
{
|
|||
|
// The slice count is fixed for now.
|
|||
|
return ComputeUvScaleAndLimitFun(new Vector2Int(viewportSize.x, viewportSize.y), bufferSize);
|
|||
|
}
|
|||
|
|
|||
|
internal float ComputeLastSliceDistance(int sliceCount)
|
|||
|
{
|
|||
|
float d = 1.0f - 0.5f / sliceCount;
|
|||
|
float ln2 = 0.69314718f;
|
|||
|
|
|||
|
// DecodeLogarithmicDepthGeneralized(1 - 0.5 / sliceCount)
|
|||
|
return depthDecodingParams.x * Mathf.Exp(ln2 * d * depthDecodingParams.y) + depthDecodingParams.z;
|
|||
|
}
|
|||
|
|
|||
|
// See EncodeLogarithmicDepthGeneralized().
|
|||
|
static Vector4 ComputeLogarithmicDepthEncodingParams(float nearPlane, float farPlane, float c)
|
|||
|
{
|
|||
|
Vector4 depthParams = new Vector4();
|
|||
|
|
|||
|
float n = nearPlane;
|
|||
|
float f = farPlane;
|
|||
|
|
|||
|
depthParams.y = 1.0f / Mathf.Log(c * (f - n) + 1, 2);
|
|||
|
depthParams.x = Mathf.Log(c, 2) * depthParams.y;
|
|||
|
depthParams.z = n - 1.0f / c; // Same
|
|||
|
depthParams.w = 0.0f;
|
|||
|
|
|||
|
return depthParams;
|
|||
|
}
|
|||
|
|
|||
|
// See DecodeLogarithmicDepthGeneralized().
|
|||
|
static Vector4 ComputeLogarithmicDepthDecodingParams(float nearPlane, float farPlane, float c)
|
|||
|
{
|
|||
|
Vector4 depthParams = new Vector4();
|
|||
|
|
|||
|
float n = nearPlane;
|
|||
|
float f = farPlane;
|
|||
|
|
|||
|
depthParams.x = 1.0f / c;
|
|||
|
depthParams.y = Mathf.Log(c * (f - n) + 1, 2);
|
|||
|
depthParams.z = n - 1.0f / c; // Same
|
|||
|
depthParams.w = 0.0f;
|
|||
|
|
|||
|
return depthParams;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal static float ComputZPlaneTexelSpacing(float planeDepth, float verticalFoV, float resolutionY)
|
|||
|
{
|
|||
|
float tanHalfVertFoV = Mathf.Tan(0.5f * verticalFoV);
|
|||
|
return tanHalfVertFoV * (2.0f / resolutionY) * planeDepth;
|
|||
|
}
|
|||
|
|
|||
|
internal static Vector4 ComputeUvScaleAndLimitFun(Vector2Int viewportResolution, Vector2Int bufferSize)
|
|||
|
{
|
|||
|
Vector2 rcpBufferSize = new Vector2(1.0f / bufferSize.x, 1.0f / bufferSize.y);
|
|||
|
|
|||
|
// vp_scale = vp_dim / tex_dim.
|
|||
|
Vector2 uvScale = new Vector2(viewportResolution.x * rcpBufferSize.x,
|
|||
|
viewportResolution.y * rcpBufferSize.y);
|
|||
|
|
|||
|
// clamp to (vp_dim - 0.5) / tex_dim.
|
|||
|
Vector2 uvLimit = new Vector2((viewportResolution.x - 0.5f) * rcpBufferSize.x,
|
|||
|
(viewportResolution.y - 0.5f) * rcpBufferSize.y);
|
|||
|
|
|||
|
return new Vector4(uvScale.x, uvScale.y, uvLimit.x, uvLimit.y);
|
|||
|
}
|
|||
|
|
|||
|
public void disable()
|
|||
|
{
|
|||
|
//Debug.Log("Volumetric Rendering: Disable Called");
|
|||
|
hasInitialized = false;
|
|||
|
#if UNITY_EDITOR
|
|||
|
RenderPipelineManager.beginCameraRendering -= UpdatePreRender;
|
|||
|
AssemblyReloadEvents.beforeAssemblyReload -= CleanupOnReload;
|
|||
|
#else
|
|||
|
RenderPipelineManager.beginCameraRendering -= UpdatePreRender;
|
|||
|
#endif
|
|||
|
ReleaseAssets();
|
|||
|
CleanupCameraData();
|
|||
|
VolumetricRegisters.UnregisterVolumetricRenderer(this);
|
|||
|
}
|
|||
|
|
|||
|
public void enable()
|
|||
|
{
|
|||
|
StartSceneViewRendering();
|
|||
|
Intialize();
|
|||
|
}
|
|||
|
|
|||
|
public void StartSceneViewRendering()
|
|||
|
{
|
|||
|
//#if UNITY_EDITOR
|
|||
|
// if (enableEditorPreview && !Application.isPlaying) RenderPipelineManager.beginCameraRendering += UpdatePreRender;
|
|||
|
//#else
|
|||
|
RenderPipelineManager.beginCameraRendering += UpdatePreRender;
|
|||
|
//#endif
|
|||
|
}
|
|||
|
|
|||
|
public void UpdateStateAfterReload()
|
|||
|
{
|
|||
|
if (enableEditorPreview && this.isActiveAndEnabled)
|
|||
|
{
|
|||
|
enable();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
disable();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void CleanupOnReload()
|
|||
|
{
|
|||
|
disable();
|
|||
|
}
|
|||
|
|
|||
|
private void OnEnable()
|
|||
|
{
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
if (!Application.isPlaying)
|
|||
|
{
|
|||
|
// Every time scripts get re-compiled, everything gets reset without calling OnDisable or OnDestroy, and the keyword gets left on
|
|||
|
enableEditorPreview = false;
|
|||
|
AssemblyReloadEvents.afterAssemblyReload += UpdateStateAfterReload;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
enable();
|
|||
|
}
|
|||
|
#else
|
|||
|
enable();
|
|||
|
#endif
|
|||
|
}
|
|||
|
private void OnDisable() //Disable this if we decide to just pause rendering instead of removing.
|
|||
|
{
|
|||
|
disable();
|
|||
|
#if UNITY_EDITOR
|
|||
|
if (!Application.isPlaying)
|
|||
|
{
|
|||
|
AssemblyReloadEvents.afterAssemblyReload -= UpdateStateAfterReload;
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
private void OnDestroy()
|
|||
|
{
|
|||
|
disable();
|
|||
|
#if UNITY_EDITOR
|
|||
|
if (!Application.isPlaying)
|
|||
|
{
|
|||
|
AssemblyReloadEvents.afterAssemblyReload -= UpdateStateAfterReload;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
private void DestroyAllTextureAssets()
|
|||
|
{
|
|||
|
ClipmapBufferA.Clear();
|
|||
|
ClipmapBufferB.Clear();
|
|||
|
ClipmapBufferC.Clear();
|
|||
|
ClipmapBufferD.Clear();
|
|||
|
|
|||
|
FroxelBufferA.Clear();
|
|||
|
FroxelBufferB.Clear();
|
|||
|
IntegrationBuffer.Clear();
|
|||
|
|
|||
|
BlurBuffer.Clear();
|
|||
|
BlurBufferB.Clear();
|
|||
|
|
|||
|
// if (createdLightProjectionTexture && LightProjectionTextures != null) { CoreUtils.Destroy(LightProjectionTextures); }
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Matrix4x4 ComputePixelCoordToWorldSpaceViewDirectionMatrix(Camera cam, Vector4 resolution)
|
|||
|
{
|
|||
|
// var proj = cam.projectionMatrix; // GL.GetGPUProjectionMatrix(cameraProj, true); //Use this if we run into platform issues
|
|||
|
//bandaid fix. There's an issue with the far clip plane in the matrix projection.
|
|||
|
var proj = Matrix4x4.Perspective(cam.fieldOfView, CamAspectRatio, cam.nearClipPlane, 100000f);
|
|||
|
var view = cam.worldToCameraMatrix ;
|
|||
|
|
|||
|
var invViewProjMatrix = (proj * view).inverse;
|
|||
|
|
|||
|
var transform = Matrix4x4.Scale(new Vector3(-1.0f, -1.0f, -1.0f)) * invViewProjMatrix; // (gpuProj * gpuView).inverse
|
|||
|
// transform = transform * Matrix4x4.Scale(new Vector3(1.0f, -1.0f, 1.0f));
|
|||
|
transform = transform * Matrix4x4.Translate(new Vector3(-1.0f, -1.0f, 0.0f));
|
|||
|
transform = transform * Matrix4x4.Scale(new Vector3(2.0f * resolution.z, 2.0f * resolution.w, 1.0f)) ;
|
|||
|
|
|||
|
return transform.transpose;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void SetComputeVariables()
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void SetComputeBuffer(string name, ComputeShader shader, int kernel, ComputeBuffer buffer)
|
|||
|
{
|
|||
|
// Debug.Log("Setting buffer");
|
|||
|
if (buffer != null)
|
|||
|
{
|
|||
|
shader.SetBuffer(kernel, name, buffer);
|
|||
|
|
|||
|
// Debug.Log(name + " set");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static void CreateComputeBuffer<T>(ref ComputeBuffer buffer, List<T> data, int stride)
|
|||
|
where T : struct
|
|||
|
{
|
|||
|
//Debug.Log("Making computebuffer ");
|
|||
|
//buffer = new ComputeBuffer(data.Count, stride);
|
|||
|
|
|||
|
// Do we already have a compute buffer?
|
|||
|
if (buffer != null && data != null && stride != null)
|
|||
|
{
|
|||
|
// If no data or buffer doesn't match the given criteria, release it
|
|||
|
if (data.Count == 0 || buffer.count != data.Count || buffer.stride != stride)
|
|||
|
{
|
|||
|
// Debug.Log("Buffer count = " + buffer.count);
|
|||
|
|
|||
|
buffer.Release();
|
|||
|
buffer = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (data.Count != 0)
|
|||
|
{
|
|||
|
// If the buffer has been released or wasn't there to
|
|||
|
// begin with, create it
|
|||
|
if (buffer == null)
|
|||
|
{
|
|||
|
buffer = new ComputeBuffer(data.Count, stride);
|
|||
|
|
|||
|
// Debug.Log("Buffer count = " + buffer.count);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Set data on the buffer
|
|||
|
buffer.SetData(data);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Editor
|
|||
|
/// </summary>
|
|||
|
///
|
|||
|
private void OnDrawGizmosSelected()
|
|||
|
{
|
|||
|
if (cam == null || volumetricData == null) return;
|
|||
|
|
|||
|
Gizmos.color = Color.black;
|
|||
|
;
|
|||
|
Gizmos.matrix = Matrix4x4.TRS(cam.transform.position, cam.transform.rotation, Vector3.one);
|
|||
|
Gizmos.DrawFrustum(Vector3.zero, cam.fieldOfView, volumetricData.near, volumetricData.far, CamAspectRatio);
|
|||
|
|
|||
|
Gizmos.color = Color.cyan;
|
|||
|
Gizmos.matrix = Matrix4x4.TRS(ClipmapCurrentPos, Quaternion.identity, Vector3.one * volumetricData.ClipmapScale);
|
|||
|
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
|||
|
|
|||
|
Gizmos.color = Color.blue;
|
|||
|
Gizmos.matrix = Matrix4x4.TRS(ClipmapCurrentPos, Quaternion.identity, Vector3.one * volumetricData.ClipmapScale2);
|
|||
|
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
|||
|
|
|||
|
|
|||
|
//Gizmos.color = Color.red;
|
|||
|
//Gizmos.matrix = cam.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left);
|
|||
|
//Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
|||
|
|
|||
|
//Gizmos.color = Color.yellow;
|
|||
|
//Gizmos.matrix = cam.GetStereoProjectionMatrix(Camera.StereoscopicEye.Right);
|
|||
|
//Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
|||
|
|
|||
|
//Gizmos.color = Color.green;
|
|||
|
//Gizmos.matrix = Matrix4x4.Perspective(cam.fieldOfView, CamAspectRatio, cam.nearClipPlane, 100000f);
|
|||
|
//Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
|||
|
|
|||
|
//Gizmos.color = Color.magenta;
|
|||
|
//Gizmos.matrix = Matrix4x4.Perspective(cam.fieldOfView, CamAspectRatio, volumetricData.near, volumetricData.far) * Matrix4x4.Translate(new Vector3(cam.stereoSeparation * 0.5f, 0, 0));
|
|||
|
//Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void ReleaseAssets()
|
|||
|
{
|
|||
|
DestroyAllTextureAssets();
|
|||
|
|
|||
|
if (ComputePerFrameConstantBuffer != null)
|
|||
|
{
|
|||
|
ComputePerFrameConstantBuffer.Release();
|
|||
|
ComputePerFrameConstantBuffer = null;
|
|||
|
}
|
|||
|
if (StepAddPerFrameConstantBuffer != null)
|
|||
|
{
|
|||
|
StepAddPerFrameConstantBuffer.Release();
|
|||
|
StepAddPerFrameConstantBuffer = null;
|
|||
|
}
|
|||
|
if (ShaderConstantBuffer != null)
|
|||
|
{
|
|||
|
ShaderConstantBuffer.Release();
|
|||
|
ShaderConstantBuffer = null;
|
|||
|
}
|
|||
|
if (participatingMediaSphereBuffer != null)
|
|||
|
{
|
|||
|
participatingMediaSphereBuffer.Release();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void CleanupCameraData()
|
|||
|
{
|
|||
|
if (activeCamData != null)
|
|||
|
{
|
|||
|
activeCamData.m_EnableVolumetrics = false;
|
|||
|
activeCamData.m_VolumetricClipMap = null;
|
|||
|
activeCamData.m_VolumetricShaderGlobals = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void SetCameraData()
|
|||
|
{
|
|||
|
if (activeCamData != null && VolumetricResult != null && ShaderConstantBuffer != null)
|
|||
|
{
|
|||
|
activeCamData.m_EnableVolumetrics = true;
|
|||
|
activeCamData.m_VolumetricClipMap = VolumetricResult;
|
|||
|
activeCamData.m_VolumetricShaderGlobals = ShaderConstantBuffer;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Debug.LogWarning("Volumetric Rendering: Null extra camera data, volumetric result, or constant buffer!");
|
|||
|
activeCamData.m_EnableVolumetrics = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
|
|||
|
void assignVaris()
|
|||
|
{
|
|||
|
|
|||
|
//cam = GetComponentInChildren<Camera>();
|
|||
|
//Get shaders and seri
|
|||
|
if (FroxelFogCompute == null)
|
|||
|
FroxelFogCompute = AssetDatabase.LoadAssetAtPath<ComputeShader>("Packages/com.unity.render-pipelines.universal/Shaders/Volumetrics/VolumetricScattering.compute");
|
|||
|
if (FroxelFogCompute == null)
|
|||
|
FroxelFogCompute = AssetDatabase.LoadAssetAtPath<ComputeShader>("Packages/com.unity.render-pipelines.universal/Shaders/Volumetrics/VolumetricScattering.compute");
|
|||
|
if (FroxelIntegrationCompute == null)
|
|||
|
FroxelIntegrationCompute = AssetDatabase.LoadAssetAtPath<ComputeShader>("Packages/com.unity.render-pipelines.universal/Shaders/Volumetrics/StepAdd.compute");
|
|||
|
if (ClipmapCompute == null)
|
|||
|
ClipmapCompute = AssetDatabase.LoadAssetAtPath<ComputeShader>("Packages/com.unity.render-pipelines.universal/Shaders/Volumetrics/ClipMapGenerator.compute");
|
|||
|
if (BlurCompute == null)
|
|||
|
BlurCompute = AssetDatabase.LoadAssetAtPath<ComputeShader>("Packages/com.unity.render-pipelines.universal/Shaders/Volumetrics/VolumetricBlur.compute");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
private void Reset()
|
|||
|
{
|
|||
|
cam = GetComponentInChildren<Camera>();
|
|||
|
assignVaris();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private void OnValidate()
|
|||
|
{
|
|||
|
|
|||
|
//Black Texture in editor to not get in the way. Isolated h ere because shaders should skip volumetric tex in precompute otherwise.
|
|||
|
// TODO: Add proper scene preview feature
|
|||
|
if (BlackTex == null) BlackTex = CoreUtils.blackVolumeTexture; //(Texture3D)MakeBlack3DTex();
|
|||
|
|
|||
|
// UnityEditor.SceneManagement.EditorSceneManager.sceneUnloaded += UnloadKeyword; //adding function when scene is unloaded
|
|||
|
assignVaris();
|
|||
|
//if (cam == null) cam = GetComponent<Camera>();
|
|||
|
//if (volumetricData.near < cam.nearClipPlane || volumetricData.far > cam.farClipPlane)
|
|||
|
//{
|
|||
|
// //Auto clamp to inside of the camera's clip planes
|
|||
|
// volumetricData.near = Mathf.Max(volumetricData.near, cam.nearClipPlane);
|
|||
|
// volumetricData.far = Mathf.Min(volumetricData.far, cam.farClipPlane);
|
|||
|
//}
|
|||
|
|
|||
|
//Shader.EnableKeyword(VolumetricsKW); //enabling here so the editor knows that it exists
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//Using core blackVolumeTexture instead
|
|||
|
//Texture MakeBlack3DTex()
|
|||
|
//{
|
|||
|
// Debug.Log("Made blank texture");
|
|||
|
|
|||
|
// int size = 1;
|
|||
|
|
|||
|
// Texture3D BlackTex = new Texture3D(1, 1, 1, TextureFormat.ARGB32, false);
|
|||
|
// var cols = new Color[size * size * size];
|
|||
|
// float mul = 1.0f / (size - 1);
|
|||
|
// int idx = 0;
|
|||
|
// Color c = Color.white;
|
|||
|
// for (int z = 0; z < size; ++z)
|
|||
|
// {
|
|||
|
// for (int y = 0; y < size; ++y)
|
|||
|
// {
|
|||
|
// for (int x = 0; x < size; ++x, ++idx)
|
|||
|
// {
|
|||
|
// c.r = 0;
|
|||
|
// c.g = 0;
|
|||
|
// c.b = 0;
|
|||
|
// c.a = 1;
|
|||
|
// cols[idx] = c;
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }
|
|||
|
|
|||
|
// BlackTex.SetPixels(cols);
|
|||
|
// BlackTex.Apply();
|
|||
|
// // SetClipmap(BlackTex, 50, Vector3.zero);
|
|||
|
|
|||
|
// Shader.SetGlobalTexture(ID_VolumetricResult, BlackTex);
|
|||
|
|
|||
|
// // Shader.SetGlobalTexture("_VolumetricClipmapTexture", BlackTex); //Set clipmap for
|
|||
|
// return BlackTex;
|
|||
|
//}
|
|||
|
|
|||
|
|
|||
|
//public void UnloadKeyword<Scene>(Scene scene)
|
|||
|
//{
|
|||
|
// Shader.DisableKeyword("_VOLUMETRICS_ENABLED");
|
|||
|
|
|||
|
// print("The scene was unloaded!");
|
|||
|
//}
|
|||
|
|
|||
|
void Clear3DTexture(RenderTexture buffer)
|
|||
|
{
|
|||
|
ClipmapCompute.SetTexture(ID_ClipMapClearKern, ID_Result, buffer);
|
|||
|
ClipmapCompute.Dispatch(ID_ClipMapClearKern, Mathf.Max(buffer.width / 4, 1), Mathf.Max(buffer.height / 4, 1), Mathf.Max(buffer.volumeDepth / 4, 1));
|
|||
|
|
|||
|
//RenderTexture activeRT = RenderTexture.active;
|
|||
|
//RenderTexture.active = rt;
|
|||
|
//GL.sRGBWrite = rt.sRGB;
|
|||
|
//if (rt.dimension == TextureDimension.Tex3D)
|
|||
|
//{
|
|||
|
// CoreUtils.SetRenderTarget(
|
|||
|
// command,
|
|||
|
// rt,
|
|||
|
// ClearFlag.Color, Color.clear,
|
|||
|
// 0, CubemapFace.Unknown, -1
|
|||
|
// );
|
|||
|
|
|||
|
//}
|
|||
|
//else if (rt.dimension == TextureDimension.Cube)
|
|||
|
//{
|
|||
|
// Graphics.SetRenderTarget(rt, 0, CubemapFace.PositiveX, 0);
|
|||
|
// GL.Clear(false, true, color);
|
|||
|
// Graphics.SetRenderTarget(rt, 0, CubemapFace.PositiveY, 0);
|
|||
|
// GL.Clear(false, true, color);
|
|||
|
// Graphics.SetRenderTarget(rt, 0, CubemapFace.PositiveZ, 0);
|
|||
|
// GL.Clear(false, true, color);
|
|||
|
// Graphics.SetRenderTarget(rt, 0, CubemapFace.NegativeX, 0);
|
|||
|
// GL.Clear(false, true, color);
|
|||
|
// Graphics.SetRenderTarget(rt, 0, CubemapFace.NegativeY, 0);
|
|||
|
// GL.Clear(false, true, color);
|
|||
|
// Graphics.SetRenderTarget(rt, 0, CubemapFace.NegativeZ, 0);
|
|||
|
// GL.Clear(false, true, color);
|
|||
|
//}
|
|||
|
// CoreUtils.SetRenderTarget(
|
|||
|
// rt,
|
|||
|
// BuiltinRenderTextureType.CameraTarget
|
|||
|
//);
|
|||
|
// RenderTexture.active = activeRT;
|
|||
|
}
|
|||
|
|
|||
|
void RefreshOnSceneChange(Scene oldS, Scene newS)
|
|||
|
{
|
|||
|
if (hasInitialized && oldS != null)
|
|||
|
{
|
|||
|
Debug.Log("Volumetric Rendering: Refreshing after scene swap");
|
|||
|
this.disable();
|
|||
|
this.enable();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|