浏览代码

Merge pull request #7 from Unity-Technologies/ShadowMapSupport

First draft design of shadowmap
/main
GitHub 8 年前
当前提交
89924c46
共有 42 个文件被更改,包括 1116 次插入405 次删除
  1. 30
      Assets/ScriptableRenderLoop/AdditionalLightData.cs
  2. 90
      Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs
  3. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Debug/DebugViewMaterialGBuffer.shader
  4. 37
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs
  5. 96
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs.hlsl
  6. 21
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Lighting.hlsl
  7. 332
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/Lit.hlsl
  8. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitData.hlsl
  9. 7
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitDefault.shader
  10. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitShare.hlsl
  11. 38
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Material.hlsl
  12. 5
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Unlit/Unlit.hlsl
  13. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Unlit/UnlitData.hlsl
  14. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Unlit/UnlitShare.hlsl
  15. 5
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/ShaderPass/ShaderPassForward.hlsl
  16. 45
      Assets/ScriptableRenderLoop/ShaderLibrary/API/D3D11.hlsl
  17. 32
      Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl
  18. 19
      Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl
  19. 90
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Deferred.shader
  20. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Deferred.shader.meta
  21. 16
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Forward.hlsl
  22. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Forward.hlsl.meta
  23. 25
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Shadow.hlsl
  24. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Shadow.hlsl.meta
  25. 28
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs
  26. 37
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs.hlsl
  27. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs.hlsl.meta
  28. 12
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs.meta
  29. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass.meta
  30. 17
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.cs
  31. 12
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.cs.meta
  32. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.hlsl.meta
  33. 69
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePassLoop.hlsl
  34. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePassLoop.hlsl.meta
  35. 120
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.hlsl
  36. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightingDeferred.meta
  37. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightingForward.meta
  38. 238
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitEnvTemplate.hlsl
  39. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitEnvTemplate.hlsl.meta

30
Assets/ScriptableRenderLoop/AdditionalLightData.cs


[RangeAttribute(0.0F, 100.0F)]
public float innerSpotPercent = 0.0F;
[RangeAttribute(0.0F, 1.0F)]
public float shadowDimmer = 1.0F;
public bool affectDiffuse = true;
public bool affectSpecular = true;
public static float GetInnerSpotPercent01(AdditionalLightData lightData)
{
if (lightData != null)

}
public static bool GetAffectDiffuse(AdditionalLightData lightData)
{
if (lightData != null)
return lightData.affectDiffuse;
else
return true;
}
public static bool GetAffectSpecular(AdditionalLightData lightData)
{
if (lightData != null)
return lightData.affectSpecular;
else
return true;
}
public static float GetShadowDimmer(AdditionalLightData lightData)
{
if (lightData != null)
return Mathf.Clamp(lightData.shadowDimmer, 0F, 1F);
else
return 1.0F;
}
public static int GetShadowResolution(AdditionalLightData lightData)

90
Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs


}
public const int MaxLights = 32;
public const int MaxShadows = 16; // Max shadow allowed on screen simultaneously - a point light is 6 shadows
//[SerializeField]
//ShadowSettings m_ShadowSettings = ShadowSettings.Default;
//ShadowRenderPass m_ShadowPass;
[SerializeField]
ShadowSettings m_ShadowSettings = ShadowSettings.Default;
ShadowRenderPass m_ShadowPass;
[SerializeField]
TextureSettings m_TextureSettings = TextureSettings.Default;

static private ComputeBuffer s_punctualLightList;
static private ComputeBuffer s_envLightList;
static private ComputeBuffer s_punctualShadowList;
private TextureCacheCubemap m_cubeReflTexArray;

if (s_punctualLightList != null)
s_punctualLightList.Release();
if (s_punctualShadowList != null)
s_punctualShadowList.Release();
if (s_envLightList != null)
s_envLightList.Release();
}

s_punctualLightList = new ComputeBuffer(MaxLights, System.Runtime.InteropServices.Marshal.SizeOf(typeof(PunctualLightData)));
s_envLightList = new ComputeBuffer(MaxLights, System.Runtime.InteropServices.Marshal.SizeOf(typeof(EnvLightData)));
s_punctualShadowList = new ComputeBuffer(MaxShadows, System.Runtime.InteropServices.Marshal.SizeOf(typeof(PunctualShadowData)));
m_DeferredMaterial = CreateEngineMaterial("Hidden/Unity/LightingDeferred");
m_DeferredMaterial = CreateEngineMaterial("Hidden/Unity/Deferred");
// m_ShadowPass = new ShadowRenderPass (m_ShadowSettings);
m_ShadowPass = new ShadowRenderPass (m_ShadowSettings);
m_cubeReflTexArray = new TextureCacheCubemap();
m_cubeReflTexArray.AllocTextureArray(32, (int)m_TextureSettings.reflectionCubemapSize, TextureFormat.BC6H, true);

s_punctualLightList.Release();
s_envLightList.Release();
s_punctualShadowList.Release();
if (m_DeferredMaterial) DestroyImmediate(m_DeferredMaterial);
if (m_FinalPassMaterial) DestroyImmediate(m_FinalPassMaterial);

//---------------------------------------------------------------------------------------------------------------------------------------------------
void UpdatePunctualLights(VisibleLight[] visibleLights)
void UpdatePunctualLights(VisibleLight[] visibleLights, ref ShadowOutput shadowOutput)
var shadows = new List<PunctualShadowData>();
for (int lightIndex = 0; lightIndex < Math.Min(visibleLights.Length, MaxLights); lightIndex++)
{

var additionalLightData = light.light.GetComponent<AdditionalLightData>();
var l = new PunctualLightData();

l.up = light.light.transform.up;
l.right = light.light.transform.right;
l.diffuseScale = 1.0f;
l.specularScale = 1.0f;
l.shadowDimmer = 1.0f;
var additionalLightData = light.light.GetComponent<AdditionalLightData>();
var innerConePercent = AdditionalLightData.GetInnerSpotPercent01(additionalLightData);
var cosSpotOuterHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * Mathf.Deg2Rad), 0.0f, 1.0f);
var cosSpotInnerHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * innerConePercent * Mathf.Deg2Rad), 0.0f, 1.0f); // inner cone

l.angleOffset = 2.0f;
}
l.diffuseScale = AdditionalLightData.GetAffectDiffuse(additionalLightData) ? 1.0f : 0.0f;
l.specularScale = AdditionalLightData.GetAffectSpecular(additionalLightData) ? 1.0f : 0.0f;
l.shadowDimmer = AdditionalLightData.GetShadowDimmer(additionalLightData);
l.flags = 0;
l.IESIndex = 0;
l.cookieIndex = 0;
l.shadowIndex = 0;
// Setup shadow data arrays
bool hasShadows = shadowOutput.GetShadowSliceCountLightIndex(lightIndex) != 0;
bool hasNotReachMaxLimit = shadows.Count + (light.lightType == LightType.Point ? 6 : 1) <= MaxShadows;
if (hasShadows && hasNotReachMaxLimit) // Note < MaxShadows should be check at shadowOutput creation
{
// When we have a point light, we assumed that there is 6 consecutive PunctualShadowData
l.shadowIndex = shadows.Count;
l.flags |= LightFlags.HasShadow;
for (int sliceIndex = 0; sliceIndex < shadowOutput.GetShadowSliceCountLightIndex(lightIndex); ++sliceIndex)
{
PunctualShadowData s = new PunctualShadowData();
int shadowSliceIndex = shadowOutput.GetShadowSliceIndex(lightIndex, sliceIndex);
s.worldToShadow = shadowOutput.shadowSlices[shadowSliceIndex].shadowTransform.transpose; // Transpose to go from ShadowToWorld to WorldToShadow
if (light.lightType == LightType.Spot)
{
s.shadowType = ShadowType.Spot;
}
else if (light.lightType == LightType.Point)
{
s.shadowType = ShadowType.Point;
}
else
{
s.shadowType = ShadowType.Directional;
}
shadows.Add(s);
}
}
s_punctualShadowList.SetData(shadows.ToArray());
Shader.SetGlobalBuffer("_PunctualShadowList", s_punctualShadowList);
}
void UpdateReflectionProbes(VisibleReflectionProbe[] activeReflectionProbes)

