Filip Iliescu 8 年前
当前提交
e94eb9e2
共有 9 个文件被更改,包括 201 次插入84 次删除
  1. 14
      Assets/ScriptableRenderLoop/HDRenderLoop/Editor/HDRenderLoopInspector.cs
  2. 25
      Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs
  3. 12
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
  4. 39
      Assets/ScriptableRenderLoop/HDRenderLoop/SceneSettings/CommonSettings.cs
  5. 98
      Assets/ScriptableRenderLoop/HDRenderLoop/SceneSettings/Editor/CommonSettingsEditor.cs
  6. 18
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyManager.cs
  7. 38
      Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl
  8. 37
      Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl
  9. 4
      Assets/ScriptableRenderLoop/ShaderLibrary/Sampling.hlsl

14
Assets/ScriptableRenderLoop/HDRenderLoop/Editor/HDRenderLoopInspector.cs


public readonly GUIContent shadowsAtlasWidth = new GUIContent("Atlas width");
public readonly GUIContent shadowsAtlasHeight = new GUIContent("Atlas height");
public readonly GUIContent shadowsMaxShadowDistance = new GUIContent("Maximum shadow distance");
public readonly GUIContent shadowsDirectionalLightCascadeCount = new GUIContent("Directional cascade count");
public readonly GUIContent[] shadowsCascadeCounts = new GUIContent[] { new GUIContent("1"), new GUIContent("2"), new GUIContent("3"), new GUIContent("4") };
public readonly int[] shadowsCascadeCountValues = new int[] { 1, 2, 3, 4 };
public readonly GUIContent shadowsCascades = new GUIContent("Cascade values");
public readonly GUIContent tileLightLoopSettings = new GUIContent("Tile Light Loop Settings");
public readonly string[] tileLightLoopDebugTileFlagStrings = new string[] { "Punctual Light", "Area Light", "Env Light"};
public readonly GUIContent splitLightEvaluation = new GUIContent("Split light and reflection evaluation", "Toggle");

shadowParameters.enabled = EditorGUILayout.Toggle(styles.shadowsEnabled, shadowParameters.enabled);
shadowParameters.shadowAtlasWidth = Mathf.Max(0, EditorGUILayout.IntField(styles.shadowsAtlasWidth, shadowParameters.shadowAtlasWidth));
shadowParameters.shadowAtlasHeight = Mathf.Max(0, EditorGUILayout.IntField(styles.shadowsAtlasHeight, shadowParameters.shadowAtlasHeight));
shadowParameters.maxShadowDistance = Mathf.Max(0, EditorGUILayout.FloatField(styles.shadowsMaxShadowDistance, shadowParameters.maxShadowDistance));
shadowParameters.directionalLightCascadeCount = EditorGUILayout.IntPopup(styles.shadowsDirectionalLightCascadeCount, shadowParameters.directionalLightCascadeCount, styles.shadowsCascadeCounts, styles.shadowsCascadeCountValues);
EditorGUI.indentLevel++;
for (int i = 0; i < shadowParameters.directionalLightCascadeCount - 1; i++)
{
shadowParameters.directionalLightCascades[i] = Mathf.Max(0, EditorGUILayout.FloatField(shadowParameters.directionalLightCascades[i]));
}
EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(renderLoop); // Repaint

25
Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs


public Matrix4x4 invViewProjectionMatrix;
}
CommonSettings m_CommonSettings = null;
public CommonSettings commonSettings
{
set { m_CommonSettings = value; }
get { return m_CommonSettings; }
}
public override void Build()
{
#if UNITY_EDITOR

m_lightLoop.PushGlobalParams(hdCamera.camera, renderLoop);
}
void UpdateCommonSettings()
{
if(m_CommonSettings == null)
{
m_ShadowSettings.maxShadowDistance = ShadowSettings.Default.maxShadowDistance;
m_ShadowSettings.directionalLightCascadeCount = ShadowSettings.Default.directionalLightCascadeCount;
m_ShadowSettings.directionalLightCascades = ShadowSettings.Default.directionalLightCascades;
}
else
{
m_ShadowSettings.directionalLightCascadeCount = m_CommonSettings.shadowCascadeCount;
m_ShadowSettings.directionalLightCascades = new Vector3(m_CommonSettings.shadowCascadeSplit0, m_CommonSettings.shadowCascadeSplit1, m_CommonSettings.shadowCascadeSplit2);
m_ShadowSettings.maxShadowDistance = m_CommonSettings.shadowMaxDistance;
}
}
public override void Render(Camera[] cameras, RenderLoop renderLoop)
{
if (!m_LitRenderLoop.isInit)

// Do anything we need to do upon a new frame.
m_lightLoop.NewFrame();
UpdateCommonSettings();
// Set Frame constant buffer
// TODO...

12
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl


PreLightData preLightData;
// TODO: check Eric idea about doing that when writting into the GBuffer (with our forward decal)
#if 0
preLightData.NdotV = GetShiftedNdotV(bsdfData.normalWS, V); // Note: May not work with speedtree...
#else
preLightData.NdotV = GetNdotV(bsdfData.normalWS, V);
#endif
preLightData.NdotV = GetShiftedNdotV(bsdfData.normalWS, V, false);
preLightData.ggxLambdaV = GetSmithJointGGXLambdaV(preLightData.NdotV, bsdfData.roughness);

// NOTE: If we follow the theory we should use the modified normal for the different calculation implying a normal (like NDotV) and use iblNormalWS
// into function like GetSpecularDominantDir(). However modified normal is just a hack. The goal is just to stretch a cubemap, no accuracy here.
// With this in mind and for performance reasons we chose to only use modified normal to calculate R.
// iblNdotV = GetNdotV(iblNormalWS, V);
// iblNdotV = GetShiftedNdotV(iblNormalWS, V), false);
}
GetPreIntegratedFGD(iblNdotV, bsdfData.perceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD);

float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float NdotV = saturate(dot(N, V));
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d

float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float NdotV = saturate(dot(N, V));
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d

39
Assets/ScriptableRenderLoop/HDRenderLoop/SceneSettings/CommonSettings.cs


public class CommonSettings
: MonoBehaviour
{
[SerializeField]
private string m_SkyRendererTypeName = "";
[SerializeField] private string m_SkyRendererTypeName = ""; // Serialize a string because serialize a Type.
[SerializeField] float m_ShadowMaxDistance = ShadowSettings.Default.maxShadowDistance;
[SerializeField] int m_ShadowCascadeCount = ShadowSettings.Default.directionalLightCascadeCount;
[SerializeField] float m_ShadowCascadeSplit0 = ShadowSettings.Default.directionalLightCascades.x;
[SerializeField] float m_ShadowCascadeSplit1 = ShadowSettings.Default.directionalLightCascades.y;
[SerializeField] float m_ShadowCascadeSplit2 = ShadowSettings.Default.directionalLightCascades.z;
public Type skyRendererType
{
set { m_SkyRendererTypeName = value != null ? value.FullName : ""; OnSkyRendererChanged(); }

public float shadowMaxDistance { set { m_ShadowMaxDistance = value; OnValidate(); } get { return m_ShadowMaxDistance; } }
public int shadowCascadeCount { set { m_ShadowCascadeCount = value; OnValidate(); } get { return m_ShadowCascadeCount; } }
public float shadowCascadeSplit0 { set { m_ShadowCascadeSplit0 = value; OnValidate(); } get { return m_ShadowCascadeSplit0; } }
public float shadowCascadeSplit1 { set { m_ShadowCascadeSplit1 = value; OnValidate(); } get { return m_ShadowCascadeSplit1; } }
public float shadowCascadeSplit2 { set { m_ShadowCascadeSplit2 = value; OnValidate(); } get { return m_ShadowCascadeSplit2; } }
void OnEnable()
{

return;
}
if (renderLoop.commonSettings == null)
renderLoop.commonSettings = this;
else if (renderLoop.commonSettings != this)
Debug.LogWarning("Only one CommonSettings can be setup at a time.");
OnSkyRendererChanged();
}

HDRenderLoop renderLoop = Utilities.GetHDRenderLoop();
if (renderLoop == null)
{
return;
}
if (renderLoop.commonSettings == this)
renderLoop.commonSettings = null;
}
void OnValidate()
{
m_ShadowMaxDistance = Mathf.Max(0.0f, m_ShadowMaxDistance);
m_ShadowCascadeCount = Math.Min(4, Math.Max(1, m_ShadowCascadeCount));
m_ShadowCascadeSplit0 = Mathf.Min(1.0f, Mathf.Max(0.0f, m_ShadowCascadeSplit0));
m_ShadowCascadeSplit1 = Mathf.Min(1.0f, Mathf.Max(0.0f, m_ShadowCascadeSplit1));
m_ShadowCascadeSplit2 = Mathf.Min(1.0f, Mathf.Max(0.0f, m_ShadowCascadeSplit2));
OnSkyRendererChanged();
}
void OnSkyRendererChanged()

