浏览代码

[PlanarReflection] (wip) refactoring projection volume in light loop

/main
Frédéric Vauchelles 7 年前
当前提交
3e63b300
共有 25 个文件被更改,包括 660 次插入59 次删除
  1. 56
      SampleScenes/HDTest/PlanarReflectionTests.unity
  2. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/PlanarReflectionProbeUI.Handles.cs
  3. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/SerializedPlanarReflectionProbe.cs
  4. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/Volume/InfluenceVolumeUI.Handles.cs
  5. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs
  6. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs
  7. 22
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs
  8. 60
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs.hlsl
  9. 222
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs
  10. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.hlsl
  11. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoopDef.hlsl
  12. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Lighting.hlsl
  13. 28
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/PlanarReflectionProbe.cs
  14. 32
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumes/InfluenceVolume.cs
  15. 20
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  16. 30
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionProbeCullResults.cs
  17. 11
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionProbeCullResults.cs.meta
  18. 34
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystem.cs
  19. 11
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystem.cs.meta
  20. 78
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemInternal.cs
  21. 11
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemInternal.cs.meta
  22. 12
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemParameters.cs
  23. 11
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemParameters.cs.meta
  24. 40
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/VolumeProjection.hlsl
  25. 9
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/VolumeProjection.hlsl.meta

56
SampleScenes/HDTest/PlanarReflectionTests.unity


m_UseColorTemperature: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!1 &1561776757
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 5
m_Component:
- component: {fileID: 1561776758}
- component: {fileID: 1561776759}
m_Layer: 0
m_Name: Planar Reflection Probe
m_TagString: Untagged
m_Icon: {fileID: -5487077368411116049, guid: 0000000000000000d000000000000000, type: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1561776758
Transform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1561776757}
m_LocalRotation: {x: -0, y: -0.7071065, z: -0, w: 0.7071072}
m_LocalPosition: {x: -6.76, y: 2.751, z: 3.33}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 1596124444}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: -90.00001, z: 0}
--- !u!114 &1561776759
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1561776757}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a4ee7c3a3b205a14a94094d01ff91d6b, type: 3}
m_Name:
m_EditorClassIdentifier:
m_ProjectionVolumeReference: {fileID: 1654939277}
m_InfluenceVolume:
m_ShapeType: 0
m_BoxBaseSize: {x: 1.7052255, y: 0.9908645, z: 0.95528436}
m_BoxBaseOffset: {x: 0.02969706, y: -0.0045677423, z: -0.022357821}
m_BoxInfluencePositiveFade: {x: 0, y: 0, z: 0.33511347}
m_BoxInfluenceNegativeFade: {x: 0, y: 0, z: 0.067846164}
m_BoxInfluenceNormalPositiveFade: {x: 0, y: 0.28144193, z: 0}
m_BoxInfluenceNormalNegativeFade: {x: 0, y: 0.07764101, z: 0}
m_BoxPositiveFaceFade: {x: 0, y: 0, z: 0}
m_BoxNegativeFaceFade: {x: 0, y: 0, z: 0}
m_SphereBaseRadius: 0.9066355
m_SphereBaseOffset: {x: 0, y: -0.09336448, z: 0}
m_SphereInfluenceFade: 0
m_SphereInfluenceNormalFade: 0
--- !u!1 &1562837666
GameObject:
m_ObjectHideFlags: 0

m_Children:
- {fileID: 547467866}
- {fileID: 1654939276}
- {fileID: 1561776758}
m_Father: {fileID: 1306845494}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/PlanarReflectionProbeUI.Handles.cs


using UnityEditorInternal;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{

InfluenceVolumeUI.DrawHandles_EditInfluenceNormal(s.influenceVolume, d.influenceVolume, o, mat, d);
break;
case EditCenter:
InfluenceVolumeUI.DrawHandles_EditCenter(s.influenceVolume, d.influenceVolume, o, mat, d);
InfluenceVolumeUI.DrawHandles_EditCenter(s.influenceVolume, d.influenceVolume, o, d.transform, d);
break;
}
}

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/SerializedPlanarReflectionProbe.cs


using UnityEditor.Experimental.Rendering.HDPipeline;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
public class SerializedPlanarReflectionProbe
{

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/Volume/InfluenceVolumeUI.Handles.cs


Handles.color = c;
}
public static void DrawHandles_EditCenter(InfluenceVolumeUI s, InfluenceVolume d, Editor o, Matrix4x4 matrix, Object sourceAsset)
public static void DrawHandles_EditCenter(InfluenceVolumeUI s, InfluenceVolume d, Editor o, Transform transform, Object sourceAsset)
}
static void DrawBoxHandle(

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs


m_GPUCopy = new GPUCopy(asset.renderPipelineResources.copyChannelCS);
EncodeBC6H.DefaultInstance = EncodeBC6H.DefaultInstance ?? new EncodeBC6H(asset.renderPipelineResources.encodeBC6HCS);
m_ReflectionProbeCullResults = new ReflectionProbeCullResults(ReflectionSystemParameters.Default);
ReflectionSystem.SetParameters(ReflectionSystemParameters.Default);
// Scan material list and assign it
m_MaterialList = HDUtils.GetRenderPipelineMaterialList();
// Find first material that have non 0 Gbuffer count and assign it as deferredMaterial

}
CullResults m_CullResults;
ReflectionProbeCullResults m_ReflectionProbeCullResults;
public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
{
base.Render(renderContext, cameras);

DecalSystem.instance.EndCull();
}
ReflectionSystem.Cull(camera, m_ReflectionProbeCullResults);
var postProcessLayer = camera.GetComponent<PostProcessLayer>();
var hdCamera = HDCamera.Get(camera, postProcessLayer, m_FrameSettings);