float blendDistance = Mathf.Min(maxBlendDist, probe.blendDistance);
l.innerDistance = probe.bounds.extents - new Vector3(blendDistance, blendDistance, blendDistance);
l.sliceIndex = m_cubeReflTexArray.FetchSlice(probe.texture);
l.envIndex = m_cubeReflTexArray.FetchSlice(probe.texture);
l.offsetLS = probe.center; // center is misnamed, it is the offset (in local space) from center of the bounding box to the cubemap capture point
l.blendDistance = blendDistance;

if (!CullResults.GetCullingParameters(camera, out cullingParams))
continue;
//m_ShadowPass.UpdateCullingParameters (ref cullingParams);
m_ShadowPass.UpdateCullingParameters (ref cullingParams);
//ShadowOutput shadows;
//m_ShadowPass.Render (renderLoop, cullResults, out shadows);
//UpdateLightConstants(cullResults.visibleLights /*, ref shadows */);
UpdatePunctualLights(cullResults.visibleLights);
UpdateReflectionProbes(cullResults.visibleReflectionProbes);
InitAndClearBuffer(camera, renderLoop);

}
else
{
ShadowOutput shadows;
m_ShadowPass.Render(renderLoop, cullResults, out shadows);
UpdatePunctualLights(cullResults.visibleLights, ref shadows);
UpdateReflectionProbes(cullResults.visibleReflectionProbes);
RenderDeferredLighting(camera, renderLoop);
RenderForward(cullResults, camera, renderLoop);

2
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Debug/DebugViewMaterialGBuffer.shader


#include "Color.hlsl"
// CAUTION: In case deferred lighting need to support various lighting model statically, we will require to do multicompile with different define like UNITY_MATERIAL_LIT
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Lighting.hlsl" // This include Material.hlsl
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Material.hlsl"
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/ShaderVariables.hlsl"
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Debug/DebugViewMaterial.hlsl"

37
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs


//-----------------------------------------------------------------------------
namespace UnityEngine.Experimental.ScriptableRenderLoop
{
[GenerateHLSL]
// Power of two value as they are flag
public enum LightFlags
{
HasShadow = (1 << 0),
HasCookie = (1 << 1),
HasIES = (1 << 2)
}
// These structures share between C# and hlsl need to be align on float4, so we pad them.
[GenerateHLSL]
public struct PunctualLightData

public float useDistanceAttenuation;
public Vector3 forward;
public float diffuseScale;
public float angleScale;
public float specularScale;
public float angleOffset;
public LightFlags flags;
public float diffuseScale;
public float specularScale;
public int shadowIndex;
public float angleScale;
public float angleOffset;
public Vector2 unused2;
public int IESIndex;
public int cookieIndex;
public Vector2 unused;
};
[GenerateHLSL]

public EnvShapeType envShapeType;
public Vector3 forward;
public float unused2;
public float envIndex;
public int sliceIndex;
public int unused0;
public float unused0;
public float unused1;
public float unused1;
public float unused2;
[GenerateHLSL]
public struct PlanarLightData
{
public Vector3 positionWS;
};
} // namespace UnityEngine.Experimental.ScriptableRenderLoop

96
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs.hlsl


//
//
// UnityEngine.Experimental.ScriptableRenderLoop.LightFlags: static fields
//
#define LIGHTFLAGS_HAS_SHADOW (1)
#define LIGHTFLAGS_HAS_COOKIE (2)
#define LIGHTFLAGS_HAS_IES (4)
//
// UnityEngine.Experimental.ScriptableRenderLoop.AreaShapeType: static fields
//
#define AREASHAPETYPE_RECTANGLE (0)

float3 color;
float useDistanceAttenuation;
float3 forward;
float diffuseScale;
float angleScale;
float specularScale;
float angleOffset;
int flags;
float diffuseScale;
float specularScale;
float angleScale;
float angleOffset;
float2 unused2;
int shadowIndex;
int IESIndex;
int cookieIndex;
float2 unused;
};
// Generated from UnityEngine.Experimental.ScriptableRenderLoop.AreaLightData

float3 positionWS;
int envShapeType;
float3 forward;
float unused2;
float envIndex;
int sliceIndex;
int unused0;
float unused0;
float3 offsetLS;
};
// Generated from UnityEngine.Experimental.ScriptableRenderLoop.PlanarLightData
// PackingRules = Exact
struct PlanarLightData
{
float3 positionWS;
float3 offsetLS;
float unused2;
};
//

{
return value.forward;
}
float GetDiffuseScale(PunctualLightData value)
float GetAngleScale(PunctualLightData value)
return value.diffuseScale;
return value.angleScale;
float GetSpecularScale(PunctualLightData value)
float GetAngleOffset(PunctualLightData value)
return value.specularScale;
return value.angleOffset;
int GetFlags(PunctualLightData value)
{
return value.flags;
}
float GetDiffuseScale(PunctualLightData value)
{
return value.diffuseScale;
}
float GetSpecularScale(PunctualLightData value)
{
return value.specularScale;
}
float GetAngleScale(PunctualLightData value)
int GetShadowIndex(PunctualLightData value)
return value.angleScale;
return value.shadowIndex;
float GetAngleOffset(PunctualLightData value)
int GetIESIndex(PunctualLightData value)
return value.angleOffset;
return value.IESIndex;
float2 GetUnused2(PunctualLightData value)
int GetCookieIndex(PunctualLightData value)
return value.unused2;
return value.cookieIndex;
}
float2 GetUnused(PunctualLightData value)
{
return value.unused;
}
//

{
return value.forward;
}
float GetUnused2(EnvLightData value)
float GetEnvIndex(EnvLightData value)
return value.unused2;
return value.envIndex;
}
float3 GetUp(EnvLightData value)
{

{
return value.right;
}
int GetSliceIndex(EnvLightData value)
int GetUnused0(EnvLightData value)
return value.sliceIndex;
return value.unused0;
float GetUnused0(EnvLightData value)
float GetUnused1(EnvLightData value)
return value.unused0;
return value.unused1;
float GetUnused1(EnvLightData value)
{
return value.unused1;
}
//
// Accessors for UnityEngine.Experimental.ScriptableRenderLoop.PlanarLightData
//
float3 GetPositionWS(PlanarLightData value)
float GetUnused2(EnvLightData value)
return value.positionWS;
return value.unused2;
}

21
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Lighting.hlsl


#ifndef UNITY_LIGHTING_INCLUDED
#define UNITY_LIGHTING_INCLUDED
// We need to define the macro used for env map evaluation based on the different architecture.
// Like for material we have one define by architecture.
// TODO: who setup the define for a given architecture ?
// The lighting architecture is in charge to define the light loop
// It is also in charge to define the sampling function for shadowmap, ies, cookie and reflection
// as only the lighting architecture is aware of the usage of texture atlas, array and format (latlong, 2D, cube)
#define LIGHTING // This define is used to know that we have include lighting when compiling material, else it will generate "default" function that are neutral to use Material.hlsl alone.
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs.hlsl"
#ifdef SINGLE_PASS
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.hlsl"
//#elif ...
#endif
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightingForward/LightingForward.hlsl"
#ifdef SINGLE_PASS
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePassLoop.hlsl"
//#elif ...
#endif
#endif // UNITY_LIGHTING_INCLUDED

332
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/Lit.hlsl


#ifndef UNITY_MATERIAL_LIT_INCLUDED
#define UNITY_MATERIAL_LIT_INCLUDED
//-----------------------------------------------------------------------------
// SurfaceData and BSDFData
//-----------------------------------------------------------------------------

// area light
float3x3 minV;
float ltcGGXMagnitude;
// Shadow (sampling rotation disc)
float2 unPositionSS;
};
PreLightData GetPreLightData(float3 V, float3 positionWS, Coordinate coord, BSDFData bsdfData)

preLightData.ltcGGXMagnitude = UNITY_SAMPLE_TEX2D_LOD(_LtcGGXMagnitude, uv, 0).w;
// Shadow
preLightData.unPositionSS = coord.unPositionSS;
return preLightData;
}