98
Assets/ScriptableRenderLoop/HDRenderLoop/SceneSettings/Editor/CommonSettingsEditor.cs


namespace UnityEngine.Experimental.ScriptableRenderLoop
{
[CustomEditor(typeof(CommonSettings))]
[CanEditMultipleObjects]
public class CommonSettingsEditor
: Editor
{

public readonly GUIContent sky = new GUIContent("Sky");
public readonly GUIContent shadows = new GUIContent("Shadows");
public readonly GUIContent maxShadowDistance = new GUIContent("Maximum shadow distance");
public readonly GUIContent shadowsDirectionalLightCascadeCount = new GUIContent("Directional cascade count");
public readonly GUIContent[] shadowsCascadeCounts = new GUIContent[] { new GUIContent("1"), new GUIContent("2"), new GUIContent("3"), new GUIContent("4") };
public readonly int[] shadowsCascadeCountValues = new int[] { 1, 2, 3, 4 };
public readonly GUIContent shadowsCascades = new GUIContent("Cascade values");
public readonly GUIContent[] shadowSplits = new GUIContent[] { new GUIContent("Split 0"), new GUIContent("Split 1"), new GUIContent("Split 2") };
}
private static Styles s_Styles = null;

}
}
private List<Type> m_SkyRendererTypes;
// Sky renderer
List<Type> m_SkyRendererTypes = new List<Type>();
private List<string> m_SkyRendererFullTypeNames = new List<string>();
private bool multipleEditing { get { return targets.Length > 1; } }
private SerializedProperty m_SkyRenderer;
private SerializedProperty m_ShadowMaxDistance;
private SerializedProperty m_ShadowCascadeCount;
private SerializedProperty[] m_ShadowCascadeSplits = new SerializedProperty[3];
m_SkyRenderer = serializedObject.FindProperty("m_SkyRendererTypeName");
m_ShadowMaxDistance = serializedObject.FindProperty("m_ShadowMaxDistance");
m_ShadowCascadeCount = serializedObject.FindProperty("m_ShadowCascadeCount");
for (int i = 0; i < 3; ++i)
m_ShadowCascadeSplits[i] = serializedObject.FindProperty(string.Format("m_ShadowCascadeSplit{0}", i));
.GetTypes()
.Where(t => t.IsSubclassOf(typeof(SkyRenderer)) && !t.IsGenericType)
.ToList();
.GetTypes()
.Where(t => t.IsSubclassOf(typeof(SkyRenderer)) && !t.IsGenericType)
.ToList();
m_SkyRendererFullTypeNames.Clear();
for(int i = 0 ; i < m_SkyRendererTypes.Count ; ++i)
for (int i = 0; i < m_SkyRendererTypes.Count; ++i)
m_SkyRendererFullTypeNames.Add(longName);
char[] separators = {'.'};
string[] tokens = longName.Split(separators);
m_SkyRendererTypeNames.Add(new GUIContent(tokens[tokens.Length - 1]));