bool enableBakeShadowMask;
using (new ProfilingSample(cmd, "TP_PrepareLightsForGPU", GetSampler(CustomSamplerId.TPPrepareLightsForGPU)))
{
enableBakeShadowMask = m_LightLoop.PrepareLightsForGPU(cmd, m_ShadowSettings, m_CullResults, camera) && m_FrameSettings.enableShadowMask;
enableBakeShadowMask = m_LightLoop.PrepareLightsForGPU(cmd, m_ShadowSettings, m_CullResults, m_ReflectionProbeCullResults, camera) && m_FrameSettings.enableShadowMask;
}
ConfigureForShadowMask(enableBakeShadowMask, cmd);

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs


public static readonly int _AreaLightCount = Shader.PropertyToID("_AreaLightCount");
public static readonly int g_vLightListGlobal = Shader.PropertyToID("g_vLightListGlobal");
public static readonly int _EnvLightDatas = Shader.PropertyToID("_EnvLightDatas");
public static readonly int _EnvProjDatas = Shader.PropertyToID("_EnvProjDatas");
public static readonly int _EnvProjCount = Shader.PropertyToID("_EnvProjCount");
public static readonly int _ShadowDatas = Shader.PropertyToID("_ShadowDatas");
public static readonly int _NumTileFtplX = Shader.PropertyToID("_NumTileFtplX");
public static readonly int _NumTileFtplY = Shader.PropertyToID("_NumTileFtplY");

22
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs


public float unused7;
};
[GenerateHLSL]
public struct EnvProjData
{
public Vector3 positionWS;
public EnvShapeType envShapeType;
public Vector3 forward;
public float minProjectionDistance;
public Vector3 up;
public int unused00;
public Vector3 right;
// User can chose if they use This is use in case we want to force infinite projection distance (i.e no projection);
public int unused01;
// Box: extents = box extents
// Sphere: extents.x = sphere radius
public Vector3 extents;
public int unused02;
}
// Usage of StencilBits.Lighting on 2 bits.
// We support both deferred and forward renderer. Here is the current usage of this 2 bits:
// 0. Everything except case below. This include any forward opaque object. No lighting in deferred lighting path.

60
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs.hlsl


float unused7;
};
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.EnvProjData
// PackingRules = Exact
struct EnvProjData
{
float3 positionWS;
int envShapeType;
float3 forward;
float minProjectionDistance;
float3 up;
int unused00;
float3 right;
int unused01;
float3 extents;
int unused02;
};
//
// Accessors for UnityEngine.Experimental.Rendering.HDPipeline.DirectionalLightData
//

float GetUnused7(EnvLightData value)
{
return value.unused7;
}
//
// Accessors for UnityEngine.Experimental.Rendering.HDPipeline.EnvProjData
//
float3 GetPositionWS(EnvProjData value)
{
return value.positionWS;
}
int GetEnvShapeType(EnvProjData value)
{
return value.envShapeType;
}
float3 GetForward(EnvProjData value)
{
return value.forward;
}
float GetMinProjectionDistance(EnvProjData value)
{
return value.minProjectionDistance;
}
float3 GetUp(EnvProjData value)
{
return value.up;
}
int GetUnused00(EnvProjData value)
{
return value.unused00;
}
float3 GetRight(EnvProjData value)
{
return value.right;
}
int GetUnused01(EnvProjData value)
{
return value.unused01;
}
float3 GetExtents(EnvProjData value)
{
return value.extents;
}
int GetUnused02(EnvProjData value)
{
return value.unused02;
}

222
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs


static ComputeBuffer s_DirectionalLightDatas = null;
static ComputeBuffer s_LightDatas = null;
static ComputeBuffer s_EnvLightDatas = null;
static ComputeBuffer s_EnvProjDatas = null;
static ComputeBuffer s_shadowDatas = null;
static Texture2DArray s_DefaultTexture2DArray;

public List<DirectionalLightData> directionalLights;
public List<LightData> lights;
public List<EnvLightData> envLights;
public List<EnvProjData> envProjs;
public List<ShadowData> shadows;
public List<SFiniteLightBound> bounds;

directionalLights.Clear();
lights.Clear();
envLights.Clear();
envProjs.Clear();
shadows.Clear();
bounds.Clear();

directionalLights = new List<DirectionalLightData>();
lights = new List<LightData>();
envLights = new List<EnvLightData>();
envProjs = new List<EnvProjData>();
shadows = new List<ShadowData>();
bounds = new List<SFiniteLightBound>();