// GetBakedDiffuseLigthing function compute the bake lighting + emissive color to be store in emissive buffer (Deferred case)
// In forward it must be add to the final contribution.
// This function require the 3 structure surfaceData, builtinData, bsdfData because it may require both the engine side data, and data that will not be store inside the gbuffer.
float3 GetBakedDiffuseLigthing(PreLightData prelightData, SurfaceData surfaceData, BuiltinData builtinData, BSDFData bsdfData)
float3 GetBakedDiffuseLigthing(PreLightData preLightData, SurfaceData surfaceData, BuiltinData builtinData, BSDFData bsdfData)
return builtinData.bakeDiffuseLighting * prelightData.diffuseFGD * surfaceData.ambientOcclusion * bsdfData.diffuseColor + builtinData.emissiveColor * builtinData.emissiveIntensity;
return builtinData.bakeDiffuseLighting * preLightData.diffuseFGD * surfaceData.ambientOcclusion * bsdfData.diffuseColor + builtinData.emissiveColor * builtinData.emissiveIntensity;
}
//-----------------------------------------------------------------------------

// BSDF share between area light (reference) and punctual light
//-----------------------------------------------------------------------------
void BSDF( float3 V, float3 L, float3 positionWS, PreLightData prelightData, BSDFData bsdfData,
void BSDF( float3 V, float3 L, float3 positionWS, PreLightData preLightData, BSDFData bsdfData,
out float3 diffuseLighting,
out float3 specularLighting)
{

float BdotL = saturate(dot(bsdfData.bitangentWS, L));
#ifdef USE_BSDF_PRE_LAMBDAV
Vis = V_SmithJointGGXAnisoLambdaV( prelightData.TdotV, prelightData.BdotV, prelightData.NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB, prelightData.anisoGGXlambdaV);
Vis = V_SmithJointGGXAnisoLambdaV( preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB, preLightData.anisoGGXlambdaV);
Vis = V_SmithJointGGXAniso( prelightData.TdotV, prelightData.BdotV, prelightData.NdotV, TdotL, BdotL, NdotL,
Vis = V_SmithJointGGXAniso( preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB);
#endif

else
{
#ifdef USE_BSDF_PRE_LAMBDAV
Vis = V_SmithJointGGX(NdotL, prelightData.NdotV, bsdfData.roughness, prelightData.ggxLambdaV);
Vis = V_SmithJointGGX(NdotL, preLightData.NdotV, bsdfData.roughness, preLightData.ggxLambdaV);
Vis = V_SmithJointGGX(NdotL, prelightData.NdotV, bsdfData.roughness);
Vis = V_SmithJointGGX(NdotL, preLightData.NdotV, bsdfData.roughness);
#endif
D = D_GGXDividePI(NdotH, bsdfData.roughness);
}

#else
float diffuseTerm = DisneyDiffuseDividePI(prelightData.NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
float diffuseTerm = DisneyDiffuseDividePI(preLightData.NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
#endif
diffuseLighting.rgb = bsdfData.diffuseColor * diffuseTerm;
}

//-----------------------------------------------------------------------------
void EvaluateBSDF_Punctual( float3 V, float3 positionWS, PreLightData prelightData, PunctualLightData lightData, BSDFData bsdfData,
void EvaluateBSDF_Punctual( LightLoopContext lightLoopContext,
float3 V, float3 positionWS, PreLightData preLightData, PunctualLightData lightData, BSDFData bsdfData,
out float4 diffuseLighting,
out float4 specularLighting)
{

diffuseLighting = float4(0.0, 0.0, 0.0, 1.0);
specularLighting = float4(0.0, 0.0, 0.0, 1.0);
if (illuminance > 0.0f)
// TODO: measure impact of having all these dynamic branch here and the gain (or not) of testing illuminace > 0
/*
const bool hasCookie = (lightData.flags & LIGHTFLAGS_HAS_COOKIE)!= 0;
[branch] if (hasCookie && illuminance > 0.0f)
{
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
illuminance *= SampleCookie(lightData.cookieIndex, lightToWorld, L);
}
*/
const bool hasIES = (lightData.flags & LIGHTFLAGS_HAS_IES) != 0;
[branch] if (hasIES && illuminance > 0.0f)
{
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
float2 sphericalCoord = GetIESTextureCoordinate(lightToWorld, L);
illuminance *= SampleIES(lightLoopContext, lightData.IESIndex, sphericalCoord, 0).r;
}
const bool hasShadow = (lightData.flags & LIGHTFLAGS_HAS_SHADOW) != 0;
[branch] if (hasShadow && illuminance > 0.0f)
{
// Apply offset
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
float3 shadowCoord = GetShadowTextureCoordinate(lightLoopContext, lightData.shadowIndex, positionWS + offset, L);
// Caution: formula doesn't work as we are texture atlas...
// if (max3(abs(NDC.x), abs(NDC.y), 1.0f - texCoordXYZ.z) <= 1.0f) return 1.0;
float3 shadowPosDX = ddx_fine(shadowCoord);
float3 shadowPosDY = ddy_fine(shadowCoord);
float shadowAttenuation = GetShadowAttenuation(lightLoopContext, lightData.shadowIndex, shadowCoord, shadowPosDX, shadowPosDY, preLightData.unPositionSS);
shadowAttenuation = lerp(1.0, shadowAttenuation, lightData.shadowDimmer);
illuminance *= shadowAttenuation;
}
[branch] if (illuminance > 0.0f)
BSDF(V, L, positionWS, prelightData, bsdfData, diffuseLighting.rgb, specularLighting.rgb);
BSDF(V, L, positionWS, preLightData, bsdfData, diffuseLighting.rgb, specularLighting.rgb);
diffuseLighting.rgb *= lightData.color * illuminance * lightData.diffuseScale;
specularLighting.rgb *= lightData.color * illuminance * lightData.specularScale;
}

// EvaluateBSDF_Area - Reference
//-----------------------------------------------------------------------------
void IntegrateGGXAreaRef(float3 V, float3 positionWS, PreLightData prelightData, AreaLightData lightData, BSDFData bsdfData,
out float4 diffuseLighting,
out float4 specularLighting,
uint sampleCount = 512)
void IntegrateGGXAreaRef( float3 V, float3 positionWS, PreLightData preLightData, AreaLightData lightData, BSDFData bsdfData,
out float4 diffuseLighting,
out float4 specularLighting,
uint sampleCount = 512)
{
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);

if (illuminance > 0.0)
{
BSDF(V, L, positionWS, prelightData, bsdfData, localDiffuseLighting, localSpecularLighting);
BSDF(V, L, positionWS, preLightData, bsdfData, localDiffuseLighting, localSpecularLighting);
localDiffuseLighting *= lightData.color * illuminance * lightData.diffuseScale;
localSpecularLighting *= lightData.color * illuminance * lightData.specularScale;
}

// EvaluateBSDF_Area
//-----------------------------------------------------------------------------
void EvaluateBSDF_Area( float3 V, float3 positionWS, PreLightData prelightData, AreaLightData lightData, BSDFData bsdfData,
void EvaluateBSDF_Area( LightLoopContext lightLoopContext,
float3 V, float3 positionWS, PreLightData preLightData, AreaLightData lightData, BSDFData bsdfData,
IntegrateGGXAreaRef(V, positionWS, prelightData, lightData, bsdfData, diffuseLighting, specularLighting);
IntegrateGGXAreaRef(V, positionWS, preLightData, lightData, bsdfData, diffuseLighting, specularLighting);
#else
// TODO: This could be precomputed

specularLighting = float4(0.0f, 0.0f, 0.0f, 1.0f);
// TODO: Fresnel is missing here but should be present
specularLighting.rgb = LTCEvaluate(V, bsdfData.normalWS, prelightData.minV, L, lightData.twoSided) * prelightData.ltcGGXMagnitude;
specularLighting.rgb = LTCEvaluate(V, bsdfData.normalWS, preLightData.minV, L, lightData.twoSided) * preLightData.ltcGGXMagnitude;
//#ifdef DIFFUSE_LAMBERT_BRDF
// Lambert diffuse term (here it should be Disney)

}
//-----------------------------------------------------------------------------
// EvaluateBSDF_Env - Reference
// ----------------------------------------------------------------------------
// Ref: Moving Frostbite to PBR (Appendix A)
float3 IntegrateLambertIBLRef( LightLoopContext lightLoopContext,
EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
float3 L;
float NdotL;
float weightOverPdf;
ImportanceSampleLambert(u, N, tangentX, tangentY, L, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
float4 val = SampleEnv(lightLoopContext, lightData.envIndex, L, 0);
// diffuse Albedo is apply here as describe in ImportanceSampleLambert function
acc += bsdfData.diffuseColor * Lambert() * weightOverPdf * val.rgb;
}
}
return acc / sampleCount;
}
float3 IntegrateDisneyDiffuseIBLRef(LightLoopContext lightLoopContext,
float3 V, EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float NdotV = dot(N, V);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
float3 L;
float NdotL;
float weightOverPdf;
// for Disney we still use a Cosine importance sampling, true Disney importance sampling imply a look up table
ImportanceSampleLambert(u, N, tangentX, tangentY, L, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
float3 H = normalize(L + V);
float LdotH = dot(L, H);
// Note: we call DisneyDiffuse that require to multiply by Albedo / PI. Divide by PI is already taken into account
// in weightOverPdf of ImportanceSampleLambert call.
float disneyDiffuse = DisneyDiffuse(NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
// diffuse Albedo is apply here as describe in ImportanceSampleLambert function
float4 val = SampleEnv(lightLoopContext, lightData.envIndex, L, 0);
acc += bsdfData.diffuseColor * disneyDiffuse * weightOverPdf * val.rgb;
}
}
return acc / sampleCount;
}
// Ref: Moving Frostbite to PBR (Appendix A)
float3 IntegrateSpecularGGXIBLRef( LightLoopContext lightLoopContext,
float3 V, EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float NdotV = saturate(dot(N, V));
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
float VdotH;
float NdotL;
float3 L;
float weightOverPdf;
// GGX BRDF
ImportanceSampleGGX(u, V, N, tangentX, tangentY, bsdfData.roughness, NdotV,
L, VdotH, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
// Fresnel component is apply here as describe in ImportanceSampleGGX function
float3 FweightOverPdf = F_Schlick(bsdfData.fresnel0, VdotH) * weightOverPdf;
float4 val = SampleEnv(lightLoopContext, lightData.envIndex, L, 0);
acc += FweightOverPdf * val.rgb;
}
}
return acc / sampleCount;
}
//-----------------------------------------------------------------------------
// We must implement EvaluateBSDF_Env for various environment map case. For now just cube array and cube (but could add latlong later).
// As a loop can call several version inside the same lighting architecture (think about sky and reflection probes, one isolated uncompressed, the others compressed BC6H in a textures array)
// we need to implemnt various version here. To factor code we play with macro to generate the various varient.
#define UNITY_ARGS_ENV(tex) UNITY_ARGS_TEXCUBEARRAY(tex)
#define UNITY_SAMPLE_ENV_LOD(tex, coord, lightData, lod) UNITY_SAMPLE_TEXCUBEARRAY_LOD(tex, float4(coord, lightData.sliceIndex), lod)
#include "LitEnvTemplate.hlsl"
#undef UNITY_ARGS_ENV
#undef UNITY_SAMPLE_ENV_LOD
// _preIntegratedFGD and _CubemapLD are unique for each BRDF
void EvaluateBSDF_Env( LightLoopContext lightLoopContext,
float3 V, float3 positionWS, PreLightData preLightData, EnvLightData lightData, BSDFData bsdfData,
out float4 diffuseLighting,
out float4 specularLighting)
{
#ifdef LIT_DISPLAY_REFERENCE
specularLighting.rgb = IntegrateSpecularGGXIBLRef(V, lightData, bsdfData);
specularLighting.a = 1.0;
#define UNITY_ARGS_ENV(tex) UNITY_ARGS_TEXCUBE(tex)
#define UNITY_SAMPLE_ENV_LOD(tex, coord, lightData, lod) UNITY_SAMPLE_TEXCUBE_LOD(tex, float3(coord), lod)
#include "LitEnvTemplate.hlsl"
#undef UNITY_ARGS_ENV
#undef UNITY_SAMPLE_ENV_LOD
/*
#ifdef DIFFUSE_LAMBERT_BRDF
diffuseLighting.rgb = IntegrateLambertIBLRef(lightData, bsdfData);
#else
diffuseLighting.rgb = IntegrateDisneyDiffuseIBLRef(V, lightData, bsdfData);
#endif
diffuseLighting.a = 1.0;
*/
diffuseLighting = float4(0.0, 0.0, 0.0, 0.0);
#endif // UNITY_MATERIAL_LIT_INCLUDED
#else
// TODO: factor this code in common, so other material authoring don't require to rewrite everything,
// also think about how such a loop can handle 2 cubemap at the same time as old unity. Macro can allow to do that
// but we need to have UNITY_SAMPLE_ENV_LOD replace by a true function instead that is define by the lighting arcitecture.
// Also not sure how to deal with 2 intersection....
// Box and sphere are related to light property (but we have also distance based roughness etc...)
// TODO: test the strech from Tomasz
// float shrinkedRoughness = AnisotropicStrechAtGrazingAngle(bsdfData.roughness, bsdfData.perceptualRoughness, NdotV);
// Note: As explain in GetPreLightData we use normalWS and not iblNormalWS here (in case of anisotropy)
float3 rayWS = GetSpecularDominantDir(bsdfData.normalWS, preLightData.iblR, bsdfData.roughness);
float3 R = rayWS;
float weight = 1.0;
// In this code we redefine a bit the behavior of the reflcetion proble. We separate the projection volume (the proxy of the scene) form the influence volume (what pixel on the screen is affected)
// 1. First determine the projection volume
// In Unity the cubemaps are capture with the localToWorld transform of the component.
// This mean that location and oritention matter. So after intersection of proxy volume we need to convert back to world.
// 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.
float3x3 worldToLocal = transpose(float3x3(lightData.right, lightData.up, lightData.forward)); // worldToLocal assume no scaling
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.
if (lightData.envShapeType == ENVSHAPETYPE_BOX)
{
float3 rayLS = mul(rayWS, worldToLocal);
float3 boxOuterDistance = lightData.innerDistance + float3(lightData.blendDistance, lightData.blendDistance, lightData.blendDistance);
float dist = BoxRayIntersectSimple(positionLS, rayLS, -boxOuterDistance, boxOuterDistance);
// No need to normalize for fetching cubemap
// 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 + dist * rayWS) - lightData.positionWS;
// TODO: add distance based roughness
}
else if (lightData.envShapeType == ENVSHAPETYPE_SPHERE)
{
float3 rayLS = mul(rayWS, worldToLocal);
float sphereOuterDistance = lightData.innerDistance.x + lightData.blendDistance;
float dist = SphereRayIntersectSimple(positionLS, rayLS, sphereOuterDistance);
R = (positionWS + dist * rayWS) - lightData.positionWS;
}
// 2. Apply the influence volume (Box volume is used for culling whatever the influence shape)
// TODO: In the future we could have an influence volume inside the projection volume (so with a different transform, in this case we will need another transform)
if (lightData.envShapeType == ENVSHAPETYPE_SPHERE)
{
float distFade = max(length(positionLS) - lightData.innerDistance.x, 0.0);
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
}
else // ENVSHAPETYPE_BOX or ENVSHAPETYPE_NONE
{
// Calculate falloff value, so reflections on the edges of the volume would gradually blend to previous reflection.
float distFade = DistancePointBox(positionLS, -lightData.innerDistance, lightData.innerDistance);
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
}
// Smooth weighting
weight = smoothstep01(weight);
// TODO: we must always perform a weight calculation as due to tiled rendering we need to smooth out cubemap at boundaries.
// So goal is to split into two category and have an option to say if we parallax correct or not.
// TODO: compare current Morten version: offline cubemap with a particular remap + the bias in perceptualRoughnessToMipmapLevel
// to classic remap like unreal/Frobiste. The function GetSpecularDominantDir can result in a better matching in this case
// We let GetSpecularDominantDir currently as it still an improvement but not as good as it could be
float mip = perceptualRoughnessToMipmapLevel(bsdfData.perceptualRoughness);
float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, mip);
specularLighting.rgb = preLD.rgb * preLightData.specularFGD;
// Apply specular occlusion on it
specularLighting.rgb *= bsdfData.specularOcclusion;
specularLighting.a = weight;
diffuseLighting = float4(0.0, 0.0, 0.0, 0.0);
#endif
}

2
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitData.hlsl


// No guard header!
//-------------------------------------------------------------------------------------
// FragInput
// This structure gather all possible varying/interpolator for this shader.

7
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitDefault.shader


#pragma fragment Frag
#define SHADERPASS SHADERPASS_GBUFFER
#include "../../Lighting/Lighting.hlsl" // This include Material.hlsl
#include "../../Material/Material.hlsl"
#include "LitData.hlsl"
#include "LitShare.hlsl"

Pass
{
Name "DepthOnly" // Name is not used
Tags { "LightMode" = "DepthOnly" } // This will be only for transparent object based on the RenderQueue index
Tags { "LightMode" = "ShadowCaster" } // This will be only for transparent object based on the RenderQueue index
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]

#pragma fragment Frag
#define SHADERPASS SHADERPASS_FORWARD
// TEMP until pragma work in include
// #include "../../Lighting/Forward.hlsl"
#pragma multi_compile SINGLE_PASS
#include "../../Lighting/Lighting.hlsl"
#include "LitData.hlsl"
#include "LitShare.hlsl"

2
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitShare.hlsl


// No guard header!
#ifndef SHADERPASS
#error Undefine_SHADERPASS
#endif

38
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Material.hlsl


#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs.hlsl"
//-----------------------------------------------------------------------------
// Lighting part that required to be define to compile without lighting.hlsl
//-----------------------------------------------------------------------------
// In case lighting.hlsl is not include before including material.hlsl, define some neutral function, so it doesn't complain
#ifndef LIGHTING
struct LightLoopContext
{
int unused;
};
float3 GetShadowTextureCoordinate(LightLoopContext lightLoopContext, int index, float3 positionWS, float3 L)
{
return float3(0.0, 0.0, 0.0);
}
float SampleShadowCompare(LightLoopContext lightLoopContext, int index, float3 texCoord)
{
return 0.0;
}
float4 SampleIES(LightLoopContext lightLoopContext, int index, float2 sphericalTexCoord, float lod)
{
return float4(0.0, 0.0, 0.0, 0.0);
}
float4 SampleEnv(LightLoopContext lightLoopContext, int index, float3 texCoord, float lod)
{
return float4(0.0, 0.0, 0.0, 0.0);
}
#endif
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Shadow.hlsl"
//-----------------------------------------------------------------------------
// common Encode/Decode functions
//-----------------------------------------------------------------------------

#include "Builtin/BuiltinData.hlsl"
//-----------------------------------------------------------------------------
// SurfaceData
// Material definition
//-----------------------------------------------------------------------------
// Here we include all the different lighting model supported by the renderloop based on define done in .shader

5
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Unlit/Unlit.hlsl


#ifndef UNITY_UNLIT_INCLUDED
#define UNITY_UNLIT_INCLUDED
//-----------------------------------------------------------------------------
// SurfaceData and BSDFData
//-----------------------------------------------------------------------------

break;
}
}
#endif // UNITY_UNLIT_INCLUDED

2
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Unlit/UnlitData.hlsl


// No guard header!
//-------------------------------------------------------------------------------------
// FragInput
// This structure gather all possible varying/interpolator for this shader.

2
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Unlit/UnlitShare.hlsl


// No guard header!
#ifndef SHADERPASS
#error Undefine_SHADERPASS
#endif

5
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/ShaderPass/ShaderPassForward.hlsl


float4 diffuseLighting;
float4 specularLighting;
ForwardLighting(V, positionWS, preLightData, bsdfData, diffuseLighting, specularLighting);
diffuseLighting.rgb += GetBakedDiffuseLigthing(preLightData, surfaceData, builtinData, bsdfData);
float3 bakeDiffuseLighting = GetBakedDiffuseLigthing(preLightData, surfaceData, builtinData, bsdfData);
LightingLoop(V, positionWS, preLightData, bsdfData, bakeDiffuseLighting, diffuseLighting, specularLighting);
return float4(diffuseLighting.rgb + specularLighting.rgb, builtinData.opacity);
}