// Add default null value.
m_SkyRendererTypeNames.Add(styles.none);
m_SkyRendererFullTypeNames.Add("");
public override void OnInspectorGUI()
void OnSkyInspectorGUI()
serializedObject.Update();
EditorGUILayout.LabelField(styles.sky);
EditorGUI.indentLevel++;
CommonSettings settings = target as CommonSettings;
// Retrieve the index of the current SkyRenderer
// Retrieve the index of the current SkyRenderer. Won't be used in case of multiple editing with different values
for(int i = 0 ; i < m_SkyRendererTypeValues.Count ; ++i )
for (int i = 0; i < m_SkyRendererTypeNames.Count; ++i)
if(m_SkyRendererTypes[i] == settings.skyRendererType)
if (m_SkyRendererFullTypeNames[i] == m_SkyRenderer.stringValue)
{
index = i;
break;

EditorGUI.showMixedValue = m_SkyRenderer.hasMultipleDifferentValues;
if (EditorGUI.EndChangeCheck())
{
m_SkyRenderer.stringValue = m_SkyRendererFullTypeNames[newValue];
}
EditorGUI.showMixedValue = false;
EditorGUI.indentLevel--;
}
void OnShadowInspectorGUI()
{
EditorGUILayout.LabelField(styles.shadows);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_ShadowMaxDistance, styles.maxShadowDistance);
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = m_ShadowCascadeCount.hasMultipleDifferentValues;
int newCascadeCount = EditorGUILayout.IntPopup(styles.shadowsDirectionalLightCascadeCount, m_ShadowCascadeCount.intValue, styles.shadowsCascadeCounts, styles.shadowsCascadeCountValues);
settings.skyRendererType = m_SkyRendererTypes[newValue];
m_ShadowCascadeCount.intValue = newCascadeCount;
}
// Compute max cascade count.
int maxCascadeCount = 0;
for (int i = 0; i < targets.Length; ++i)
{
CommonSettings settings = targets[i] as CommonSettings;
maxCascadeCount = Math.Max(maxCascadeCount, settings.shadowCascadeCount);
EditorGUI.indentLevel++;
for (int i = 0; i < maxCascadeCount - 1; i++)
{
EditorGUILayout.PropertyField(m_ShadowCascadeSplits[i], styles.shadowSplits[i]);
}
EditorGUI.indentLevel--;
EditorGUI.indentLevel--;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
OnSkyInspectorGUI();
OnShadowInspectorGUI();
serializedObject.ApplyModifiedProperties();
}

18
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyManager.cs


public class BuiltinSkyParameters
{
public Matrix4x4 viewProjMatrix;
public Matrix4x4 invViewProjMatrix;
public Vector4 screenSize;
public Mesh skyMesh;
public RenderLoop renderLoop;
public Light sunLight;
public Matrix4x4 viewProjMatrix;
public Matrix4x4 invViewProjMatrix;
public Vector4 screenSize;
public Mesh skyMesh;
public RenderLoop renderLoop;
public Light sunLight;
public RenderTargetIdentifier colorBuffer;
public RenderTargetIdentifier depthBuffer;
}
public class SkyManager

builtinParams.viewProjMatrix = m_faceCameraViewProjectionMatrix[i];
builtinParams.screenSize = m_CubemapScreenSize;
builtinParams.skyMesh = m_CubemapFaceMesh[i];
builtinParams.colorBuffer = target;
builtinParams.depthBuffer = new RenderTargetIdentifier();
m_Renderer.RenderSky(builtinParams, skyParameters);
}
}

m_BuiltinParameters.viewProjMatrix = camera.viewProjectionMatrix;
m_BuiltinParameters.screenSize = camera.screenSize;
m_BuiltinParameters.skyMesh = BuildSkyMesh(camera.camera.GetComponent<Transform>().position, m_BuiltinParameters.invViewProjMatrix, false);
m_BuiltinParameters.colorBuffer = colorBuffer;
m_BuiltinParameters.depthBuffer = depthBuffer;
Utilities.SetRenderTarget(renderLoop, colorBuffer, depthBuffer);
m_Renderer.RenderSky(m_BuiltinParameters, skyParameters);