s_DirectionalLightDatas = new ComputeBuffer(k_MaxDirectionalLightsOnScreen, System.Runtime.InteropServices.Marshal.SizeOf(typeof(DirectionalLightData)));
s_LightDatas = new ComputeBuffer(k_MaxPunctualLightsOnScreen + k_MaxAreaLightsOnScreen, System.Runtime.InteropServices.Marshal.SizeOf(typeof(LightData)));
s_EnvLightDatas = new ComputeBuffer(k_MaxEnvLightsOnScreen, System.Runtime.InteropServices.Marshal.SizeOf(typeof(EnvLightData)));
s_EnvProjDatas = new ComputeBuffer(k_MaxEnvLightsOnScreen, System.Runtime.InteropServices.Marshal.SizeOf(typeof(EnvProjData)));
s_shadowDatas = new ComputeBuffer(k_MaxCascadeCount + k_MaxShadowOnScreen, System.Runtime.InteropServices.Marshal.SizeOf(typeof(ShadowData)));
GlobalLightLoopSettings gLightLoopSettings = hdAsset.GetRenderPipelineSettings().lightLoopSettings;

CoreUtils.SafeRelease(s_DirectionalLightDatas);
CoreUtils.SafeRelease(s_LightDatas);
CoreUtils.SafeRelease(s_EnvLightDatas);
CoreUtils.SafeRelease(s_EnvProjDatas);
CoreUtils.SafeRelease(s_shadowDatas);
if (m_ReflectionProbeCache != null)

m_lightList.lightVolumes.Add(lightVolumeData);
}
public bool GetEnvLightData(CommandBuffer cmd, Camera camera, VisibleReflectionProbe probe)
class ProbeWrapper
{
public Vector3 influencePositionWS;
public Vector3 offsetLS;
public Vector3 projectionPositionWS;
public ProbeWrapper(VisibleReflectionProbe probe, PlanarReflectionProbe planarProbe)
{
}
public EnvShapeType influenceShapeType { get; set; }
public float dimmer { get; set; }
public Vector3 influenceExtents { get; set; }
public Vector3 blendNormalDistancePositive { get; set; }
public Vector3 blendNormalDistanceNegative { get; set; }
public Vector3 blendDistancePositive { get; set; }
public Vector3 blendDistanceNegative { get; set; }
public Vector3 boxSideFadePositive { get; set; }
public Vector3 boxSideFadeNegative { get; set; }
public Vector3 influenceRight { get; set; }
public Vector3 influenceUp { get; set; }
public Vector3 influenceForward { get; set; }
public EnvShapeType projectionShapeType { get; set; }
public Vector3 projectionRight { get; set; }
public Vector3 projectionUp { get; set; }
public Vector3 projectionForward { get; set; }
public Vector3 projectionExtents { get; set; }
public float minProjectionDistance { get; set; }
}
public bool GetEnvLightData(CommandBuffer cmd, Camera camera, VisibleReflectionProbe probe, PlanarReflectionProbe planarProbe)
var p = new ProbeWrapper(probe, planarProbe);
// For now we won't display real time probe when rendering one.
// TODO: We may want to display last frame result but in this case we need to be careful not to update the atlas before all realtime probes are rendered (for frame coherency).
// Unfortunately we don't have this information at the moment.
if (probe.probe.mode == ReflectionProbeMode.Realtime && camera.cameraType == CameraType.Reflection)
return false;
int envIndex = m_ReflectionProbeCache.FetchSlice(cmd, probe.texture);
// -1 means that the texture is not ready yet (ie not convolved/compressed yet)
if (envIndex == -1)
return false;
var envLightData = new EnvLightData();
envLightData.envShapeType = p.influenceShapeType;
envLightData.dimmer = p.dimmer;
envLightData.positionWS = p.influencePositionWS;
envLightData.influenceExtents = p.influenceExtents;
envLightData.blendNormalDistancePositive = p.blendNormalDistancePositive;
envLightData.blendNormalDistanceNegative = p.blendNormalDistanceNegative;
envLightData.blendDistancePositive = p.blendDistancePositive;
envLightData.blendDistanceNegative = p.blendDistanceNegative;
envLightData.boxSideFadePositive = p.boxSideFadePositive;
envLightData.boxSideFadeNegative = p.boxSideFadeNegative;
envLightData.right = p.influenceRight;
envLightData.up = p.influenceUp;
envLightData.forward = p.influenceForward;
envLightData.envIndex = envIndex;
envLightData.offsetLS = p.offsetLS;
m_lightList.envLights.Add(envLightData);
var envProjData = new EnvProjData();
envProjData.envShapeType = p.projectionShapeType;
envProjData.right = p.projectionRight;
envProjData.up = p.projectionUp;
envProjData.forward = p.projectionForward;
envProjData.extents = p.projectionExtents;
envProjData.positionWS = p.projectionPositionWS;
envProjData.minProjectionDistance = p.minProjectionDistance;
m_lightList.envProjs.Add(envProjData);
#if false
var additionalData = GetHDAdditionalReflectionData(probe);
var extents = probe.bounds.extents;
var influenceBlendDistancePositive = Vector3.one * probe.blendDistance;

return false;
var envLightData = new EnvLightData();
var envProjData = new EnvProjData();
envProjData.positionWS = envLightData.positionWS;
envLightData.boxSideFadePositive = Vector3.one;
envLightData.boxSideFadeNegative = Vector3.one;

case ReflectionInfluenceShape.Box:
{
envLightData.envShapeType = EnvShapeType.Box;
envProjData.envShapeType = EnvShapeType.Box;
envLightData.boxSideFadePositive = additionalData.boxSideFadePositive;
envLightData.boxSideFadeNegative = additionalData.boxSideFadeNegative;
break;

envProjData.envShapeType = EnvShapeType.Sphere;
extents = Vector3.one * additionalData.influenceSphereRadius;
break;
}