45
Assets/ScriptableRenderLoop/ShaderLibrary/API/D3D11.hlsl


#define UNITY_SAMPLE_TEXCUBEARRAY_LOD(tex,coord,lod) tex.SampleLevel (sampler##tex,coord, lod)
#define UNITY_SAMPLE_TEXCUBEARRAY_SAMPLER(tex,samplertex,coord) tex.Sample (sampler##samplertex,coord)
// Shadow
#define UNITY_DECLARE_SHADOWMAP(tex) Texture2D tex; SamplerComparisonState sampler##tex
#define UNITY_SAMPLE_SHADOW(tex,coord) tex.SampleCmpLevelZero (sampler##tex,(coord).xy,(coord).z)
#define UNITY_SAMPLE_SHADOW_PROJ(tex,coord) tex.SampleCmpLevelZero (sampler##tex,(coord).xy/(coord).w,(coord).z/(coord).w)
// Alternative
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName;
#define TEXTURECUBE(textureName) TextureCube textureName;
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName;
#define TEXTURE3D(textureName) Texture3D textureName;
#define SAMPLERCUBE(samplerName) SamplerState samplerName;
#define SAMPLER3D(samplerName) SamplerState samplerName;
#define SAMPLER2D_SHADOW(samplerName) SamplerComparisonState samplerName
#define SAMPLERCUBE_SHADOW(samplerName) SamplerComparisonState samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) Texture2DArray textureName, SamplerState samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) TextureCube textureName, SamplerState samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) TextureCubeArray textureName, SamplerState samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) Texture3D textureName, SamplerState samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) Texture2D textureName, SamplerComparisonState samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) Texture2DArray textureName, SamplerComparisonState samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) TextureCube textureName, SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord) textureName.Sample(samplerName, coord)
#define TEXTURE2D_ARRAY_PASS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_PASS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_PASS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_PASS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_PASS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_PASS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_PASS(textureName, samplerName) textureName, samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3((coord2).xy, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3((coord2).xy, index), lod)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3) textureName.Sample(samplerName, float4((coord3).xyz, index))
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, float4((coord3).xyz, index), lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord3).xyz, (coord3).w)