38
Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl


}
#ifndef INTRINSIC_CUBEMAP_FACE_ID
// TODO: implement this. Is the reference implementation of cubemapID provide by AMD the reverse of our ?
// TODO: implement this. Is the reference implementation of cubemapID provide by AMD the reverse of our ?
/*
float CubemapFaceID(float3 dir)
{

// 4 VGPR, 16 FR (12 FR, 1 QR), 2 scalar
// input [-infinity, infinity] and output [-PI/2, PI/2]
float FastATan(float x)
float FastATan(float x)
{
float t0 = FastATanPos(abs(x));
return (x < 0.0) ? -t0 : t0;

// various helper
//-----------------------------------------------------------------------------
// NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping + decal
// In this case this may cause weird artifact.
// GetNdotV return a 'valid' data
float GetNdotV(float3 N, float3 V)
{
return abs(dot(N, V)); // This abs allow to limit artifact
}
// NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping + decal
// In this case normal should be modified to become valid (i.e facing camera) and not cause weird artifacts.
// but this operation adds few ALU and users may not want it. Alternative is to simply take the abs of NdotV (less correct but works too).
// Note: This code is not compatible with two sided lighting used in SpeedTree (TODO: investigate).
float GetShiftedNdotV(float3 N, float3 V)
// NdotV should not be negative for visible pixels, but it can happen due to the
// perspective projection and the normal mapping + decals. In that case, the normal
// should be modified to become valid (i.e facing the camera) to avoid weird artifacts.
// Note: certain applications (e.g. SpeedTree) make use of two-sided lighting.
float GetShiftedNdotV(inout float3 N, float3 V, bool twoSided)
// The amount we shift the normal toward the view vector is defined by the dot product.
float shiftAmount = dot(N, V);
N = shiftAmount < 0.0 ? N + V * (-shiftAmount + 1e-5f) : N;
N = normalize(N);
float NdotV = dot(N, V);
float limit = 1e-6;
if (!twoSided && NdotV < limit)
{
// We do not renormalize the normal because { abs(length(N) - 1.0) < limit }.
N += (-NdotV + limit) * V;
NdotV = limit;
}
return saturate(dot(N, V)); // TODO: this saturate should not be necessary here
return NdotV;
#endif // UNITY_COMMON_INCLUDED

37
Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl


// weightOverPdf = F(H) * G(V, L) * (L.H) / ((N.H) * (N.V))
// weightOverPdf = F(H) * 4 * (N.L) * V(V, L) * (L.H) / (N.H) with V(V, L) = G(V, L) / (4 * (N.L) * (N.V))
// Remind (L.H) == (V.H)
// F is apply outside the function
// F is apply outside the function
float TdotV = dot(tangentX, V);
float BdotV = dot(tangentY, V);
float TdotL = saturate(dot(tangentX, L));

// Ref: Listing 18 in "Moving Frostbite to PBR" + https://knarkowicz.wordpress.com/2014/12/27/analytical-dfg-term-for-ibl/
float4 IntegrateGGXAndDisneyFGD(float3 V, float3 N, float roughness, uint sampleCount)
{
float NdotV = saturate(dot(N, V));
float NdotV = GetShiftedNdotV(N, V, false);
float4 acc = float4(0.0, 0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);

}
else // Prefiltered BRDF importance sampling
{
float NdotH = saturate(dot(N, H));
// Note: since L and V are symmetric around H, LdotH == VdotH
float LdotH = saturate(dot(L, H));
// Use pre - filtered importance sampling (i.e use lower mipmap
// level for fetching sample with low probability in order
// to reduce the variance ).
// ( Reference : GPU Gem3: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html)
// Use lower MIP-map levels for fetching samples with low probabilities
// in order to reduce the variance.
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
//
// pdf = D * NdotH * jacobian, where jacobian = 1.0 / (4* LdotH).
// Since we pre - integrate the result for normal direction ,
// N == V and then NdotH == LdotH . This is why the BRDF pdf
// can be simplifed from :
// pdf = D * NdotH /(4* LdotH ) to pdf = D / 4;
// Since L and V are symmetric around H, LdotH == VdotH.
// Since we pre-integrate the result for the normal direction,
// N == V and then NdotH == LdotH. Therefore, the BRDF's pdf
// can be simplified:
// pdf = D * NdotH / (4 * LdotH) = D * 0.25;
float pdf = D_GGXNoPI(NdotH, roughness) * NdotH / (4.0 * LdotH); // TODO: Check if divide PI is required here
float omegaS = 1.0 / (sampleCount * pdf); // Solid angle associated to a sample
float NdotH = saturate(dot(N, H));
float pdf = D_GGX(NdotH, roughness) * 0.25;
float omegaS = 1.0 / (sampleCount * pdf); // Solid angle associated with the sample
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth); // Solid angle associated to a pixel of the cubemap
// Clamp is not necessary as the hardware will do it.
// mipLevel = Clamp(0.5f * log2(omegaS * invOmegaP), 0, mipmapcount);
mipLevel = 0.5 * log2(omegaS * invOmegaP); // Clamp is not necessary as the hardware will do it.
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth); // Solid angle associated with the pixel of the cubemap
mipLevel = 0.5 * log2(omegaS * invOmegaP) + 1.0; // Clamp is not necessary as the hardware will do it
}
if (NdotL > 0.0f)

4
Assets/ScriptableRenderLoop/ShaderLibrary/Sampling.hlsl


// Ref: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
uint ReverseBits32(uint bits)
{
#if 0 // Shader model 5
#if 1 // Shader model 5
return reversebits(bits);
#else
bits = (bits << 16) | (bits >> 16);

Ns = UniformSampleSphere(u1, u2);
// Transform from unit sphere to world space
// Transform from unit sphere to world space
P = radius * Ns + localToWorld[3].xyz;
// pdf is inverse of area

正在加载...
取消
保存