influenceBlendDistanceNegative = additionalData.blendDistanceNegative;
// remove scale from the matrix (Scale in this matrix is use to scale the widget)
envLightData.right = probe.localToWorld.GetColumn(0);
envLightData.right.Normalize();
envLightData.up = probe.localToWorld.GetColumn(1);
envLightData.up.Normalize();
envLightData.forward = probe.localToWorld.GetColumn(2);
envLightData.forward.Normalize();
envLightData.right = probe.localToWorld.GetColumn(0).normalized;
envLightData.up = probe.localToWorld.GetColumn(1).normalized;
envLightData.forward = probe.localToWorld.GetColumn(2).normalized;
envProjData.right = envLightData.right;
envProjData.up = envLightData.up;
envProjData.forward = envLightData.forward;
// Artists prefer to have blend distance inside the volume!
// So we let the current UI but we assume blendDistance is an inside factor instead

var blendDistanceNegative = Vector3.Min(probe.bounds.extents, influenceBlendDistanceNegative);
envLightData.influenceExtents = extents;
envProjData.extents = extents;
envLightData.envIndex = envIndex;
envLightData.offsetLS = probe.center; // center is misnamed, it is the offset (in local space) from center of the bounding box to the cubemap capture point
envLightData.blendDistancePositive = blendDistancePositive;