32
Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl


// OS: object space
// HS: Homogenous clip space
// CS: clips space
// TS: tangent space
// TXS: texture space
// Example: NormalWS
// normalized / unormalized vector

return saturate(dot(N, V)); // TODO: this saturate should not be necessary here
}
// ----------------------------------------------------------------------------
// Util cubemap
// ----------------------------------------------------------------------------
#define CUBEMAPFACE_POSITIVE_X 0
#define CUBEMAPFACE_NEGATIVE_X 1
#define CUBEMAPFACE_POSITIVE_Y 2
#define CUBEMAPFACE_NEGATIVE_Y 3
#define CUBEMAPFACE_POSITIVE_Z 4
#define CUBEMAPFACE_NEGATIVE_Z 5
void GetCubeFaceID(float3 dir, out int faceIndex)
{
// TODO: Use faceID intrinsic on console
float3 adir = abs(dir);
// +Z -Z
faceIndex = dir.z > 0.0f ? CUBEMAPFACE_NEGATIVE_Z : CUBEMAPFACE_POSITIVE_Z;
// +X -X
if (adir.x > adir.y && adir.x > adir.z)
{
faceIndex = dir.x > 0.0 ? CUBEMAPFACE_NEGATIVE_X : CUBEMAPFACE_POSITIVE_X;
}
// +Y -Y
else if (adir.y > adir.x && adir.y > adir.z)
{
faceIndex = dir.y > 0.0 ? CUBEMAPFACE_NEGATIVE_Y : CUBEMAPFACE_POSITIVE_Y;
}
}
#endif // UNITY_COMMON_INCLUDED

19
Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl


}
//-----------------------------------------------------------------------------
// IES Helper
//-----------------------------------------------------------------------------
float2 GetIESTextureCoordinate(float3x3 lightToWord, float3 L)
{
// IES need to be sample in light space
float3 dir = mul(lightToWord, -L); // Using matrix on left side do a transpose
// convert to spherical coordinate
float2 sphericalCoord; // .x is theta, .y is phi
// Texture is encoded with cos(phi), scale from -1..1 to 0..1
sphericalCoord.y = (dir.z * 0.5) + 0.5;
float theta = atan2(dir.y, dir.x);
sphericalCoord.x = theta * INV_TWO_PI;
return sphericalCoord;
}
//-----------------------------------------------------------------------------
// Helper function for anisotropy
//-----------------------------------------------------------------------------

90
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Deferred.shader


Shader "Hidden/Unity/Deferred"
{
Properties
{
_SrcBlend("", Float) = 1
_DstBlend("", Float) = 1
}
SubShader
{
Pass
{
ZWrite Off
Blend[_SrcBlend][_DstBlend]
HLSLPROGRAM
#pragma target 5.0
#pragma only_renderers d3d11 // TEMP: unitl we go futher in dev
#pragma vertex VertDeferred
#pragma fragment FragDeferred
#include "Common.hlsl"
// Chose supported lighting architecture in case of deferred rendering
#pragma multi_compile SINGLE_PASS
// CAUTION: In case deferred lighting need to support various lighting model statically, we will require to do multicompile with different define like UNITY_MATERIAL_DISNEYGXX
// TODO: Currently a users that add a new deferred material must also add it manually here... Need to think about it. Maybe add a multicompile inside a file in Material directory to include here ?
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Lighting.hlsl" // This include Material.hlsl
#include "Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/ShaderVariables.hlsl"
DECLARE_GBUFFER_TEXTURE(_CameraGBufferTexture);
DECLARE_GBUFFER_BAKE_LIGHTING(_CameraGBufferTexture);
UNITY_DECLARE_TEX2D(_CameraDepthTexture);
float4x4 _InvViewProjMatrix;
struct Attributes
{
float3 positionOS : POSITION;
};
struct Varyings
{
float4 positionHS : SV_POSITION;
};
Varyings VertDeferred(Attributes input)
{
// TODO: implement SV_vertexID full screen quad
// Lights are draw as one fullscreen quad
Varyings output;
float3 positionWS = TransformObjectToWorld(input.positionOS);
output.positionHS = TransformWorldToHClip(positionWS);
return output;
}
float4 FragDeferred(Varyings input) : SV_Target
{
Coordinate coord = GetCoordinate(input.positionHS.xy, _ScreenSize.zw);
// No need to manage inverse depth, this is handled by the projection matrix
float depth = _CameraDepthTexture.Load(uint3(coord.unPositionSS, 0)).x;
float3 positionWS = UnprojectToWorld(depth, coord.positionSS, _InvViewProjMatrix);
float3 V = GetWorldSpaceNormalizeViewDir(positionWS);
FETCH_GBUFFER(gbuffer, _CameraGBufferTexture, coord.unPositionSS);
BSDFData bsdfData = DECODE_FROM_GBUFFER(gbuffer);
PreLightData preLightData = GetPreLightData(V, positionWS, coord, bsdfData);
float4 diffuseLighting;
float4 specularLighting;
FETCH_BAKE_LIGHTING_GBUFFER(gbuffer, _CameraGBufferTexture, coord.unPositionSS);
float3 bakeDiffuseLighting = DECODE_BAKE_LIGHTING_FROM_GBUFFER(gbuffer);
LightingLoop(V, positionWS, preLightData, bsdfData, bakeDiffuseLighting, diffuseLighting, specularLighting);
return float4(diffuseLighting.rgb + specularLighting.rgb, 1.0);
}
ENDHLSL
}
}
Fallback Off
}

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Deferred.shader.meta


fileFormatVersion: 2
guid: 00dd221e34a6ab349a1196b0f2fab693
timeCreated: 1477266585
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

16
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Forward.hlsl


// There is two kind of lighting architectures.
// Those that are control from inside the "Material".shader with "Pass" concept like forward lighting. Call later forward lighting architecture.
// Those that are control outside the "Material".shader in a "Lighting".shader like deferred lighting. Call later deferred lighting architecture.
// When dealing with deferred lighting architecture, the renderloop is in charge to call the correct .shader.
// RenderLoop can do multiple call of various deferred lighting architecture.
// (Note: enabled variant for deferred lighting architecture are in deferred.shader)
// When dealing with forward lighting architecture, the renderloop must specify a shader pass (like "forward") but it also need
// to specify which variant of the forward lighting architecture he want (with cmd.EnableShaderKeyword()).
// Renderloop can suppose dynamically switching from regular forward to tile forward for example within the same "Forward" pass.
// The purpose of the following pragma is to define the variant available for "Forward" Pass in "Material".shader.
// If only one keyword is present it mean that only one type of forward lighting architecture is supported.
// Must match name in GetKeyword() method of forward lighting architecture .cs file
// #pragma multi_compile SINGLE_PASS -> can't use a pragma from include... (for now)

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Forward.hlsl.meta


fileFormatVersion: 2
guid: c4e4a82a4f02d5946848b918b72488fd
timeCreated: 1477269249
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

25
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Shadow.hlsl


//-----------------------------------------------------------------------------
// Shadow
// Ref: https://mynameismjp.wordpress.com/2015/02/18/shadow-sample-update/
// ----------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
// Calculates the offset to use for sampling the shadow map, based on the surface normal
//-------------------------------------------------------------------------------------------------
float3 GetShadowPosOffset(float NdotL, float3 normalWS, float2 invShadowMapSize)
{
float texelSize = 2.0 * invShadowMapSize.x;
float offsetScaleNormalize = saturate(1.0 - NdotL);
// return texelSize * OffsetScale * offsetScaleNormalize * normalWS;
return texelSize * offsetScaleNormalize * normalWS;
}
// TODO: implement various algorithm
// GetShadowAttenuation is the "default" algorithm use, material can code explicitely a particular algorithm if required.
// TODO: how this work related to shadow format ?
float GetShadowAttenuation(LightLoopContext lightLoopContext, int index, float3 shadowCoord, float3 shadowPosDX, float3 shadowPosDY, float2 unPositionSS)
{
// TODO: How to support a Gather sampling with such abstraction...
return SampleShadowCompare(lightLoopContext, index, shadowCoord);
}

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/Shadow.hlsl.meta


fileFormatVersion: 2
guid: 272a43c3c23646a4e8bc73faebaf0ee5
timeCreated: 1477313383
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

28
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs


using UnityEngine;
//-----------------------------------------------------------------------------
// structure definition
//-----------------------------------------------------------------------------
namespace UnityEngine.Experimental.ScriptableRenderLoop
{
[GenerateHLSL]
public enum ShadowType
{
Spot,
Directional,
Point
};
// A point light is 6x PunctualShadowData
[GenerateHLSL]
public struct PunctualShadowData
{
// World to ShadowMap matrix
// Include scale and bias for shadow atlas if any
public Matrix4x4 worldToShadow;
public ShadowType shadowType;
public float bias;
public Vector2 unused;
};
} // namespace UnityEngine.Experimental.ScriptableRenderLoop

37
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs.hlsl


//
// This file was automatically generated from Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs. Please don't edit by hand.
//
//
// UnityEngine.Experimental.ScriptableRenderLoop.ShadowType: static fields
//
#define SHADOWTYPE_SPOT (0)
#define SHADOWTYPE_DIRECTIONAL (1)
#define SHADOWTYPE_POINT (2)
// Generated from UnityEngine.Experimental.ScriptableRenderLoop.PunctualShadowData
// PackingRules = Exact
struct PunctualShadowData
{
float4x4 worldToShadow;
int shadowType;
float3 unused;
};
//
// Accessors for UnityEngine.Experimental.ScriptableRenderLoop.PunctualShadowData
//
float4x4 GetWorldToShadow(PunctualShadowData value)
{
return value.worldToShadow;
}
int GetShadowType(PunctualShadowData value)
{
return value.shadowType;
}
float3 GetUnused(PunctualShadowData value)
{
return value.unused;
}

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs.hlsl.meta


fileFormatVersion: 2
guid: f22956c3631d5f64388bdb93e12ec747
timeCreated: 1477268655
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

12
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/ShadowDefinition.cs.meta


fileFormatVersion: 2
guid: 548c943bc73a18d4998420073b25d44b
timeCreated: 1477263464
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass.meta


fileFormatVersion: 2
guid: 16efe1cc514ae594993f6705dacbf97d
folderAsset: yes
timeCreated: 1477266406
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

17
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.cs


using UnityEngine;
using UnityEngine.Experimental.Rendering;
using System;
//-----------------------------------------------------------------------------
// structure definition
//-----------------------------------------------------------------------------
namespace UnityEngine.Experimental.ScriptableRenderLoop
{
public class SinglePass
{
string GetKeyword()
{
return "SINGLE_PASS";
}
};
}

12
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.cs.meta


fileFormatVersion: 2
guid: cb651810696af0d4789441b1f469aa2f
timeCreated: 1477266406
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.hlsl.meta


fileFormatVersion: 2
guid: 16878a2c634119a4ab27e2c83a09b20e
timeCreated: 1477266410
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