m_lightList.envProjs.Add(envProjData);
#endif
public void GetEnvLightVolumeDataAndBound(VisibleReflectionProbe probe, LightVolumeType lightVolumeType, Matrix4x4 worldToView)
public void GetEnvLightVolumeDataAndBound(VisibleReflectionProbe probe, PlanarReflectionProbe planarProbe, LightVolumeType lightVolumeType, Matrix4x4 worldToView)
{
var add = GetHDAdditionalReflectionData(probe);

}
// Return true if BakedShadowMask are enabled
public bool PrepareLightsForGPU(CommandBuffer cmd, ShadowSettings shadowSettings, CullResults cullResults, Camera camera)
public bool PrepareLightsForGPU(CommandBuffer cmd, ShadowSettings shadowSettings, CullResults cullResults, ReflectionProbeCullResults reflectionProbeCullResults, Camera camera)
{
using (new ProfilingSample(cmd, "Prepare Lights For GPU"))
{

// Redo everything but this time with envLights
int envLightCount = 0;
int probeCount = Math.Min(cullResults.visibleReflectionProbes.Count, k_MaxEnvLightsOnScreen);
var totalProbes = cullResults.visibleReflectionProbes.Count + reflectionProbeCullResults.visiblePlanarReflectionProbeCount;
int probeCount = Math.Min(totalProbes, k_MaxEnvLightsOnScreen);
for (int probeIndex = 0, numProbes = cullResults.visibleReflectionProbes.Count; (probeIndex < numProbes) && (sortCount < probeCount); probeIndex++)
for (int probeIndex = 0, numProbes = totalProbes; (probeIndex < numProbes) && (sortCount < probeCount); probeIndex++)
VisibleReflectionProbe probe = cullResults.visibleReflectionProbes[probeIndex];
HDAdditionalReflectionData additional = probe.probe.GetComponent<HDAdditionalReflectionData>();
if (probeIndex < cullResults.visibleReflectionProbes.Count)
{
VisibleReflectionProbe probe = cullResults.visibleReflectionProbes[probeIndex];
HDAdditionalReflectionData additional = probe.probe.GetComponent<HDAdditionalReflectionData>();
// probe.texture can be null when we are adding a reflection probe in the editor
if (probe.texture == null || envLightCount >= k_MaxEnvLightsOnScreen)
continue;
// probe.texture can be null when we are adding a reflection probe in the editor
if (probe.texture == null || envLightCount >= k_MaxEnvLightsOnScreen)
continue;
// Work around the culling issues. TODO: fix culling in C++.
if (probe.probe == null || !probe.probe.isActiveAndEnabled)
continue;
// Work around the culling issues. TODO: fix culling in C++.
if (probe.probe == null || !probe.probe.isActiveAndEnabled)
continue;
// Work around the data issues.
if (probe.localToWorld.determinant == 0)
{
Debug.LogError("Reflection probe " + probe.probe.name + " has an invalid local frame and needs to be fixed.");
continue;
// Work around the data issues.
if (probe.localToWorld.determinant == 0)
{
Debug.LogError("Reflection probe " + probe.probe.name + " has an invalid local frame and needs to be fixed.");
continue;
}
LightVolumeType lightVolumeType = LightVolumeType.Box;
if (additional != null && additional.influenceShape == ReflectionInfluenceShape.Sphere)
lightVolumeType = LightVolumeType.Sphere;
++envLightCount;
var logVolume = CalculateProbeLogVolume(probe.bounds);
sortKeys[sortCount++] = PackProbeKey(logVolume, lightVolumeType, 0u, probeIndex); // Sort by volume
else
{
probeIndex = probeIndex - cullResults.visibleReflectionProbes.Count;
var probe = reflectionProbeCullResults.visiblePlanarReflectionProbes[probeIndex];
LightVolumeType lightVolumeType = LightVolumeType.Box;
if (additional != null && additional.influenceShape == ReflectionInfluenceShape.Sphere)
lightVolumeType = LightVolumeType.Sphere;
++envLightCount;
// probe.texture can be null when we are adding a reflection probe in the editor
if (probe.texture == null || envLightCount >= k_MaxEnvLightsOnScreen)
continue;
float boxVolume = 8 * probe.bounds.extents.x * probe.bounds.extents.y * probe.bounds.extents.z;
float logVolume = Mathf.Clamp(256 + Mathf.Log(boxVolume, 1.05f), 0, 8191); // Allow for negative exponents
var lightVolumeType = LightVolumeType.Box;
if (probe.influenceVolume.shapeType == ShapeType.Sphere)
lightVolumeType = LightVolumeType.Sphere;
++envLightCount;
// 13 bit volume, 3 bit LightVolumeType, 16 bit index
sortKeys[sortCount++] = (uint)logVolume << 19 | (uint)lightVolumeType << 16 | ((uint)probeIndex & 0xFFFF); // Sort by volume
var logVolume = CalculateProbeLogVolume(probe.bounds);
sortKeys[sortCount++] = PackProbeKey(logVolume, lightVolumeType, 1u, probeIndex); // Sort by volume
}
}
// Not necessary yet but call it for future modification with sphere influence volume

{
// In 1. we have already classify and sorted the light, we need to use this sorted order here
uint sortKey = sortKeys[sortIndex];
LightVolumeType lightVolumeType = (LightVolumeType)((sortKey >> 16) & 0x3);
int probeIndex = (int)(sortKey & 0xFFFF);
LightVolumeType lightVolumeType;
int probeIndex;
int listType;
UnpackProbeSortKey(sortKey, out lightVolumeType, out probeIndex, out listType);
VisibleReflectionProbe probe = cullResults.visibleReflectionProbes[probeIndex];
PlanarReflectionProbe planarProbe = null;
VisibleReflectionProbe probe = default(VisibleReflectionProbe);
if (listType == 0)
probe = cullResults.visibleReflectionProbes[probeIndex];
else
planarProbe = reflectionProbeCullResults.visiblePlanarReflectionProbes[probeIndex];
if (GetEnvLightData(cmd, camera, probe))
if (GetEnvLightData(cmd, camera, probe, planarProbe))
GetEnvLightVolumeDataAndBound(probe, lightVolumeType, worldToView);
GetEnvLightVolumeDataAndBound(probe, planarProbe, lightVolumeType, worldToView);
// We make the light position camera-relative as late as possible in order
// to allow the preceding code to work with the absolute world space coordinates.

EnvLightData envLightData = m_lightList.envLights[n - 1];
envLightData.positionWS -= camPosWS;
m_lightList.envLights[n - 1] = envLightData;
var envProjData = m_lightList.envProjs[n - 1];
envProjData.positionWS -= camPosWS;
m_lightList.envProjs[n - 1] = envProjData;
}
}
}

Debug.Assert(m_lightList.bounds.Count == m_lightCount);
Debug.Assert(m_lightList.lightVolumes.Count == m_lightCount);
Debug.Assert(m_lightList.envProjs.Count == m_lightList.envLights.Count);
UpdateDataBuffers();

}
}
static float CalculateProbeLogVolume(Bounds bounds)
{
float boxVolume = 8 * bounds.extents.x * bounds.extents.y * bounds.extents.z;
float logVolume = Mathf.Clamp(256 + Mathf.Log(boxVolume, 1.05f), 0, 4095); // Allow for negative exponents
return logVolume;
}
static void UnpackProbeSortKey(uint sortKey, out LightVolumeType lightVolumeType, out int probeIndex, out int listType)
{
lightVolumeType = (LightVolumeType)((sortKey >> 17) & 0x3);
probeIndex = (int)(sortKey & 0xFFFF);
listType = (int)((sortKey >> 16) & 1);
}
static uint PackProbeKey(float logVolume, LightVolumeType lightVolumeType, uint listType, int probeIndex)
{
// 12 bit volume, 3 bit LightVolumeType, 1 bit list type, 16 bit index
return (uint)logVolume << 20 | (uint)lightVolumeType << 17 | listType << 16 | ((uint)probeIndex & 0xFFFF);
}
void VoxelLightListGeneration(CommandBuffer cmd, Camera camera, Matrix4x4 projscr, Matrix4x4 invProjscr, RenderTargetIdentifier cameraDepthBufferRT)

s_DirectionalLightDatas.SetData(m_lightList.directionalLights);
s_LightDatas.SetData(m_lightList.lights);
s_EnvLightDatas.SetData(m_lightList.envLights);
s_EnvProjDatas.SetData(m_lightList.envProjs);
s_shadowDatas.SetData(m_lightList.shadows);
// These two buffers have been set in Rebuild()

cmd.SetGlobalInt(HDShaderIDs._PunctualLightCount, m_punctualLightCount);
cmd.SetGlobalInt(HDShaderIDs._AreaLightCount, m_areaLightCount);
cmd.SetGlobalBuffer(HDShaderIDs._EnvLightDatas, s_EnvLightDatas);
cmd.SetGlobalBuffer(HDShaderIDs._EnvProjDatas, s_EnvProjDatas);
cmd.SetGlobalInt(HDShaderIDs._EnvProjCount, m_lightList.envProjs.Count);
cmd.SetGlobalBuffer(HDShaderIDs._ShadowDatas, s_shadowDatas);
cmd.SetGlobalInt(HDShaderIDs._NumTileFtplX, GetNumTileFtplX(camera));

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.hlsl


#else
uint envLightIndex = i;
#endif
IndirectLighting lighting = EvaluateBSDF_Env( context, V, posInput, preLightData, _EnvLightDatas[envLightIndex], bsdfData, _EnvLightDatas[envLightIndex].envShapeType,
IndirectLighting lighting = EvaluateBSDF_Env( context, V, posInput, preLightData, _EnvLightDatas[envLightIndex], _EnvProjDatas[envLightIndex], bsdfData, _EnvLightDatas[envLightIndex].envShapeType,
GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION, reflectionHierarchyWeight);
AccumulateIndirectLighting(lighting, aggregateLighting);
}

#else
uint envLightIndex = i;
#endif
IndirectLighting lighting = EvaluateBSDF_Env( context, V, posInput, preLightData, _EnvLightDatas[envLightIndex], bsdfData, _EnvLightDatas[envLightIndex].envShapeType,
IndirectLighting lighting = EvaluateBSDF_Env( context, V, posInput, preLightData, _EnvLightDatas[envLightIndex], _EnvProjDatas[envLightIndex], bsdfData, _EnvLightDatas[envLightIndex].envShapeType,
GPUIMAGEBASEDLIGHTINGTYPE_REFRACTION, refractionHierarchyWeight);
AccumulateIndirectLighting(lighting, aggregateLighting);
}

// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression)
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY;
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code
IndirectLighting lighting = EvaluateBSDF_Env(context, V, posInput, preLightData, envLightSky, bsdfData, ENVSHAPETYPE_SKY, GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION, reflectionHierarchyWeight);
IndirectLighting lighting = EvaluateBSDF_Env(context, V, posInput, preLightData, envLightSky, (EnvProjData) 0, bsdfData, ENVSHAPETYPE_SKY, GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION, reflectionHierarchyWeight);
AccumulateIndirectLighting(lighting, aggregateLighting);
}

// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression)
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY;
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code
IndirectLighting lighting = EvaluateBSDF_Env(context, V, posInput, preLightData, envLightSky, bsdfData, ENVSHAPETYPE_SKY, GPUIMAGEBASEDLIGHTINGTYPE_REFRACTION, refractionHierarchyWeight);
IndirectLighting lighting = EvaluateBSDF_Env(context, V, posInput, preLightData, envLightSky, (EnvProjData) 0, bsdfData, ENVSHAPETYPE_SKY, GPUIMAGEBASEDLIGHTINGTYPE_REFRACTION, refractionHierarchyWeight);
AccumulateIndirectLighting(lighting, aggregateLighting);
}
}

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoopDef.hlsl


StructuredBuffer<DirectionalLightData> _DirectionalLightDatas;
StructuredBuffer<LightData> _LightDatas;
StructuredBuffer<EnvLightData> _EnvLightDatas;
StructuredBuffer<EnvProjData> _EnvProjDatas;
StructuredBuffer<ShadowData> _ShadowDatas;
// Used by directional and spot lights

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Lighting.hlsl


#include "LightLoop/Shadow.hlsl"
#if defined(LIGHTLOOP_SINGLE_PASS) || defined(LIGHTLOOP_TILE_PASS)
#include "../Lighting/VolumeProjection.hlsl"
#include "../Lighting/LightLoop/LightLoopDef.hlsl"
#endif

28
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/PlanarReflectionProbe.cs


using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEngine.Experimental.Rendering
namespace UnityEngine.Experimental.Rendering.HDPipeline
[ExecuteInEditMode]
public class PlanarReflectionProbe : MonoBehaviour
{
[SerializeField]

public ProjectionVolumeComponent projectionVolumeReference { get { return m_ProjectionVolumeReference; } }
public InfluenceVolume influenceVolume { get { return m_InfluenceVolume; } }
public BoundingSphere boundingSphere
{
get { return m_InfluenceVolume.GetBoundingSphereAt(transform); }
}
public Texture texture { get; private set; }
public Bounds bounds { get { return m_InfluenceVolume.GetBoundsAt(transform); } }
void OnEnable()
{
ReflectionSystem.RegisterProbe(this);
}
void OnDisable()
{
ReflectionSystem.UnregisterProbe(this);
}
void OnValidate()
{
ReflectionSystem.SetProbeBoundsDirty(this);
}
}
}

32
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumes/InfluenceVolume.cs


public float sphereInfluenceRadiusOffset { get { return -sphereInfluenceFade; } }
public float sphereInfluenceNormalRadiusOffset { get { return -sphereInfluenceNormalFade; } }
public BoundingSphere GetBoundingSphereAt(Transform transform)
{
switch (shapeType)
{
default:
case ShapeType.Sphere:
return new BoundingSphere(transform.position, sphereBaseRadius);
case ShapeType.Box:
{
var position = transform.TransformPoint(boxBaseOffset);
var radius = Mathf.Max(boxBaseSize.x, Mathf.Max(boxBaseSize.y, boxBaseSize.z));
return new BoundingSphere(position, radius);
}
}
}
public Bounds GetBoundsAt(Transform transform)
{
switch (shapeType)
{
default:
case ShapeType.Sphere:
return new Bounds(transform.position, Vector3.one * sphereBaseRadius);
case ShapeType.Box:
{
var position = transform.TransformPoint(boxBaseOffset);
// TODO: Return a proper AABB based on influence box volume
return new Bounds(position, boxBaseSize);
}
}
}
}
}

20
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