69
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePassLoop.hlsl


StructuredBuffer<PunctualLightData> _PunctualLightList;
int _PunctualLightCount;
StructuredBuffer<EnvLightData> _EnvLightList;
int _EnvLightCount;
EnvLightData _EnvLightSky;
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path)
void LightingLoop( float3 V, float3 positionWS, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting,
out float4 diffuseLighting,
out float4 specularLighting)
{
LightLoopContext context;
ZERO_INITIALIZE(LightLoopContext, context);
diffuseLighting = float4(0.0, 0.0, 0.0, 0.0);
specularLighting = float4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < _PunctualLightCount; ++i)
{
float4 localDiffuseLighting;
float4 localSpecularLighting;
EvaluateBSDF_Punctual(context, V, positionWS, prelightData, _PunctualLightList[i], bsdfData, localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
/*
for (int i = 0; i < 4; ++i)
{
float4 localDiffuseLighting;
float4 localSpecularLighting;
EvaluateBSDF_Area(0, V, positionWS, areaLightData[i], bsdfData, localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
*/
float4 iblDiffuseLighting = float4(0.0, 0.0, 0.0, 0.0);
float4 iblSpecularLighting = float4(0.0, 0.0, 0.0, 0.0);
for (int j = 0; j < _EnvLightCount; ++j)
{
float4 localDiffuseLighting;
float4 localSpecularLighting;
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES;
EvaluateBSDF_Env(context, V, positionWS, prelightData, _EnvLightList[j], bsdfData, localDiffuseLighting, localSpecularLighting);
iblDiffuseLighting.rgb = lerp(iblDiffuseLighting.rgb, localDiffuseLighting.rgb, localDiffuseLighting.a); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting.rgb = lerp(iblSpecularLighting.rgb, localSpecularLighting.rgb, localSpecularLighting.a);
}
/*
// Sky Ibl
{
float4 localDiffuseLighting;
float4 localSpecularLighting;
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY;
EvaluateBSDF_Env(context, V, positionWS, prelightData, _EnvLightSky, bsdfData, localDiffuseLighting, localSpecularLighting);
iblDiffuseLighting.rgb = lerp(iblDiffuseLighting.rgb, localDiffuseLighting.rgb, localDiffuseLighting.a); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting.rgb = lerp(iblSpecularLighting.rgb, localSpecularLighting.rgb, localSpecularLighting.a);
}
*/
diffuseLighting += iblDiffuseLighting;
specularLighting += iblSpecularLighting;
diffuseLighting.rgb += bakeDiffuseLighting;
}

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePassLoop.hlsl.meta


fileFormatVersion: 2
guid: beb12ac3f2147dd499eee23eab1aea89
timeCreated: 1477266410
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

120
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/SinglePass/SinglePass.hlsl


//-----------------------------------------------------------------------------
// Single pass forward loop architecture
// It use maxed list of lights of the scene - use just as proof of concept - do not used in regular game
//-----------------------------------------------------------------------------
struct LightLoopContext
{
int sampleShadow;
int sampleReflection;
};
//-----------------------------------------------------------------------------
// Shadow
// ----------------------------------------------------------------------------
#define SINGLE_PASS_CONTEXT_SAMPLE_SHADOWATLAS 0
#define SINGLE_PASS_CONTEXT_SAMPLE_SHADOWARRAY 1
//TEXTURE2D_ARRAY(_ShadowArray);
//SAMPLER2D_SHADOW(sampler_ShadowArray);
//SAMPLER2D(sampler_ManualShadowArray); // TODO: settings sampler individually is not supported in shader yet...
//TEXTURE2D(_ShadowAtlas);
//SAMPLER2D_SHADOW(sampler_ShadowAtlas);
//SAMPLER2D(sampler_ManualShadowAtlas); // TODO: settings sampler individually is not supported in shader yet...
TEXTURE2D(g_tShadowBuffer) // TODO: No choice, the name is hardcoded in ShadowrenderPass.cs for now. Need to change this!
SAMPLER2D_SHADOW(samplerg_tShadowBuffer);
// Use texture atlas for shadow map
StructuredBuffer<PunctualShadowData> _PunctualShadowList;
float3 GetShadowTextureCoordinate(LightLoopContext lightLoopContext, int index, float3 positionWS, float3 L)
{
int faceIndex;
if (_PunctualShadowList[index].shadowType == SHADOWTYPE_POINT)
{
GetCubeFaceID(L, faceIndex);
}
// Note: scale and bias of shadow atlas are included in ShadowTransform
float4x4 shadowTransform = _PunctualShadowList[index + faceIndex].worldToShadow;
float4 positionTXS = mul(float4(positionWS, 1.0), shadowTransform);
return positionTXS.xyz / positionTXS.w;
}
float SampleShadowCompare(LightLoopContext lightLoopContext, int index, float3 texCoord)
{
// if (lightLoopContext.sampleShadow == SINGLE_PASS_CONTEXT_SAMPLE_SHADOWATLAS)
{
// Index could be use to get scale bias for uv but this is already merged into the shadow matrix
return SAMPLE_TEXTURE2D_SHADOW(g_tShadowBuffer, samplerg_tShadowBuffer, texCoord);
}
/*
else // SINGLE_PASS_CONTEXT_SAMPLE_SHADOWARRAY
{
return SAMPLE_TEXTURE2D_ARRAY_SHADOW(_ShadowArray, sampler_ShadowArray, texCoord, index);
}
*/
}
/*
float SampleShadow(LightLoopContext lightLoopContext, int index, float2 texCoord)
{
if (lightLoopContext.sampleShadow == SINGLE_PASS_CONTEXT_SAMPLE_SHADOWATLAS)
{
// Index could be use to get scale bias for uv but this is already merged into the shadow matrix
return SAMPLE_TEXTURE2D(_ShadowAtlas, sampler_ManualShadowArray, texCoord);
}
else // SINGLE_PASS_CONTEXT_SAMPLE_SHADOWARRAY
{
return SAMPLE_TEXTURE2D_ARRAY(_ShadowArray, sampler_ManualShadowAtlas, texCoord, index);
}
}
*/
//-----------------------------------------------------------------------------
// IES
// ----------------------------------------------------------------------------
#define SINGLE_PASS_CONTEXT_SAMPLE_IESARRAY 0
TEXTURE2D_ARRAY(_IESArray);
SAMPLER2D(sampler_IESArray);
// sphericalTexCoord is theta and phi spherical coordinate
float4 SampleIES(LightLoopContext lightLoopContext, int index, float2 sphericalTexCoord, float lod)
{
return SAMPLE_TEXTURE2D_ARRAY_LOD(_IESArray, sampler_IESArray, sphericalTexCoord, index, 0);
}
//-----------------------------------------------------------------------------
// Reflection proble / Sky
// ----------------------------------------------------------------------------
// Use texture array for reflection
TEXTURECUBE_ARRAY(_EnvTextures);
SAMPLERCUBE(sampler_EnvTextures);
TEXTURECUBE(_SkyTexture);
SAMPLERCUBE(sampler_SkyTexture); // NOTE: Sampler could be share here with _EnvTextures. Don't know if the shader compiler will complain...
#define SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES 0
#define SINGLE_PASS_CONTEXT_SAMPLE_SKY 1
// Note: index is whatever the lighting architecture want, it can contain information like in which texture to sample (in case we have a compressed BC6H texture and an uncompressed for real time reflection ?)
// EnvIndex can also be use to fetch in another array of struct (to atlas information etc...).
float4 SampleEnv(LightLoopContext lightLoopContext, int index, float3 texCoord, float lod)
{
// This code will be inlined as lightLoopContext is hardcoded in the light loop
if (lightLoopContext.sampleReflection == SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES)
{
return UNITY_SAMPLE_TEXCUBEARRAY_LOD(_EnvTextures, float4(texCoord, index), lod);
}
else // SINGLE_PASS_SAMPLE_SKY
{
return UNITY_SAMPLE_TEXCUBE_LOD(_SkyTexture, texCoord, lod);
}
}

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightingDeferred.meta


fileFormatVersion: 2
guid: df85c88f855185249aad13cf37a4952a
folderAsset: yes
timeCreated: 1476653183
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightingForward.meta


fileFormatVersion: 2
guid: 8f27521401d2efc4fb35f246e296940e
folderAsset: yes
timeCreated: 1476653182
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

238
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitEnvTemplate.hlsl


// No guard header!
//-----------------------------------------------------------------------------
// EvaluateBSDF_Env - Reference
// ----------------------------------------------------------------------------
// Ref: Moving Frostbite to PBR (Appendix A)
float3 IntegrateLambertIBLRef( EnvLightData lightData, BSDFData bsdfData,
UNITY_ARGS_ENV(_EnvTextures),
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
float3 L;
float NdotL;
float weightOverPdf;
ImportanceSampleLambert(u, N, tangentX, tangentY, L, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
float4 val = UNITY_SAMPLE_ENV_LOD(_EnvTextures, L, lightData, 0);
// diffuse Albedo is apply here as describe in ImportanceSampleLambert function
acc += bsdfData.diffuseColor * Lambert() * weightOverPdf * val.rgb;
}
}
return acc / sampleCount;
}
float3 IntegrateDisneyDiffuseIBLRef(float3 V, EnvLightData lightData, BSDFData bsdfData,
UNITY_ARGS_ENV(_EnvTextures),
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float NdotV = dot(N, V);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
float3 L;
float NdotL;
float weightOverPdf;
// for Disney we still use a Cosine importance sampling, true Disney importance sampling imply a look up table
ImportanceSampleLambert(u, N, tangentX, tangentY, L, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
float3 H = normalize(L + V);
float LdotH = dot(L, H);
// Note: we call DisneyDiffuse that require to multiply by Albedo / PI. Divide by PI is already taken into account
// in weightOverPdf of ImportanceSampleLambert call.
float disneyDiffuse = DisneyDiffuse(NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
// diffuse Albedo is apply here as describe in ImportanceSampleLambert function
float4 val = UNITY_SAMPLE_ENV_LOD(_EnvTextures, L, lightData, 0);
acc += bsdfData.diffuseColor * disneyDiffuse * weightOverPdf * val.rgb;
}
}
return acc / sampleCount;
}
// Ref: Moving Frostbite to PBR (Appendix A)
float3 IntegrateSpecularGGXIBLRef( float3 V, EnvLightData lightData, BSDFData bsdfData,
UNITY_ARGS_ENV(_EnvTextures),
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float NdotV = saturate(dot(N, V));
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
float VdotH;
float NdotL;
float3 L;
float weightOverPdf;
// GGX BRDF
ImportanceSampleGGX(u, V, N, tangentX, tangentY, bsdfData.roughness, NdotV,
L, VdotH, NdotL, weightOverPdf);
if (NdotL > 0.0)
{
// Fresnel component is apply here as describe in ImportanceSampleGGX function
float3 FweightOverPdf = F_Schlick(bsdfData.fresnel0, VdotH) * weightOverPdf;
float4 val = UNITY_SAMPLE_ENV_LOD(_EnvTextures, L, lightData, 0);
acc += FweightOverPdf * val.rgb;
}
}
return acc / sampleCount;
}
//-----------------------------------------------------------------------------
// EvaluateBSDF_Env
// ----------------------------------------------------------------------------
// _preIntegratedFGD and _CubemapLD are unique for each BRDF
void EvaluateBSDF_Env( float3 V, float3 positionWS, PreLightData prelightData, EnvLightData lightData, BSDFData bsdfData,
UNITY_ARGS_ENV(_EnvTextures),
out float4 diffuseLighting,
out float4 specularLighting)
{
#ifdef LIT_DISPLAY_REFERENCE
specularLighting.rgb = IntegrateSpecularGGXIBLRef(V, lightData, bsdfData, UNITY_PASS_ENV(_EnvTextures));
specularLighting.a = 1.0;
/*
#ifdef DIFFUSE_LAMBERT_BRDF
diffuseLighting.rgb = IntegrateLambertIBLRef(lightData, bsdfData, UNITY_PASS_ENV(_EnvTextures));
#else
diffuseLighting.rgb = IntegrateDisneyDiffuseIBLRef(V, lightData, bsdfData, UNITY_PASS_ENV(_EnvTextures));
#endif
diffuseLighting.a = 1.0;
*/
diffuseLighting = float4(0.0, 0.0, 0.0, 0.0);
#else
// TODO: factor this code in common, so other material authoring don't require to rewrite everything,
// also think about how such a loop can handle 2 cubemap at the same time as old unity. Macro can allow to do that
// but we need to have UNITY_SAMPLE_ENV_LOD replace by a true function instead that is define by the lighting arcitecture.
// Also not sure how to deal with 2 intersection....
// Box and sphere are related to light property (but we have also distance based roughness etc...)
// TODO: test the strech from Tomasz
// float shrinkedRoughness = AnisotropicStrechAtGrazingAngle(bsdfData.roughness, bsdfData.perceptualRoughness, NdotV);
// Note: As explain in GetPreLightData we use normalWS and not iblNormalWS here (in case of anisotropy)
float3 rayWS = GetSpecularDominantDir(bsdfData.normalWS, prelightData.iblR, bsdfData.roughness);
float3 R = rayWS;
float weight = 1.0;
// In this code we redefine a bit the behavior of the reflcetion proble. We separate the projection volume (the proxy of the scene) form the influence volume (what pixel on the screen is affected)
// 1. First determine the projection volume
// In Unity the cubemaps are capture with the localToWorld transform of the component.
// This mean that location and oritention matter. So after intersection of proxy volume we need to convert back to world.
// 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.
float3x3 worldToLocal = transpose(float3x3(lightData.right, lightData.up, lightData.forward)); // worldToLocal assume no scaling
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.
if (lightData.envShapeType == ENVSHAPETYPE_BOX)
{
float3 rayLS = mul(rayWS, worldToLocal);
float3 boxOuterDistance = lightData.innerDistance + float3(lightData.blendDistance, lightData.blendDistance, lightData.blendDistance);
float dist = BoxRayIntersectSimple(positionLS, rayLS, -boxOuterDistance, boxOuterDistance);
// No need to normalize for fetching cubemap
// 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 + dist * rayWS) - lightData.positionWS;
// TODO: add distance based roughness
}
else if (lightData.envShapeType == ENVSHAPETYPE_SPHERE)
{
float3 rayLS = mul(rayWS, worldToLocal);
float sphereOuterDistance = lightData.innerDistance.x + lightData.blendDistance;
float dist = SphereRayIntersectSimple(positionLS, rayLS, sphereOuterDistance);
R = (positionWS + dist * rayWS) - lightData.positionWS;
}
// 2. Apply the influence volume (Box volume is used for culling whatever the influence shape)
// TODO: In the future we could have an influence volume inside the projection volume (so with a different transform, in this case we will need another transform)
if (lightData.envShapeType == ENVSHAPETYPE_SPHERE)
{
float distFade = max(length(positionLS) - lightData.innerDistance.x, 0.0);
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
}
else // ENVSHAPETYPE_BOX or ENVSHAPETYPE_NONE
{
// Calculate falloff value, so reflections on the edges of the volume would gradually blend to previous reflection.
float distFade = DistancePointBox(positionLS, -lightData.innerDistance, lightData.innerDistance);
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
}
// Smooth weighting
weight = smoothstep01(weight);
// TODO: we must always perform a weight calculation as due to tiled rendering we need to smooth out cubemap at boundaries.
// So goal is to split into two category and have an option to say if we parallax correct or not.
// TODO: compare current Morten version: offline cubemap with a particular remap + the bias in perceptualRoughnessToMipmapLevel
// to classic remap like unreal/Frobiste. The function GetSpecularDominantDir can result in a better matching in this case
// We let GetSpecularDominantDir currently as it still an improvement but not as good as it could be
float mip = perceptualRoughnessToMipmapLevel(bsdfData.perceptualRoughness);
float4 preLD = UNITY_SAMPLE_ENV_LOD(_EnvTextures, R, lightData, mip);
specularLighting.rgb = preLD.rgb * prelightData.specularFGD;
// Apply specular occlusion on it
specularLighting.rgb *= bsdfData.specularOcclusion;
specularLighting.a = weight;
diffuseLighting = float4(0.0, 0.0, 0.0, 0.0);
#endif
}

9
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/LitEnvTemplate.hlsl.meta


fileFormatVersion: 2
guid: 22c20a34a48ade04daa95ffdc51ac052
timeCreated: 1476997917
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存