// _preIntegratedFGD and _CubemapLD are unique for each BRDF
IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, EnvLightData lightData, BSDFData bsdfData, int envShapeType, int GPUImageBasedLightingType,
PreLightData preLightData, EnvLightData lightData, EnvProjData projData, BSDFData bsdfData, int envShapeType, int GPUImageBasedLightingType,
inout float hierarchyWeight)
{
IndirectLighting lighting;

float3 positionLS = positionWS - lightData.positionWS;
positionLS = mul(positionLS, worldToLocal).xyz - lightData.offsetLS; // We want to calculate the intersection from the center of the bounding box.
float3x3 worldToLS = EnvLightData_GetWorldToLocal(lightData);
float3 positionLS = EnvLightData_WorldToLocalPosition(lightData, worldToLS, positionWS);
// Projection and influence share the shape
float3x3 worldToPS = worldToLS;
float3 positionPS = positionLS;
float3 dirLS = mul(R, worldToLocal);
float sphereOuterDistance = lightData.influenceExtents.x;
float3 dirPS = mul(R, worldToPS);
float projectionDistance = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);
projectionDistance = max(projectionDistance, lightData.minProjectionDistance); // Setup projection to infinite if requested (mean no projection shape)
float projectionDistance = EnvProjData_Sphere_Project(projData, dirPS, positionPS);
// We can reuse dist calculate in LS directly in WS as there is no scaling. Also the offset is already include in lightData.positionWS
R = (positionWS + projectionDistance * R) - lightData.positionWS;

dirLS = mul(coatR, worldToLocal);
projectionDistance = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);
projectionDistance = max(projectionDistance, lightData.minProjectionDistance); // Setup projection to infinite if requested (mean no projection shape)
dirPS = mul(coatR, worldToPS);
projectionDistance = EnvProjData_Sphere_Project(projData, dirPS, positionPS);
coatR = (positionWS + projectionDistance * coatR) - lightData.positionWS;
}

30
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionProbeCullResults.cs


using UnityEngine.Assertions;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
public class ReflectionProbeCullResults
{
int[] m_PlanarReflectionProbeIndices;
PlanarReflectionProbe[] m_VisiblePlanarReflectionProbes;
public int visiblePlanarReflectionProbeCount { get; private set; }
public PlanarReflectionProbe[] visiblePlanarReflectionProbes { get { return m_VisiblePlanarReflectionProbes; } }
internal ReflectionProbeCullResults(ReflectionSystemParameters parameters)
{
Assert.IsTrue(parameters.maxPlanarReflectionProbes >= 0, "Maximum number of planar reflection probe must be positive");
visiblePlanarReflectionProbeCount = 0;
m_PlanarReflectionProbeIndices = new int[parameters.maxPlanarReflectionProbes];
m_VisiblePlanarReflectionProbes = new PlanarReflectionProbe[parameters.maxPlanarReflectionProbes];
}
public void CullPlanarReflectionProbes(CullingGroup cullingGroup, PlanarReflectionProbe[] planarReflectionProbes)
{
visiblePlanarReflectionProbeCount = cullingGroup.QueryIndices(true, m_PlanarReflectionProbeIndices, 0);
for (var i = 0; i < visiblePlanarReflectionProbeCount; ++i)
m_VisiblePlanarReflectionProbes[i] = planarReflectionProbes[m_PlanarReflectionProbeIndices[i]];
}
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionProbeCullResults.cs.meta


fileFormatVersion: 2
guid: 868c3344466c826429bef5e9bd753c2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

34
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystem.cs


using UnityEngine.Experimental.Rendering.HDPipeline.Internal;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
public static class ReflectionSystem
{
static ReflectionSystemInternal s_Instance = new ReflectionSystemInternal(ReflectionSystemParameters.Default, null);
public static void SetParameters(ReflectionSystemParameters parameters)
{
s_Instance = new ReflectionSystemInternal(parameters, s_Instance);
}
public static void RegisterProbe(PlanarReflectionProbe planarProbe)
{
s_Instance.RegisterProbe(planarProbe);
}
public static void UnregisterProbe(PlanarReflectionProbe planarProbe)
{
s_Instance.UnregisterProbe(planarProbe);
}
public static void Cull(Camera camera, ReflectionProbeCullResults results)
{
s_Instance.Cull(camera, results);
}
public static void SetProbeBoundsDirty(PlanarReflectionProbe planarProbe)
{
s_Instance.SetProbeBoundsDirty(planarProbe);
}
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystem.cs.meta


fileFormatVersion: 2
guid: 58df2fc77c2d11c49b4a2e47ed9d75cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

78
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemInternal.cs


using System.Collections.Generic;
namespace UnityEngine.Experimental.Rendering.HDPipeline.Internal
{
class ReflectionSystemInternal
{
HashSet<PlanarReflectionProbe> m_PlanarReflectionProbes;
HashSet<PlanarReflectionProbe> m_DirtyPlanarReflectionProbeBounds;
Dictionary<PlanarReflectionProbe, BoundingSphere> m_PlanarReflectionProbeBounds;
PlanarReflectionProbe[] m_PlanarReflectionProbesArray;
BoundingSphere[] m_PlanarReflectionProbeBoundsArray;
public ReflectionSystemInternal(ReflectionSystemParameters parameters, ReflectionSystemInternal previous)
{
m_PlanarReflectionProbes = new HashSet<PlanarReflectionProbe>();
m_DirtyPlanarReflectionProbeBounds = new HashSet<PlanarReflectionProbe>();
m_PlanarReflectionProbeBounds = new Dictionary<PlanarReflectionProbe, BoundingSphere>(parameters.maxPlanarReflectionProbes);
m_PlanarReflectionProbesArray = new PlanarReflectionProbe[parameters.maxPlanarReflectionProbes];
m_PlanarReflectionProbeBoundsArray = new BoundingSphere[parameters.maxPlanarReflectionProbes];
if (previous != null)
{
m_PlanarReflectionProbes.UnionWith(previous.m_PlanarReflectionProbes);
m_DirtyPlanarReflectionProbeBounds.UnionWith(m_PlanarReflectionProbes);
}
}
public void RegisterProbe(PlanarReflectionProbe planarProbe)
{
m_PlanarReflectionProbes.Add(planarProbe);
m_DirtyPlanarReflectionProbeBounds.Add(planarProbe);
}
public void UnregisterProbe(PlanarReflectionProbe planarProbe)
{
m_PlanarReflectionProbes.Remove(planarProbe);
m_DirtyPlanarReflectionProbeBounds.Remove(planarProbe);
}
public void Cull(Camera camera, ReflectionProbeCullResults results)
{
UpdateAllPlanarReflectionProbeBounds();
var cullingGroup = new CullingGroup();
cullingGroup.targetCamera = camera;
cullingGroup.SetBoundingSpheres(m_PlanarReflectionProbeBoundsArray);
cullingGroup.SetBoundingSphereCount(m_PlanarReflectionProbeBounds.Count);
results.CullPlanarReflectionProbes(cullingGroup, m_PlanarReflectionProbesArray);
cullingGroup.Dispose();
}
public void SetProbeBoundsDirty(PlanarReflectionProbe planarProbe)
{
m_DirtyPlanarReflectionProbeBounds.Add(planarProbe);
}
void UpdateAllPlanarReflectionProbeBounds()
{
if (m_DirtyPlanarReflectionProbeBounds.Count > 0)
{
m_DirtyPlanarReflectionProbeBounds.IntersectWith(m_PlanarReflectionProbes);
foreach (var planarReflectionProbe in m_DirtyPlanarReflectionProbeBounds)
UpdatePlanarReflectionProbeBounds(planarReflectionProbe);
m_PlanarReflectionProbeBounds.Values.CopyTo(m_PlanarReflectionProbeBoundsArray, 0);
m_PlanarReflectionProbeBounds.Keys.CopyTo(m_PlanarReflectionProbesArray, 0);
}
}
void UpdatePlanarReflectionProbeBounds(PlanarReflectionProbe planarReflectionProbe)
{
m_PlanarReflectionProbeBounds[planarReflectionProbe] = planarReflectionProbe.boundingSphere;
}
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemInternal.cs.meta


fileFormatVersion: 2
guid: 7ffb6818ff5985b41b56aaf521251faf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

12
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemParameters.cs


namespace UnityEngine.Experimental.Rendering.HDPipeline
{
public struct ReflectionSystemParameters
{
public static ReflectionSystemParameters Default = new ReflectionSystemParameters
{
maxPlanarReflectionProbes = 512
};
public int maxPlanarReflectionProbes;
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/ReflectionSystemParameters.cs.meta


fileFormatVersion: 2
guid: fef0534b5e07802479555345c14b1ecb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

40
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/VolumeProjection.hlsl


#ifndef UNITY_VOLUMEPROJECTION_INCLUDED
#define UNITY_VOLUMEPROJECTION_INCLUDED
float3x3 EnvProjData_GetWorldToLocal(EnvProjData projData)
{
return transpose(float3x3(projData.right, projData.up, projData.forward)); // worldToLocal assume no scaling
}
float3x3 EnvProjData_WorldToLocalPosition(EnvProjData projData, float3x3 worldToLS, float3 positionWS)
{
float3 positionLS = positionWS - projData.positionWS;
positionLS = mul(positionLS, worldToLS).xyz;
return positionLS;
}
float EnvProjData_Sphere_Project(EnvProjData projData, float3 dirPS, float3 positionPS)
{
float sphereOuterDistance = projData.extents.x;
float projectionDistance = SphereRayIntersectSimple(positionPS, dirPS, sphereOuterDistance);
projectionDistance = max(projectionDistance, projData.minProjectionDistance); // Setup projection to infinite if requested (mean no projection shape)
return projectionDistance;
}
float3x3 EnvLightData_GetWorldToLocal(EnvLightData lightData)
{
return transpose(float3x3(lightData.right, lightData.up, lightData.forward)); // worldToLocal assume no scaling
}
float3 EnvLightData_WorldToLocalPosition(EnvLightData lightData, float3x3 worldToLS, float3 positionWS)
{
// CAUTION: localToWorld is the transform use to convert the cubemap capture point to world space (mean it include the offset)
// the center of the bounding box is thus in locals space: positionLS - offsetLS
// We use this formulation as it is the one of legacy unity that was using only AABB box.
float3 positionLS = positionWS - lightData.positionWS;
positionLS = mul(positionLS, worldToLS).xyz - lightData.offsetLS;
return positionLS;
}
#endif // UNITY_VOLUMEPROJECTION_INCLUDED

9
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/VolumeProjection.hlsl.meta


fileFormatVersion: 2
guid: 72d86f1ba1cdf3e4785451f251a9dfe2
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存