浏览代码

Update lightweight pipeline / SRP version

/main
Tim Cooper 7 年前
当前提交
85affe1f
共有 675 个文件被更改,包括 4619 次插入1156 次删除
  1. 4
      MaterialGraphProject/Assets/SRP.meta
  2. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline.meta
  3. 2
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Camera/CameraSwitcher.cs
  4. 82
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Camera/FreeCamera.cs
  5. 19
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/CommandBufferPool.cs
  6. 107
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugActionManager.cs
  7. 14
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugItemHandler.cs
  8. 6
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugItemUI.cs
  9. 3
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuManager.cs
  10. 56
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuState.cs
  11. 3
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuUI.cs
  12. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuUpdater.cs
  13. 14
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugPanel.cs
  14. 39
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugPanelUI.cs
  15. 1
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Debugging.cs
  16. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Editor/DebugMenuEditor.cs
  17. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateBool.cs
  18. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateColor.cs
  19. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateFloat.cs
  20. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateInt.cs
  21. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateUInt.cs
  22. 2
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderGenerator/Editor/CSharpToHLSL.cs
  23. 193
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/BSDF.hlsl
  24. 26
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Common.hlsl
  25. 46
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/CommonLighting.hlsl
  26. 29
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/CommonMaterial.hlsl
  27. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/EntityLighting.hlsl
  28. 8
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Fibonacci.hlsl
  29. 174
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/ImageBasedLighting.hlsl
  30. 9
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/PerPixelDisplacement.hlsl
  31. 9
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Shadow/Shadow.hlsl
  32. 310
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl
  33. 46
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Shadow/ShadowSampling.hlsl
  34. 10
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/VolumeRendering.hlsl
  35. 32
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Wind.hlsl
  36. 2
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Singleton.cs
  37. 90
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/TextureCache.cs
  38. 28
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/LegacyShadersToLightweightPipelineUpgrader.cs
  39. 46
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/LightweightAssetInspector.cs
  40. 72
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/LightweightPipelineUpgraders.cs
  41. 3
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/ShaderGUI/LightweightUnlitGUI.cs
  42. 8
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/StandardToLightweightMaterialUpgrader.cs
  43. 1
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/UpgradeCommon.cs
  44. 888
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipeline.cs
  45. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset
  46. 98
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.cs
  47. 106
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineUtils.cs
  48. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Materials/Lightweight-DefaultParticle.mat
  49. 2
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Materials/Lightweight-StandardShader.mat
  50. 4
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Materials/Lightweight-StandardSimpleLighting.mat
  51. 67
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightUnlit.shader
  52. 84
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Templates/lightweightSubshaderPBR.template
  53. 6
      MaterialGraphProject/Packages/manifest.json
  54. 8
      MaterialGraphProject/Assets/SRP/PostProcessing.meta
  55. 249
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/CoreUtils.cs
  56. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/CoreUtils.cs.meta
  57. 121
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/CoreEditorUtils.cs
  58. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/CoreEditorUtils.cs.meta
  59. 60
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/PropertyFetcher.cs
  60. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/PropertyFetcher.cs.meta
  61. 10
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Inputs.meta
  62. 60
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ProfilingSample.cs
  63. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ProfilingSample.cs.meta
  64. 10
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/Editor.meta
  65. 23
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.compute
  66. 10
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.compute.meta
  67. 33
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.cs
  68. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.cs.meta
  69. 164
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyAsset.cs
  70. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyAsset.cs.meta
  71. 17
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyDefinition.asset
  72. 10
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyDefinition.asset.meta
  73. 9
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Shadow.meta
  74. 437
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/ShaderGUI/LightweightStandardGUI.cs
  75. 253
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/ShaderGUI/LightweightStandardSimpleLightingGUI.cs
  76. 24
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightConstantBuffer.cs
  77. 13
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightConstantBuffer.cs.meta
  78. 46
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightBlit.shader
  79. 10
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightBlit.shader.meta
  80. 46
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCopyDepth.shader
  81. 10
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCopyDepth.shader.meta
  82. 135
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.cginc
  83. 380
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.cginc
  84. 226
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.cginc
  85. 9
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.cginc.meta
  86. 20
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.cginc
  87. 9
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.cginc.meta
  88. 93
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShadows.cginc
  89. 142
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandard.shader
  90. 172
      MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardSimpleLighting.shader
  91. 39
      MaterialGraphProject/Assets/SRP/PostProcessing/.gitignore
  92. 0
      MaterialGraphProject/Assets/SRP/PostProcessing/.npmignore
  93. 21
      MaterialGraphProject/Assets/SRP/PostProcessing/LICENSE
  94. 8
      MaterialGraphProject/Assets/SRP/PostProcessing/PostProcessing/Editor.meta

4
MaterialGraphProject/Assets/SRP.meta


fileFormatVersion: 2
guid: c29d1b9487ffd4a729adcbe0f197a3f4
guid: 612579e2db831754e87f0b4b938dbfaf
timeCreated: 1505274236
timeCreated: 1504184175
licenseType: Pro
DefaultImporter:
externalObjects: {}

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline.meta


fileFormatVersion: 2
guid: fd470011795144262bf5aa4bf5f396a1
guid: 22c204b70537f8d46a054fa00bf16298
timeCreated: 1505274236
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:

2
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Camera/CameraSwitcher.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering

82
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Camera/FreeCamera.cs


using System.Collections.Generic;
[ExecuteInEditMode]
public float m_MoveSpeed = 50.0f;
public float m_MoveSpeed = 10.0f;
public float m_Turbo = 10.0f;
private static string kMouseX = "Mouse X";

private static string kVertical = "Vertical";
private static string kHorizontal = "Horizontal";
private string[] m_RequiredInputAxes = { kMouseX, kMouseY, kRightStickX, kRightStickY, kVertical, kHorizontal };
private bool m_Valid = true;
m_Valid = Debugging.CheckRequiredInputAxisMapping(m_RequiredInputAxes);
RegisterInputs();
}
void RegisterInputs()
{
#if UNITY_EDITOR
List <InputManagerEntry> inputEntries = new List<InputManagerEntry>();
// Add new bindings
inputEntries.Add(new InputManagerEntry { name = kRightStickX, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Fourth, sensitivity = 1.0f, gravity = 1.0f, deadZone = 0.2f });
inputEntries.Add(new InputManagerEntry { name = kRightStickY, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Fifth, sensitivity = 1.0f, gravity = 1.0f, deadZone = 0.2f, invert = true });
InputRegistering.RegisterInputs(inputEntries);
#endif
if (m_Valid)
float inputRotateAxisX = 0.0f;
float inputRotateAxisY = 0.0f;
if (Input.GetMouseButton(1))
float inputRotateAxisX = 0.0f;
float inputRotateAxisY = 0.0f;
if (Input.GetMouseButton(1))
{
inputRotateAxisX = Input.GetAxis(kMouseX) * m_LookSpeedMouse;
inputRotateAxisY = Input.GetAxis(kMouseY) * m_LookSpeedMouse;
}
inputRotateAxisX += (Input.GetAxis(kRightStickX) * m_LookSpeedController * Time.deltaTime);
inputRotateAxisY += (Input.GetAxis(kRightStickY) * m_LookSpeedController * Time.deltaTime);
inputRotateAxisX = Input.GetAxis(kMouseX) * m_LookSpeedMouse;
inputRotateAxisY = Input.GetAxis(kMouseY) * m_LookSpeedMouse;
}
inputRotateAxisX += (Input.GetAxis(kRightStickX) * m_LookSpeedController * Time.deltaTime);
inputRotateAxisY += (Input.GetAxis(kRightStickY) * m_LookSpeedController * Time.deltaTime);
float inputVertical = Input.GetAxis(kVertical);
float inputHorizontal = Input.GetAxis(kHorizontal);
float inputVertical = Input.GetAxis(kVertical);
float inputHorizontal = Input.GetAxis(kHorizontal);
bool moved = inputRotateAxisX != 0.0f || inputRotateAxisY != 0.0f || inputVertical != 0.0f || inputHorizontal != 0.0f;
if (moved)
{
float rotationX = transform.localEulerAngles.x;
float newRotationY = transform.localEulerAngles.y + inputRotateAxisX;
bool moved = inputRotateAxisX != 0.0f || inputRotateAxisY != 0.0f || inputVertical != 0.0f || inputHorizontal != 0.0f;
if (moved)
{
float rotationX = transform.localEulerAngles.x;
float newRotationY = transform.localEulerAngles.y + inputRotateAxisX;
// Weird clamping code due to weird Euler angle mapping...
float newRotationX = (rotationX - inputRotateAxisY);
if (rotationX <= 90.0f && newRotationX >= 0.0f)
newRotationX = Mathf.Clamp(newRotationX, 0.0f, 90.0f);
if (rotationX >= 270.0f)
newRotationX = Mathf.Clamp(newRotationX, 270.0f, 360.0f);
// Weird clamping code due to weird Euler angle mapping...
float newRotationX = (rotationX - inputRotateAxisY);
if (rotationX <= 90.0f && newRotationX >= 0.0f)
newRotationX = Mathf.Clamp(newRotationX, 0.0f, 90.0f);
if (rotationX >= 270.0f)
newRotationX = Mathf.Clamp(newRotationX, 270.0f, 360.0f);
transform.localRotation = Quaternion.Euler(newRotationX, newRotationY, transform.localEulerAngles.z);
transform.localRotation = Quaternion.Euler(newRotationX, newRotationY, transform.localEulerAngles.z);
float moveSpeed = Time.deltaTime * m_MoveSpeed;
if (Input.GetMouseButton(1))
moveSpeed *= Input.GetKey(KeyCode.LeftShift) ? m_Turbo : 1.0f;
else
moveSpeed *= Input.GetAxis("Fire1") > 0.0f ? m_Turbo : 1.0f;
transform.position += transform.forward * moveSpeed * inputVertical;
transform.position += transform.right * moveSpeed * inputHorizontal;
}
float moveSpeed = Time.deltaTime * m_MoveSpeed;
if (Input.GetMouseButton(1))
moveSpeed *= Input.GetKey(KeyCode.LeftShift) ? m_Turbo : 1.0f;
else
moveSpeed *= Input.GetAxis("Fire1") > 0.0f ? m_Turbo : 1.0f;
transform.position += transform.forward * moveSpeed * inputVertical;
transform.position += transform.right * moveSpeed * inputHorizontal;
}
}
}

19
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/CommandBufferPool.cs


namespace UnityEngine.Experimental.Rendering
{
internal class ObjectPool<T> where T : new()
class ObjectPool<T> where T : new()
private readonly Stack<T> m_Stack = new Stack<T>();
private readonly UnityAction<T> m_ActionOnGet;
private readonly UnityAction<T> m_ActionOnRelease;
readonly Stack<T> m_Stack = new Stack<T>();
readonly UnityAction<T> m_ActionOnGet;
readonly UnityAction<T> m_ActionOnRelease;
public int countAll { get; private set; }
public int countActive { get { return countAll - countInactive; } }

m_Stack.Push(element);
}
}
private static ObjectPool<CommandBuffer> m_BufferPool = new ObjectPool<CommandBuffer>(null, x => x.Clear());
static ObjectPool<CommandBuffer> s_BufferPool = new ObjectPool<CommandBuffer>(null, x => x.Clear());
var cmd = m_BufferPool.Get();
var cmd = s_BufferPool.Get();
var cmd = m_BufferPool.Get();
var cmd = s_BufferPool.Get();
cmd.name = name;
return cmd;
}

m_BufferPool.Release(buffer);
s_BufferPool.Release(buffer);
}
}
}

107
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugActionManager.cs


using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering

persistent.repeatMode = DebugActionRepeatMode.Never;
AddAction(DebugAction.MakePersistent, persistent);
AddAction(DebugAction.MoveVertical, new DebugActionDesc { axisTrigger = kDPadVertical, repeatMode = DebugActionRepeatMode.Delay, repeatDelay = 0.2f });
AddAction(DebugAction.MoveHorizontal, new DebugActionDesc { axisTrigger = kDPadHorizontal, repeatMode = DebugActionRepeatMode.Delay, repeatDelay = 0.2f });
AddAction(DebugAction.MoveVertical, new DebugActionDesc { axisTrigger = kDPadVertical, repeatMode = DebugActionRepeatMode.Delay, repeatDelay = 0.4f });
AddAction(DebugAction.MoveHorizontal, new DebugActionDesc { axisTrigger = kDPadHorizontal, repeatMode = DebugActionRepeatMode.Delay, repeatDelay = 0.4f });
}
DebugActionManager()

void RegisterInputs()
{
#if UNITY_EDITOR
// Grab reference to input manager
var currentSelection = UnityEditor.Selection.activeObject;
UnityEditor.EditorApplication.ExecuteMenuItem("Edit/Project Settings/Input");
var inputManager = UnityEditor.Selection.activeObject;
// Wrap in serialized object
var soInputManager = new UnityEditor.SerializedObject(inputManager);
var spAxes = soInputManager.FindProperty("m_Axes");
List <InputManagerEntry > inputEntries = new List<InputManagerEntry>();
new InputManagerEntry { name = kEnableDebugBtn1, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "left ctrl", altBtnPositive = "joystick button 8" }.WriteEntry(spAxes);
new InputManagerEntry { name = kEnableDebugBtn2, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "backspace", altBtnPositive = "joystick button 9" }.WriteEntry(spAxes);
inputEntries.Add(new InputManagerEntry { name = kEnableDebugBtn1, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "left ctrl", altBtnPositive = "joystick button 8" });
inputEntries.Add(new InputManagerEntry { name = kEnableDebugBtn2, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "backspace", altBtnPositive = "joystick button 9" });
inputEntries.Add(new InputManagerEntry { name = kDebugNextBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "page down", altBtnPositive = "joystick button 5" });
inputEntries.Add(new InputManagerEntry { name = kDebugPreviousBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "page up", altBtnPositive = "joystick button 4" });
new InputManagerEntry { name = kDebugNextBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "page down", altBtnPositive = "joystick button 5" }.WriteEntry(spAxes);
new InputManagerEntry { name = kDebugPreviousBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "page up", altBtnPositive = "joystick button 4" }.WriteEntry(spAxes);
new InputManagerEntry { name = kDPadHorizontal, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "right", btnNegative = "left", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }.WriteEntry(spAxes);
new InputManagerEntry { name = kDPadHorizontal, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Sixth, btnPositive = "right", btnNegative = "left", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }.WriteEntry(spAxes);
new InputManagerEntry { name = kDPadVertical, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "up", btnNegative = "down", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }.WriteEntry(spAxes);
new InputManagerEntry { name = kDPadVertical, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Seventh, btnPositive = "up", btnNegative = "down", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f }.WriteEntry(spAxes);
inputEntries.Add(new InputManagerEntry { name = kDPadHorizontal, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "right", btnNegative = "left", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f });
inputEntries.Add(new InputManagerEntry { name = kDPadHorizontal, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Sixth, btnPositive = "right", btnNegative = "left", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f });
inputEntries.Add(new InputManagerEntry { name = kDPadVertical, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "up", btnNegative = "down", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f });
inputEntries.Add(new InputManagerEntry { name = kDPadVertical, kind = InputManagerEntry.Kind.Axis, axis = InputManagerEntry.Axis.Seventh, btnPositive = "up", btnNegative = "down", gravity = 1000.0f, deadZone = 0.001f, sensitivity = 1000.0f });
inputEntries.Add(new InputManagerEntry { name = kValidateBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "return", altBtnPositive = "joystick button 0" });
inputEntries.Add(new InputManagerEntry { name = kPersistentBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "right shift", altBtnPositive = "joystick button 2" });
new InputManagerEntry { name = kValidateBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "return", altBtnPositive = "joystick button 0" }.WriteEntry(spAxes);
new InputManagerEntry { name = kPersistentBtn, kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "right shift", altBtnPositive = "joystick button 2" }.WriteEntry(spAxes);
// Commit
soInputManager.ApplyModifiedProperties();
UnityEditor.Selection.activeObject = currentSelection;
InputRegistering.RegisterInputs(inputEntries);
#if UNITY_EDITOR
class InputManagerEntry
{
public enum Kind { KeyOrButton, Mouse, Axis }
public enum Axis { X, Y, Third, Fourth, Fifth, Sixth, Seventh, Eigth }
public enum Joy { All, First, Second }
public string name = "";
public string desc = "";
public string btnNegative = "";
public string btnPositive = "";
public string altBtnNegative = "";
public string altBtnPositive = "";
public float gravity = 0.0f;
public float deadZone = 0.0f;
public float sensitivity = 0.0f;
public bool snap = false;
public bool invert = false;
public Kind kind = Kind.Axis;
public Axis axis = Axis.X;
public Joy joystick = Joy.All;
bool InputAlreadyRegistered(string name, Kind kind, UnityEditor.SerializedProperty spAxes)
{
for (var i = 0; i < spAxes.arraySize; ++i )
{
var spAxis = spAxes.GetArrayElementAtIndex(i);
var axisName = spAxis.FindPropertyRelative("m_Name").stringValue;
var kindValue = spAxis.FindPropertyRelative("type").intValue;
if (axisName == name && (int)kind == kindValue)
return true;
}
return false;
}
public void WriteEntry(UnityEditor.SerializedProperty spAxes)
{
if(InputAlreadyRegistered(name, kind, spAxes))
return;
spAxes.InsertArrayElementAtIndex(spAxes.arraySize);
var spAxis = spAxes.GetArrayElementAtIndex(spAxes.arraySize - 1);
spAxis.FindPropertyRelative("m_Name").stringValue = name;
spAxis.FindPropertyRelative("descriptiveName").stringValue = desc;
spAxis.FindPropertyRelative("negativeButton").stringValue = btnNegative;
spAxis.FindPropertyRelative("altNegativeButton").stringValue = altBtnNegative;
spAxis.FindPropertyRelative("positiveButton").stringValue = btnPositive;
spAxis.FindPropertyRelative("altPositiveButton").stringValue = altBtnPositive;
spAxis.FindPropertyRelative("gravity").floatValue = gravity;
spAxis.FindPropertyRelative("dead").floatValue = deadZone;
spAxis.FindPropertyRelative("sensitivity").floatValue = sensitivity;
spAxis.FindPropertyRelative("snap").boolValue = snap;
spAxis.FindPropertyRelative("invert").boolValue = invert;
spAxis.FindPropertyRelative("type").intValue = (int)kind;
spAxis.FindPropertyRelative("axis").intValue = (int)axis;
spAxis.FindPropertyRelative("joyNum").intValue = (int)joystick;
}
}
#endif
}
}

14
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugItemHandler.cs


using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using System;

m_DebugItem = item;
}
// Method user needs to override for specific value clamping.
public virtual void ClampValues(Func<object> getter, Action<object> setter) {}
// Method user needs to override for specific value validation.
public virtual void ValidateValues(Func<object> getter, Action<object> setter) {}
// Method that will create UI items for runtime debug menu.
public abstract DebugItemUI BuildGUI(GameObject parent);

public void OnEditorGUI()
{
if (m_DebugItem.runtimeOnly)
return;
if(OnEditorGUIImpl())
{
DebugMenuUI.changed = true;

m_Max = max;
}
public override void ClampValues(Func<object> getter, Action<object> setter)
public override void ValidateValues(Func<object> getter, Action<object> setter)
{
setter(Mathf.Clamp((float)getter(), m_Min, m_Max));
}

m_Max = max;
}
public override void ClampValues(Func<object> getter, Action<object> setter)
public override void ValidateValues(Func<object> getter, Action<object> setter)
{
setter(Math.Min(m_Max, Math.Max(m_Min, (uint)getter())));
}

6
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugItemUI.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering
{

protected DebugItem m_DebugItem = null;
public bool dynamicDisplay { get { return (m_DebugItem.flags & DebugItemFlag.DynamicDisplay) != 0; } }
public DebugItem debugItem { get { return m_DebugItem; } }
protected DebugItemUI(DebugItem debugItem)
{

3
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuManager.cs


using System;
using System.Linq;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

if(m_DebugMenuState != null && m_DebugMenuStateDirty)
{
m_DebugMenuStateDirty = false;
m_DebugMenuState.UpdateAllDebugItems();
m_DebugMenuState.ReInitializeDebugItemStates();
}
m_DebugMenuUI.Update();

56
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuState.cs


using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
[Serializable]
public abstract class DebugItemState
: ScriptableObject
{

#if UNITY_EDITOR
UnityEditor.Undo.undoRedoPerformed += OnUndoRedoPerformed;
#endif
DebugMenuManager.instance.SetDebugMenuState(this);
}
public void OnDisable()
{
DebugMenuManager.instance.SetDebugMenuState(null);
#if UNITY_EDITOR
UnityEditor.Undo.undoRedoPerformed -= OnUndoRedoPerformed;
#endif
}
public void ReInitializeDebugItemStates()
{
CleanUp();
// Populate item states
DebugMenuManager dmm = DebugMenuManager.instance;
for (int panelIdx = 0; panelIdx < dmm.panelCount; ++panelIdx)

if (debugItemState == null)
{
debugItemState = item.handler.CreateDebugItemState();
debugItemState.hideFlags = HideFlags.DontSave;
debugItemState.Initialize(item);
debugItemState.SetValue(item.GetValue());
AddDebugItemState(debugItemState);
if (debugItemState != null)
{
debugItemState.hideFlags = HideFlags.DontSave;
debugItemState.Initialize(item);
debugItemState.SetValue(item.GetValue());
AddDebugItemState(debugItemState);
}
else
{
Debug.LogWarning(String.Format("DebugItemState for item {0} of type {1} is not provided.\nDid you implement CreateDebugItemState in your custom Handler?", item.name, item.type));
}
DebugMenuManager.instance.SetDebugMenuState(this);
UpdateAllDebugItems();
public void OnDisable()
private void CleanUp()
#if UNITY_EDITOR
UnityEditor.Undo.undoRedoPerformed -= OnUndoRedoPerformed;
#endif
foreach (var item in m_ItemStateList)
{
Object.DestroyImmediate(item);
}
m_ItemStateList.Clear();
foreach(var item in m_ItemStateList)
{
Object.DestroyImmediate(item);
}
CleanUp();
}
void OnUndoRedoPerformed()

#endif
}
public void AddDebugItemState(DebugItemState state)
private void AddDebugItemState(DebugItemState state)
{
m_ItemStateList.Add(state);
}

return m_ItemStateList.Find(x => x.itemName == item.name && x.panelName == item.panelName);
}
public void UpdateAllDebugItems()
private void UpdateAllDebugItems()
{
foreach (var itemState in m_ItemStateList)
{

3
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuUI.cs


using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugMenuUpdater.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering
{

14
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugPanel.cs


using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using System;

public enum DebugItemFlag
{
None,
DynamicDisplay,
EditorOnly
None = 0,
DynamicDisplay = 1 << 0,
EditorOnly = 1 << 1,
RuntimeOnly = 1 << 2
}
public class DebugItem

public DebugItemHandler handler { get { return m_Handler; } }
public DebugItemFlag flags { get { return m_Flags; } }
public bool readOnly { get { return m_Setter == null; } }
public bool editorOnly { get { return (flags & DebugItemFlag.EditorOnly) != 0; } }
public bool runtimeOnly { get { return (flags & DebugItemFlag.RuntimeOnly) != 0; } }
public DebugItem(string name, string panelName, Type type, Func<object> getter, Action<object> setter, DebugItemFlag flags = DebugItemFlag.None, DebugItemHandler handler = null)
{

if(m_Setter != null)
{
m_Setter(value);
m_Handler.ClampValues(m_Getter, m_Setter);
m_Handler.ValidateValues(m_Getter, m_Setter);
}
if (record && OnItemDirty != null)

39
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/DebugPanelUI.cs


using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using System;

GameObject.Destroy(child.gameObject);
}
m_ItemsUI.Clear();
protected void AddDebugItemUI(DebugItem item, GameObject parent)
{
#if UNITY_EDITOR
// We don't want runtime only items even in the "player" debug menu if we are in the editor.
if (item.runtimeOnly)
return;
#endif
if(item.editorOnly)
return;
DebugItemUI itemUI = item.handler.BuildGUI(parent);
if(itemUI == null)
{
Debug.LogWarning(String.Format("DebugItemUI not provided for item {0} of type {1}.\n Did you implement BuildGUI for your custom Handler?", item.name, item.type));
}
else
{
m_ItemsUI.Add(itemUI);
}
}
m_ItemsUI.Clear();
if(!((item.flags & DebugItemFlag.EditorOnly) != 0))
{
DebugItemHandler handler = item.handler; // Should never be null, we have at least the default handler
m_ItemsUI.Add(handler.BuildGUI(parent));
}
AddDebugItemUI(item, parent);
}
}

{
if (m_SelectedItem != -1)
{
return m_DebugPanel.GetDebugItem(m_SelectedItem);
return m_ItemsUI[m_SelectedItem].debugItem;
}
return null;

public void OnMoveHorizontal(float value)
{
if (m_SelectedItem != -1 && !m_DebugPanel.GetDebugItem(m_SelectedItem).readOnly)
if (m_SelectedItem != -1 && !m_ItemsUI[m_SelectedItem].debugItem.readOnly)
{
if (value > 0.0f)
m_ItemsUI[m_SelectedItem].OnIncrement();

public void OnValidate()
{
if (m_SelectedItem != -1 && !m_DebugPanel.GetDebugItem(m_SelectedItem).readOnly)
if (m_SelectedItem != -1 && !m_ItemsUI[m_SelectedItem].debugItem.readOnly)
m_ItemsUI[m_SelectedItem].OnValidate();
}

1
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Debugging.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Editor/DebugMenuEditor.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
using UnityEditor;
namespace UnityEngine.Experimental.Rendering

{
DebugItemState debugItemState = m_DebugMenuState.FindDebugItemState(item);
UnityEditor.Undo.RecordObject(debugItemState, "DebugMenu State Update");
debugItemState.SetValue(item.GetValue());
EditorUtility.SetDirty(m_DebugMenuState);
if(debugItemState != null)
{
UnityEditor.Undo.RecordObject(debugItemState, "DebugMenu State Update");
debugItemState.SetValue(item.GetValue());
EditorUtility.SetDirty(m_DebugMenuState);
}
}
void OnGUI()

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateBool.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering
{

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateColor.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering
{

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateFloat.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering
{

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateInt.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering
{

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Debugging/Serialization/DebugItemStateUInt.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
namespace UnityEngine.Experimental.Rendering
{

2
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderGenerator/Editor/CSharpToHLSL.cs


guard = "_" + guard;
writer.Write("//\n");
writer.Write("// This file was automatically generated from " + it.Key + ". Please don't edit by hand.\n");
writer.Write("// This file was automatically generated. Please don't edit by hand.\n");
writer.Write("//\n\n");
writer.Write("#ifndef " + guard + "\n");
writer.Write("#define " + guard + "\n");

193
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/BSDF.hlsl


}
// Ref: Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, p. 19, 29.
float G_MaskingSmithGGX(float NdotV, float VdotH, float roughness)
float G_MaskingSmithGGX(float NdotV, float roughness)
{
// G1(V, H) = HeavisideStep(VdotH) / (1 + Λ(V)).
// Λ(V) = -0.5 + 0.5 * sqrt(1 + 1 / a²).

// Assume that (VdotH > 0), e.i. (acos(LdotV) < Pi).
float hs = VdotH > 0.0 ? 1.0 : 0.0;
return hs / (0.5 + 0.5 * sqrt(1.0 + a2 * (1.0 / z2 - 1.0)));
return 1 / (0.5 + 0.5 * sqrt(1.0 + a2 * (1.0 / z2 - 1.0)));
// Note that we pass 1.0 instead of 'VdotH' since the multiplication will already clamp.
return D_GGX(NdotH, roughness) * G_MaskingSmithGGX(NdotV, 1.0, roughness) * VdotH / NdotV;
return D_GGX(NdotH, roughness) * G_MaskingSmithGGX(NdotV, roughness) * VdotH / NdotV;
}
// Precompute part of lambdaV
float GetSmithJointGGXPartLambdaV(float NdotV, float roughness)
{
float a2 = roughness * roughness;
return sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
// Note: V = G / (4 * NdotL * NdotV)
float V_SmithJointGGX(float NdotL, float NdotV, float roughness)
float V_SmithJointGGX(float NdotL, float NdotV, float roughness, float partLambdaV)
float a2 = roughness * roughness;
// lambda_v = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
// lambda_l = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f;
// G = 1 / (1 + lambda_v + lambda_l);
// lambda_v = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5
// lambda_l = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5
// G = 1 / (1 + lambda_v + lambda_l);
float a = roughness;
float a2 = a * a;
// Reorder code to be more optimal
float lambdaV = NdotL * sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
// Reorder code to be more optimal:
float lambdaV = NdotL * partLambdaV;
float lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
// Simplify visibility term: (2.0 * NdotL * NdotV) / ((4.0 * NdotL * NdotV) * (lambda_v + lambda_l));

// Precompute part of lambdaV
float GetSmithJointGGXLambdaV(float NdotV, float roughness)
float V_SmithJointGGX(float NdotL, float NdotV, float roughness)
float a = roughness;
float a2 = a * a;
return sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
float partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
return V_SmithJointGGX(NdotL, NdotV, roughness, partLambdaV);
float V_SmithJointGGX(float NdotL, float NdotV, float roughness, float lambdaV)
// Inline D_GGX() * V_SmithJointGGX() together for better code generation.
float DV_SmithJointGGX(float NdotH, float NdotL, float NdotV, float roughness, float partLambdaV)
float a = roughness;
float a2 = a * a;
// Reorder code to be more optimal
lambdaV *= NdotL;
float a2 = roughness * roughness;
float f = (NdotH * a2 - NdotH) * NdotH + 1.0;
float2 D = float2(a2, f * f); // Fraction without the constant (1/Pi)
float lambdaV = NdotL * partLambdaV;
// Simplify visibility term: (2.0 * NdotL * NdotV) / ((4.0 * NdotL * NdotV) * (lambda_v + lambda_l));
return 0.5 / (lambdaV + lambdaL);
float2 G = float2(1, lambdaV + lambdaL); // Fraction without the constant (0.5)
return (INV_PI * 0.5) * (D.x * G.x) / (D.y * G.y);
float V_SmithJointGGXApprox(float NdotL, float NdotV, float roughness)
float DV_SmithJointGGX(float NdotH, float NdotL, float NdotV, float roughness)
float a = roughness;
// Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)
float lambdaV = NdotL * (NdotV * (1 - a) + a);
float lambdaL = NdotV * (NdotL * (1 - a) + a);
return 0.5 / (lambdaV + lambdaL);
float partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
return DV_SmithJointGGX(NdotH, NdotL, NdotV, roughness, partLambdaV);
// Precompute part of LambdaV
float GetSmithJointGGXApproxLambdaV(float NdotV, float roughness)
// Precompute a part of LambdaV.
// Note on this linear approximation.
// Exact for roughness values of 0 and 1. Also, exact when the cosine is 0 or 1.
// Otherwise, the worst case relative error is around 10%.
// https://www.desmos.com/calculator/wtp8lnjutx
float GetSmithJointGGXPartLambdaVApprox(float NdotV, float roughness)
float V_SmithJointGGXApprox(float NdotL, float NdotV, float roughness, float lambdaV)
float V_SmithJointGGXApprox(float NdotL, float NdotV, float roughness, float partLambdaV)
// Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)
lambdaV *= NdotL;
float lambdaV = NdotL * partLambdaV;
float V_SmithJointGGXApprox(float NdotL, float NdotV, float roughness)
{
float partLambdaV = GetSmithJointGGXPartLambdaVApprox(NdotV, roughness);
return V_SmithJointGGXApprox(NdotL, NdotV, roughness, partLambdaV);
}
float f = TdotH * TdotH / (roughnessT * roughnessT) + BdotH * BdotH / (roughnessB * roughnessB) + NdotH * NdotH;
float aT2 = roughnessT * roughnessT;
float aB2 = roughnessB * roughnessB;
float f = TdotH * TdotH / aT2 + BdotH * BdotH / aB2 + NdotH * NdotH;
return 1.0 / (roughnessT * roughnessB * f * f);
}

}
float GetSmithJointGGXAnisoPartLambdaV(float TdotV, float BdotV, float NdotV, float roughnessT, float roughnessB)
{
float aT2 = roughnessT * roughnessT;
float aB2 = roughnessB * roughnessB;
return sqrt(aT2 * TdotV * TdotV + aB2 * BdotV * BdotV + NdotV * NdotV);
}
// Note: V = G / (4 * NdotL * NdotV)
float V_SmithJointGGXAniso(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB)
float V_SmithJointGGXAniso(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB, float partLambdaV)
float aT = roughnessT;
float aT2 = aT * aT;
float aB = roughnessB;
float aB2 = aB * aB;
float aT2 = roughnessT * roughnessT;
float aB2 = roughnessB * roughnessB;
float lambdaV = NdotL * sqrt(aT2 * TdotV * TdotV + aB2 * BdotV * BdotV + NdotV * NdotV);
float lambdaV = NdotL * partLambdaV;
float GetSmithJointGGXAnisoLambdaV(float TdotV, float BdotV, float NdotV, float roughnessT, float roughnessB)
float V_SmithJointGGXAniso(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB)
float aT = roughnessT;
float aT2 = aT * aT;
float aB = roughnessB;
float aB2 = aB * aB;
return sqrt(aT2 * TdotV * TdotV + aB2 * BdotV * BdotV + NdotV * NdotV);
float partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB);
return V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB, partLambdaV);
float V_SmithJointGGXAnisoLambdaV(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB, float lambdaV)
// Inline D_GGXAniso() * V_SmithJointGGXAniso() together for better code generation.
float DV_SmithJointGGXAniso(float TdotH, float BdotH, float NdotH,
float TdotV, float BdotV, float NdotV,
float TdotL, float BdotL, float NdotL,
float roughnessT, float roughnessB, float partLambdaV)
float aT = roughnessT;
float aT2 = aT * aT;
float aB = roughnessB;
float aB2 = aB * aB;
float aT2 = roughnessT * roughnessT;
float aB2 = roughnessB * roughnessB;
lambdaV *= NdotL;
float f = TdotH * TdotH / aT2 + BdotH * BdotH / aB2 + NdotH * NdotH;
float2 D = float2(1, roughnessT * roughnessB * f * f); // Fraction without the constant (1/Pi)
float lambdaV = NdotL * partLambdaV;
return 0.5 / (lambdaV + lambdaL);
float2 G = float2(1, lambdaV + lambdaL); // Fraction without the constant (0.5)
return (INV_PI * 0.5) * (D.x * G.x) / (D.y * G.y);
}
float DV_SmithJointGGXAniso(float TdotH, float BdotH, float NdotH,
float TdotV, float BdotV, float NdotV,
float TdotL, float BdotL, float NdotL,
float roughnessT, float roughnessB)
{
float partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB);
return DV_SmithJointGGXAniso(TdotH, BdotH, NdotH,
TdotV, BdotV, NdotV,
TdotL, BdotL, NdotL,
roughnessT, roughnessB, partLambdaV);
}
//-----------------------------------------------------------------------------

return INV_PI;
}
float DisneyDiffuseNoPI(float NdotV, float NdotL, float LdotH, float perceptualRoughness)
float DisneyDiffuseNoPI(float NdotV, float NdotL, float LdotV, float perceptualRoughness)
float fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
// (2 * LdotH * LdotH) = 1 + LdotV
// float fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
float fd90 = 0.5 + (perceptualRoughness + perceptualRoughness * LdotV);
float viewScatter = F_Schlick(1.0, fd90, NdotV);
float viewScatter = F_Schlick(1.0, fd90, NdotV);
return lightScatter * viewScatter;
// Normalize the BRDF for polar view angles of up to (Pi/4).
// We use the worst case of (roughness = albedo = 1), and, for each view angle,
// integrate (brdf * cos(theta_light)) over all light directions.
// The resulting value is for (theta_view = 0), which is actually a little bit larger
// than the value of the integral for (theta_view = Pi/4).
// Hopefully, the compiler folds the constant together with (1/Pi).
return rcp(1.03571) * (lightScatter * viewScatter);
float DisneyDiffuse(float NdotV, float NdotL, float LdotH, float perceptualRoughness)
float DisneyDiffuse(float NdotV, float NdotL, float LdotV, float perceptualRoughness)
return INV_PI * DisneyDiffuseNoPI(NdotV, NdotL, LdotH, perceptualRoughness);
return INV_PI * DisneyDiffuseNoPI(NdotV, NdotL, LdotV, perceptualRoughness);
float3 DiffuseGGXNoPI(float3 albedo, float NdotV, float NdotL, float NdotH, float LdotV, float perceptualRoughness)
float3 DiffuseGGXNoPI(float3 albedo, float NdotV, float NdotL, float NdotH, float LdotV, float roughness)
float facing = 0.5 + 0.5 * LdotV;
float rough = facing * (0.9 - 0.4 * facing) * ((0.5 + NdotH) / NdotH);
float facing = 0.5 + 0.5 * LdotV; // (LdotH)^2
float rough = facing * (0.9 - 0.4 * facing) * (0.5 / NdotH + 1);
float smooth = transmitL * transmitV * 1.05; // Normalize F_t over the hemisphere
float single = lerp(smooth, rough, perceptualRoughness); // Rescaled by PI
// This constant is picked s.t. setting perceptualRoughness, albedo and all angles to 1
// allows us to match the Lambertian and the Disney Diffuse models. Original value: 0.1159.
float multiple = perceptualRoughness * (0.079577 * PI); // Rescaled by PI
float smooth = transmitL * transmitV * 1.05; // Normalize F_t over the hemisphere
float single = lerp(smooth, rough, roughness); // Rescaled by PI
float multiple = roughness * (0.1159 * PI); // Rescaled by PI
float3 DiffuseGGX(float3 albedo, float NdotV, float NdotL, float NdotH, float LdotV, float perceptualRoughness)
float3 DiffuseGGX(float3 albedo, float NdotV, float NdotL, float NdotH, float LdotV, float roughness)
return INV_PI * DiffuseGGXNoPI(albedo, NdotV, NdotL, NdotH, LdotV, perceptualRoughness);
return INV_PI * DiffuseGGXNoPI(albedo, NdotV, NdotL, NdotH, LdotV, roughness);
}
#endif // UNITY_BSDF_INCLUDED

26
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Common.hlsl


// The reason is that for compute shader we need to guarantee that the layout of CBs is consistent across kernels. Something that we can't control with the global namespace (uniforms get optimized out if not used, modifying the global CBuffer layout per kernel)
// Structure definition that are share between C# and hlsl.
// These structures need to be align on float4 to respectect various packing rules from sahder language.
// These structures need to be align on float4 to respect various packing rules from sahder language.
// This mean that these structure need to be padded.
// Do not use "in", only "out" or "inout" as califier, not "inline" keyword either, useless.

return x * x;
}
// Acos in 14 cycles.
// Ref: https://seblagarde.wordpress.com/2014/12/01/inverse-trigonometric-functions-gpu-optimization-for-amd-gcn-architecture/
float FastACos(float inX)
// Input [0, 1] and output [0, PI/2]
// 9 VALU
float FastACosPos(float inX)
return res;
}
// Ref: https://seblagarde.wordpress.com/2014/12/01/inverse-trigonometric-functions-gpu-optimization-for-amd-gcn-architecture/
// Input [-1, 1] and output [0, PI]
// 12 VALU
float FastACos(float inX)
{
float res = FastACosPos(inX);
return (inX >= 0) ? res : PI - res; // Undo range reduction
}

float3 FastSign(float x)
{
return saturate(x * FLT_MAX) * 2.0 - 1.0;
}
// Orthonormalize the basis vectors using the Gram-Schmidt process.
// We assume that the length of the surface normal is sufficiently close to 1.
// return orthonormalize tangent
float3 Orthonormalize(float3 tangent, float3 normal)
{
return normalize(tangent - dot(tangent, normal) * normal);
}
// ----------------------------------------------------------------------------

46
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/CommonLighting.hlsl


}
// Ref: Moving Frostbite to PBR - Gotanda siggraph 2011
float GetSpecularOcclusion(float NdotV, float ambientOcclusion, float roughness)
// Return specular occlusion based on ambient occlusion (usually get from SSAO) and view/roughness info
float GetSpecularOcclusionFromAmbientOcclusion(float NdotV, float ambientOcclusion, float roughness)
}
// ref: Practical Realtime Strategies for Accurate Indirect Occlusion
// Update ambient occlusion to colored ambient occlusion based on statitics of how light is bouncing in an object and with the albedo of the object
float3 GTAOMultiBounce(float visibility, float3 albedo)
{
float3 a = 2.0404 * albedo - 0.3324;
float3 b = -4.7951 * albedo + 0.6417;
float3 c = 2.7552 * albedo + 0.6903;
float x = visibility;
return max(x, ((x * a + b) * x + c) * x);
}
// Based on Oat and Sander's 2008 technique
// Area/solidAngle of intersection of two cone
float SphericalCapIntersectionSolidArea(float cosC1, float cosC2, float cosB)
{
float r1 = FastACos(cosC1);
float r2 = FastACos(cosC2);
float rd = FastACos(cosB);
float area = 0.0;
if (rd <= max(r1, r2) - min(r1, r2))
{
// One cap is completely inside the other
area = TWO_PI - TWO_PI * max(cosC1, cosC2);
}
else if (rd >= r1 + r2)
{
// No intersection exists
area = 0.0;
}
else
{
float diff = abs(r1 - r2);
float den = r1 + r2 - diff;
float x = 1.0 - saturate((rd - diff) / den);
area = smoothstep(0.0, 1.0, x);
area *= TWO_PI - TWO_PI * max(cosC1, cosC2);
}
return area;
}
//-----------------------------------------------------------------------------

29
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/CommonMaterial.hlsl


// Convert anisotropic ratio (0->no isotropic; 1->full anisotropy in tangent direction) to roughness
void ConvertAnisotropyToRoughness(float roughness, float anisotropy, out float roughnessT, out float roughnessB)
{
// (0 <= anisotropy <= 1), therefore (0 <= anisoAspect <= 1)
// The 0.9 factor limits the aspect ratio to 10:1.
float anisoAspect = sqrt(1.0 - 0.9 * anisotropy);
roughnessT = roughness / anisoAspect; // Distort along tangent (rougher)
roughnessB = roughness * anisoAspect; // Straighten along bitangent (smoother)
}
// Ref: Donald Revie - Implementing Fur Using Deferred Shading (GPU Pro 2)
// The grain direction (e.g. hair or brush direction) is assumed to be orthogonal to the normal.
// The returned normal is NOT normalized.
float3 ComputeGrainNormal(float3 grainDir, float3 V)
{
float3 B = cross(-V, grainDir);
return cross(B, grainDir);
}
// Fake anisotropic by distorting the normal.
// The grain direction (e.g. hair or brush direction) is assumed to be orthogonal to N.
// Anisotropic ratio (0->no isotropic; 1->full anisotropy in tangent direction)
float3 GetAnisotropicModifiedNormal(float3 grainDir, float3 N, float3 V, float anisotropy)
{
float3 grainNormal = ComputeGrainNormal(grainDir, V);
// TODO: test whether normalizing 'grainNormal' is worth it.
return normalize(lerp(N, grainNormal, anisotropy));
// Use the parametrization of Sony Imageworks.
// Ref: Revisiting Physically Based Shading at Imageworks, p. 15.
roughnessT = roughness * (1 + anisotropy);
roughnessB = roughness * (1 - anisotropy);
}
//-----------------------------------------------------------------------------

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/EntityLighting.hlsl


}
// This sample a 3D volume storing SH
// Volume is store as 3D texture with 4 R, G, B, X set of 4 coefficient store atlas in same 3D texture. X unused.
// TODO: the packing here is innefficient as we will fetch values far away from each other and they may not fit into the cache
// Suggest we pack only RGB not X and continuous
float3 SampleProbeVolumeSH4(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture, float texelSizeX)
// Volume is store as 3D texture with 4 R, G, B, X set of 4 coefficient store atlas in same 3D texture. X is use for occlusion.
// TODO: the packing here is inefficient as we will fetch values far away from each other and they may not fit into the cache - Suggest we pack only RGB continuously
// TODO: The calcul of texcoord could be perform with a single matrix multicplication calcualted on C++ side that will fold probeVolumeMin and probeVolumeSizeInv into it and handle the identity case, no reasons to do it in C++ (ask Ionut about it)
// It should also handle the camera relative path (if the render pipeline use it)
float3 SampleProbeVolumeSH4(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture,
float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv)
float3 texCoord = mul(WorldToTexture, float4(positionWS, 1.0)).xyz;
float3 position = (transformToLocal == 1.0f) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS;
float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv.xyz;
// Each component is store in the same texture 3D. Each use one quater on the x axis
// Here we get R component then increase by step size (0.25) to get other component. This assume 4 component
// but last one is not used.

8
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Fibonacci.hlsl


return float2(i / fibN1 + (0.5f / fibN1), frac(i * (fibN2 / fibN1)));
}
#define GOLDEN_RATIO 1.6180339887498948482
// Replaces the Fibonacci sequence in Fibonacci2dSeq() with the Golden ratio.
float2 Golden2dSeq(int i, float n)
{
return float2(i / n + (0.5f / n), frac(i * rcp(GOLDEN_RATIO)));
}
static const int k_FibonacciSeq[] = {
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181
};

174
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/ImageBasedLighting.hlsl


#include "BSDF.hlsl"
#include "Sampling.hlsl"
// TODO: We need to change this hard limit!
#ifndef UNITY_SPECCUBE_LOD_STEPS
#define UNITY_SPECCUBE_LOD_STEPS 6
#endif

// approximating the cone of the specular lobe, and then computing the MIP map level
// which (approximately) covers the footprint of the lobe with a single texel.
// Improves the perceptual roughness distribution.
float PerceptualRoughnessToMipmapLevel(float perceptualRoughness)
float PerceptualRoughnessToMipmapLevel(float perceptualRoughness, uint mipMapCount)
return perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;
return perceptualRoughness * mipMapCount;
}
float PerceptualRoughnessToMipmapLevel(float perceptualRoughness)
{
return PerceptualRoughnessToMipmapLevel(perceptualRoughness, UNITY_SPECCUBE_LOD_STEPS);
}
// The *accurate* version of the non-linear remapping. It works by

return saturate(1.7 / 1.4 - sqrt(2.89 / 1.96 - (2.8 / 1.96) * perceptualRoughness));
}
//-----------------------------------------------------------------------------
// Anisotropic image based lighting
//-----------------------------------------------------------------------------
// Ref: Donald Revie - Implementing Fur Using Deferred Shading (GPU Pro 2)
// The grain direction (e.g. hair or brush direction) is assumed to be orthogonal to the normal.
// The returned normal is NOT normalized.
float3 ComputeGrainNormal(float3 grainDir, float3 V)
{
float3 B = cross(grainDir, V);
return cross(B, grainDir);
}
// Fake anisotropy by distorting the normal (non-negative anisotropy values only).
// The grain direction (e.g. hair or brush direction) is assumed to be orthogonal to N.
// Anisotropic ratio (0->no isotropic; 1->full anisotropy in tangent direction)
float3 GetAnisotropicModifiedNormal(float3 grainDir, float3 N, float3 V, float anisotropy)
{
float3 grainNormal = ComputeGrainNormal(grainDir, V);
return normalize(lerp(N, grainNormal, anisotropy));
}
// Ref: "Moving Frostbite to PBR", p. 69.
float3 GetSpecularDominantDir(float3 N, float3 R, float roughness, float NdotV)
{

return lerp(N, R, lerpFactor);
}
//-----------------------------------------------------------------------------
// Anisotropic image based lighting
//-----------------------------------------------------------------------------
// To simulate the streching of highlight at grazing angle for IBL we shrink the roughness
// which allow to fake an anisotropic specular lobe.
// Ref: http://www.frostbite.com/2015/08/stochastic-screen-space-reflections/ - slide 84

// Compute { localL = reflect(-localV, localH) }
float3 localL = -localV + 2.0 * VdotH * localH;
NdotL = localL.z;
L = mul(localL, localToWorld);
}
// Ref: "A Simpler and Exact Sampling Routine for the GGX Distribution of Visible Normals".
void SampleVisibleAnisoGGXDir(float2 u, float3 V, float3x3 localToWorld,
float roughnessT, float roughnessB,
out float3 L,
out float NdotL,
out float NdotH,
out float VdotH,
bool VeqN = false)
{
float3 localV = mul(V, transpose(localToWorld));
// Construct an orthonormal basis around the stretched view direction.
float3x3 viewToLocal;
if (VeqN)
{
viewToLocal = k_identity3x3;
}
else
{
viewToLocal[2] = normalize(float3(roughnessT * localV.x, roughnessB * localV.y, localV.z));
viewToLocal[0] = (viewToLocal[2].z < 0.9999) ? normalize(cross(viewToLocal[2], float3(0, 0, 1))) : float3(1, 0, 0);
viewToLocal[1] = cross(viewToLocal[0], viewToLocal[2]);
}
// Compute a sample point with polar coordinates (r, phi).
float r = sqrt(u.x);
float b = viewToLocal[2].z + 1;
float a = rcp(b);
float c = (u.y < a) ? u.y * b : 1 + (u.y * b - 1) / viewToLocal[2].z;
float phi = PI * c;
float p1 = r * cos(phi);
float p2 = r * sin(phi) * ((u.y < a) ? 1 : viewToLocal[2].z);
// Unstretch.
float3 viewH = normalize(float3(roughnessT * p1, roughnessB * p2, sqrt(1 - p1 * p1 - p2 * p2)));
VdotH = viewH.z;
float3 localH = mul(viewH, viewToLocal);
NdotH = localH.z;
// Compute { localL = reflect(-localV, localH) }
float3 localL = -localV + 2 * VdotH * localH;
NdotL = localL.z;
L = mul(localL, localToWorld);

float3 N,
float roughness,
float index, // Current MIP level minus one
float lastMipLevel,
float invOmegaP,
uint sampleCount, // Must be a Fibonacci number
bool prefilter,

// Bias samples towards the mirror direction to reduce variance.
// This will have a side effect of making the reflection sharper.
// Ref: Stochastic Screen-Space Reflections, p. 67.
const float bias = 0.5 * roughness;
#ifndef USE_KARIS_APPROXIMATION
float NdotV = 1; // N == V
float partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness);
#endif
float3 lightInt = float3(0.0, 0.0, 0.0);
float cbsdfInt = 0.0;

float3 L;
float NdotL, NdotH, VdotH;
bool isValid;
float NdotL, NdotH, LdotH;
L = mul(localL, localToWorld);
NdotL = localL.z;
isValid = true;
L = mul(localL, localToWorld);
NdotL = localL.z;
LdotH = sqrt(0.5 + 0.5 * NdotL);
u.x = lerp(u.x, 0.0, bias);
SampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH, true);
// Note: if (N == V), all of the microsurface normals are visible.
SampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, LdotH, true);
isValid = NdotL > 0.0;
if (NdotL <= 0) continue; // Note that some samples will have 0 contribution
}
float mipLevel;

// 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 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;
//
// - OmegaS : Solid angle associated with the sample
// - OmegaP : Solid angle associated with the texel of the cubemap
// - OmegaS: Solid angle associated with the sample
// - OmegaP: Solid angle associated with the texel of the cubemap
float omegaS;

}
else
{
float pdf = D_GGX(NdotH, roughness) * 0.25;
// TODO: check the accuracy of the sample's solid angle fit for GGX.
omegaS = rcp(sampleCount) / pdf;
// float PDF = D * NdotH * Jacobian, where Jacobian = 1 / (4 * LdotH).
// Since (N == V), NdotH == LdotH.
float pdf = 0.25 * D_GGX(NdotH, roughness);
// TODO: improve the accuracy of the sample's solid angle fit for GGX.
omegaS = rcp(sampleCount) * rcp(pdf);
// invOmegaP is precomputed on CPU and provide as a parameter of the function
// 'invOmegaP' is precomputed on CPU and provided as a parameter to the function.
mipLevel = 0.5 * log2(omegaS * invOmegaP);
const float mipBias = roughness;
mipLevel = 0.5 * log2(omegaS * invOmegaP) + mipBias;
if (isValid)
{
// Bias the MIP map level to compensate for the importance sampling bias.
// This will blur the reflection.
// TODO: find a more accurate MIP bias function.
mipLevel = lerp(mipLevel, lastMipLevel, bias);
// TODO: use a Gaussian-like filter to generate the MIP pyramid.
float3 val = SAMPLE_TEXTURECUBE_LOD(tex, sampl, L, mipLevel).rgb;
// TODO: use a Gaussian-like filter to generate the MIP pyramid.
float3 val = SAMPLE_TEXTURECUBE_LOD(tex, sampl, L, mipLevel).rgb;
// The goal of this function is to use Monte-Carlo integration to find
// X = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}.
// Note: Integral{CBSDF(L, N, V) dL} is given by the FDG texture.
// CBSDF = F * D * G * NdotL / (4 * NdotL * NdotV) = F * D * G / (4 * NdotV).
// PDF = D * NdotH / (4 * LdotH).
// Weight = CBSDF / PDF = F * G * LdotH / (NdotV * NdotH).
// Since we perform filtering with the assumption that (V == N),
// (LdotH == NdotH) && (NdotV == 1) && (Weight == F * G).
// Therefore, after the Monte Carlo expansion of the integrals,
// X = Sum(Radiance(L) * Weight) / Sum(Weight) = Sum(Radiance(L) * F * G) / Sum(F * G).
// Our goal is to use Monte-Carlo integration with importance sampling to evaluate
// X(V) = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}.
// CBSDF = F * D * G * NdotL / (4 * NdotL * NdotV) = F * D * G / (4 * NdotV).
// PDF = D * NdotH / (4 * LdotH).
// Weight = CBSDF / PDF = F * G * LdotH / (NdotV * NdotH).
// Since we perform filtering with the assumption that (V == N),
// (LdotH == NdotH) && (NdotV == 1) && (Weight == F * G).
// We use the approximation of Brian Karis from "Real Shading in Unreal Engine 4":
// Weight ≈ NdotL, which produces nearly identical results in practice.
#ifndef USE_KARIS_APPROXIMATION
// The choice of the Fresnel factor does not appear to affect the result.
float F = 1; // F_Schlick(F0, LdotH);
float V = V_SmithJointGGX(NdotL, NdotV, roughness, partLambdaV);
float G = V * NdotL * NdotV; // 4 cancels out
lightInt += NdotL * val;
cbsdfInt += NdotL;
}
lightInt += F * G * val;
cbsdfInt += F * G;
#else
// Use the approximation from "Real Shading in Unreal Engine 4": Weight ≈ NdotL.
lightInt += NdotL * val;
cbsdfInt += NdotL;
#endif
}
return float4(lightInt / cbsdfInt, 1.0);

9
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/PerPixelDisplacement.hlsl


// it return the offset to apply to the UVSet provide in PerPixelHeightDisplacementParam
// viewDirTS is view vector in texture space matching the UVSet
// ref: https://www.gamedev.net/resources/_/technical/graphics-programming-and-theory/a-closer-look-at-parallax-occlusion-mapping-r3262
float2 ParallaxOcclusionMapping(float lod, float lodThreshold, int numSteps, float3 viewDirTS, float maxHeight, PerPixelHeightDisplacementParam ppdParam, out float outHeight)
float2 ParallaxOcclusionMapping(float lod, float lodThreshold, int numSteps, float3 viewDirTS, PerPixelHeightDisplacementParam ppdParam, out float outHeight)
// TODO: explain this factor! Necessary to achieve parity between tessellation and POM w.r.t. height.
maxHeight *= 0.1;
// Convention: 1.0 is top, 0.0 is bottom - POM is always inward, no extrusion
float stepSize = 1.0 / (float)numSteps;

// float2 parallaxDir = normalize(Out.viewDirTS.xy);
// float2 parallaxMaxOffsetTS = parallaxDir * parallaxLimit;
// Above code simplify to
float2 parallaxMaxOffsetTS = (viewDirTS.xy / -viewDirTS.z) * maxHeight;
float2 parallaxMaxOffsetTS = (viewDirTS.xy / -viewDirTS.z);
float2 texOffsetPerStep = stepSize * parallaxMaxOffsetTS;
// Do a first step before the loop to init all value correctly

// Secant method to affine the search
// Ref: Faster Relief Mapping Using the Secant Method - Eric Risser
for (int i = 0; i < 5; ++i)
for (int i = 0; i < 3; ++i)
{
// intersectionHeight is the height [0..1] for the intersection between view ray and heightfield line
float intersectionHeight = (pt0 * delta1 - pt1 * delta0) / (delta1 - delta0);

9
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Shadow/Shadow.hlsl


#ifndef SHADOW_HLSL
#ifndef SHADOW_HLSL
#define SHADOW_HLSL
//
// Shadow master include header.

#define SHADOW_SUPPORTS_DYNAMIC_INDEXING 0 // only on >= sm 5.1
#define SHADOW_OPTIMIZE_REGISTER_USAGE 0 // redefine this as 1 in your ShadowContext.hlsl to optimize for register usage over instruction count
#include "../../../Core/Shadow/ShadowBase.cs.hlsl" // ShadowData definition, auto generated (don't modify)
#include "ShadowTexFetch.hlsl" // Resource sampling definitions (don't modify)

// Shadow context definition and initialization, i.e. resource binding (project header, must be kept in sync with C# runtime)
#define SHADOW_CONTEXT_INCLUDE
#include "../../ShadowIncludes.inl"
#include "../../ShadowIncludes.hlsl"
//#include "ShadowContext.hlsl"
// helper function to extract shadowmap data from the ShadowData struct
void UnpackShadowmapId( uint shadowmapId, out uint texIdx, out uint sampIdx, out float slice )

// include project specific shadow dispatcher. If this file is not empty, it MUST define which default shadows it's overriding
#define SHADOW_DISPATCH_INCLUDE
#include "../../ShadowIncludes.inl"
#include "../../ShadowIncludes.hlsl"
//#include "ShadowDispatch.hlsl"
// if shadow dispatch is empty we'll fall back to default shadow sampling implementations
#ifndef SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL

310
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl


// calc TCs
float2 posTC = posNDC * 0.5 + 0.5;
closestSampleNDC = (floor(posTC * sd.textureSize.zw) + 0.5) * sd.texelSizeRcp.zw * 2.0 - 1.0.xx;
return (posTC * sd.scaleOffset.xy + sd.scaleOffset.zw) * sd.textureSize.xy;
return uint2( (posTC * sd.scaleOffset.xy + sd.scaleOffset.zw) * sd.textureSize.xy );
}
int EvalShadow_GetCubeFaceID( float3 dir )

//
#define kMaxShadowCascades 4
#define SHADOW_REPEAT_CASCADE( _x ) _x, _x, _x, _x
int EvalShadow_GetSplitSphereIndexForDirshadows( float3 positionWS, float4 dirShadowSplitSpheres[4], out float relDistance )
{

payloadOffset++;
float4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
float border = borders[shadowSplitIndex];
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
// normal based bias

// Be careful of this code, we need it here before the if statement otherwise the compiler screws up optimizing dirShadowSplitSpheres VGPRs away
float3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz;
float3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[min( shadowSplitIndex+1, kMaxShadowCascades-1 )].xyz );
float3 wposDir = normalize( -splitSphere + positionWS );
float cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
// sample the texture
uint texIdx, sampIdx;
float slice;

UnpackShadowType( sd.shadowType, shadowType, shadowAlgorithm );
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
float border = borders[shadowSplitIndex];
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border );
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
float shadow1 = 1.0;
float shadow1 = 1.0;
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex - 1];
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex].xyz );
float3 wposDir = normalize( -splitSphere.xyz + positionWS );
float cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
[branch]
if( alpha > 0.0 )
{
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];

UnpackShadowmapId( sd.id, slice );
[branch]
if( all( abs( posNDC.xy ) <= (1.0 - sd.texelSizeRcp.zw * 0.5) ) )
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, texIdx, sampIdx );
}

}
#define EvalShadow_CascadedDepth_( _samplerType ) \
float EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
/* load the right shadow data for the current face */ \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
if( shadowSplitIndex < 0 ) \
return 1.0; \
\
float4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
/* normal based bias */ \
float3 orig_pos = positionWS; \
uint orig_payloadOffset = payloadOffset; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
\
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
\
float border = borders[shadowSplitIndex]; \
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
shadowSplitIndex++; \
float shadow1 = 1.0; \
if( shadowSplitIndex < kMaxShadowCascades ) \
{ \
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex - 1]; \
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex].xyz ); \
float3 wposDir = normalize( -splitSphere.xyz + positionWS ); \
float cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
shadow1 = shadow; \
\
[branch] \
if( alpha > 0.0 ) \
{ \
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false ); \
/* sample the texture */ \
UnpackShadowmapId( sd.id, slice ); \
\
if( all( abs( posNDC.xy ) <= (1.0 - sd.texelSizeRcp.zw * 0.5) ) ) \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
} \
} \
shadow = lerp( shadow, shadow1, alpha ); \
return shadow; \
#define EvalShadow_CascadedDepth_( _samplerType ) \
float EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithms[kMaxShadowCascades], Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
/* load the right shadow data for the current face */ \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
if( shadowSplitIndex < 0 ) \
return 1.0; \
\
float4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float border = borders[shadowSplitIndex]; \
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
/* normal based bias */ \
float3 orig_pos = positionWS; \
uint orig_payloadOffset = payloadOffset; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* Be careful of this code, we need it here before the if statement otherwise the compiler screws up optimizing dirShadowSplitSpheres VGPRs away */ \
float3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz; \
float3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[min( shadowSplitIndex+1, kMaxShadowCascades-1 )].xyz ); \
float3 wposDir = normalize( -splitSphere + positionWS ); \
float cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
\
/* get shadowmap texcoords */ \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
\
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
\
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
float shadow1 = 1.0; \
\
shadowSplitIndex++; \
if( shadowSplitIndex < kMaxShadowCascades ) \
{ \
shadow1 = shadow; \
\
if( alpha > 0.0 ) \
{ \
sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, false ); \
/* sample the texture */ \
UnpackShadowmapId( sd.id, slice ); \
\
[branch] \
if( all( abs( posNDC.xy ) <= (1.0 - sd.texelSizeRcp.zw * 0.5) ) ) \
shadow1 = SampleShadow_SelectAlgorithm( shadowContext, sd, orig_payloadOffset, posTC, sd.bias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
} \
} \
shadow = lerp( shadow, shadow1, alpha ); \
return shadow; \
} \
\
float EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
uint shadowAlgorithms[kMaxShadowCascades] = { SHADOW_REPEAT_CASCADE( shadowAlgorithm ) }; \
return EvalShadow_CascadedDepth_Blend( shadowContext, shadowAlgorithms, tex, samp, positionWS, normalWS, index, L ); \
EvalShadow_CascadedDepth_( SamplerComparisonState )
EvalShadow_CascadedDepth_( SamplerState )
#undef EvalShadow_CascadedDepth_

float EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, float3 positionWS, float3 normalWS, int index, float3 L )
{
// load the right shadow data for the current face
float4 dirShadowSplitSpheres[4];
float4 dirShadowSplitSpheres[kMaxShadowCascades];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
float relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );

float3 posNDC;
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true );
if( shadowSplitIndex < (kMaxShadowCascades-1) )
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 );
float3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz;
float3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[min( 3, shadowSplitIndex + 1 )].xyz );
float3 wposDir = normalize( -splitSphere + positionWS );
float cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
if( shadowSplitIndex < nextSplit && step( EvalShadow_hash12( posTC.xy ), alpha ) )
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex];
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex+1].xyz );
float3 wposDir = normalize( -splitSphere.xyz + positionWS );
float cascDot = dot( cascadeDir, wposDir );
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) );
if( step( EvalShadow_hash12( posTC.xy ), alpha ) )
{
shadowSplitIndex++;
sd = shadowContext.shadowDatas[index + 2 + shadowSplitIndex];
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex+1] * sd.texelSizeRcp.zw, sd.normalBias );
posTC = EvalShadow_GetTexcoords( sd, positionWS );
}
sd = shadowContext.shadowDatas[index + 1 + nextSplit];
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[nextSplit] * sd.texelSizeRcp.zw, sd.normalBias );
posTC = EvalShadow_GetTexcoords( sd, positionWS );
}
// sample the texture
uint texIdx, sampIdx;

return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha );
}
#define EvalShadow_CascadedDepth_( _samplerType ) \
float EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
/* load the right shadow data for the current face */ \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
if( shadowSplitIndex < 0 ) \
return 1.0; \
\
float4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float border = borders[shadowSplitIndex]; \
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
/* normal based bias */ \
float3 orig_pos = positionWS; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
\
if( shadowSplitIndex < (kMaxShadowCascades-1) ) \
{ \
float4 splitSphere = dirShadowSplitSpheres[shadowSplitIndex]; \
float3 cascadeDir = normalize( -splitSphere.xyz + dirShadowSplitSpheres[shadowSplitIndex+1].xyz ); \
float3 wposDir = normalize( -splitSphere.xyz + positionWS ); \
float cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
\
if( step( EvalShadow_hash12( posTC.xy ), alpha ) ) \
{ \
sd = shadowContext.shadowDatas[index + 2 + shadowSplitIndex]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex+1] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
} \
} \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithm, tex, samp ); \
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha ); \
#define EvalShadow_CascadedDepth_( _samplerType ) \
float EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithms[kMaxShadowCascades], Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
/* load the right shadow data for the current face */ \
float4 dirShadowSplitSpheres[kMaxShadowCascades]; \
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres ); \
float relDistance; \
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance ); \
if( shadowSplitIndex < 0 ) \
return 1.0; \
\
float4 scales = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float4 borders = asfloat( shadowContext.payloads[payloadOffset] ); \
payloadOffset++; \
float border = borders[shadowSplitIndex]; \
float alpha = border <= 0.0 ? 0.0 : saturate( (relDistance - (1.0 - border)) / border ); \
\
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex]; \
/* normal based bias */ \
float3 orig_pos = positionWS; \
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[shadowSplitIndex] * sd.texelSizeRcp.zw, sd.normalBias ); \
/* get shadowmap texcoords */ \
float3 posNDC; \
float3 posTC = EvalShadow_GetTexcoords( sd, positionWS, posNDC, true ); \
\
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 ); \
float3 splitSphere = dirShadowSplitSpheres[shadowSplitIndex].xyz; \
float3 cascadeDir = normalize( -splitSphere + dirShadowSplitSpheres[nextSplit].xyz ); \
float3 wposDir = normalize( -splitSphere + positionWS ); \
float cascDot = dot( cascadeDir, wposDir ); \
alpha = cascDot > 0.0 ? alpha : lerp( alpha, 0.0, saturate( -cascDot * 4.0 ) ); \
\
if( shadowSplitIndex != nextSplit && step( EvalShadow_hash12( posTC.xy ), alpha ) ) \
{ \
sd = shadowContext.shadowDatas[index + 1 + nextSplit]; \
positionWS = orig_pos + EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), scales[nextSplit] * sd.texelSizeRcp.zw, sd.normalBias ); \
posTC = EvalShadow_GetTexcoords( sd, positionWS ); \
} \
/* sample the texture */ \
float slice; \
UnpackShadowmapId( sd.id, slice ); \
float shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sd.bias, slice, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha ); \
} \
\
float EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, float3 positionWS, float3 normalWS, int index, float3 L ) \
{ \
uint shadowAlgorithms[kMaxShadowCascades] = { SHADOW_REPEAT_CASCADE( shadowAlgorithm ) }; \
return EvalShadow_CascadedDepth_Dither( shadowContext, shadowAlgorithms, tex, samp, positionWS, normalWS, index, L ); \
EvalShadow_CascadedDepth_( SamplerComparisonState )
EvalShadow_CascadedDepth_( SamplerState )
#undef EvalShadow_CascadedDepth_

float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}
float3 EvalShadow_GetClosestSample_Cascade( ShadowContext shadowContext, Texture2DArray tex, float3 positionWS, float3 normalWS, int index, float4 L )
{
// load the right shadow data for the current face
float4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
float relDistance;
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres, relDistance );
if( shadowSplitIndex < 0 )
return 1.0;
float4 scales = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
float4 borders = asfloat( shadowContext.payloads[payloadOffset] );
payloadOffset++;
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
float4 closestNDC = { 0,0,0,1 };
uint2 texelIdx = EvalShadow_GetTexcoords( sd, positionWS, closestNDC.xy );
// load the texel
uint texIdx, sampIdx;
float slice;
UnpackShadowmapId( sd.id, texIdx, sampIdx, slice );
closestNDC.z = LOAD_TEXTURE2D_ARRAY_LOD( tex, texelIdx, slice, 0 ).x;
// reconstruct depth position
float4 closestWS = mul( closestNDC, sd.shadowToWorld );
return closestWS.xyz / closestWS.w;
}

46
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Shadow/ShadowSampling.hlsl


float2 fetchesUV[9];
SampleShadow_ComputeSamples_Tent_5x5(shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV);
for (int i = 0; i < 9; i++)
for( int i = 0; i < 9; i++ )
return shadow;
}

float2 fetchesUV[16];
SampleShadow_ComputeSamples_Tent_7x7(shadowMapTexture_TexelSize, coord.xy, fetchesWeights, fetchesUV);
for (int i = 0; i < 16; i++)
#if SHADOW_OPTIMIZE_REGISTER_USAGE == 1
int i;
[loop]
for( i = 0; i < 1; i++ )
{
shadow += fetchesWeights[ 0] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 0].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 1] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 1].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 2] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 2].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 3] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 3].xy, coord.z ), slice ).x;
}
[loop]
for( i = 0; i < 1; i++ )
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[i].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 4] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 4].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 5] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 5].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 6] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 6].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 7] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 7].xy, coord.z ), slice ).x;
[loop]
for( i = 0; i < 1; i++ )
{
shadow += fetchesWeights[ 8] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 8].xy, coord.z ), slice ).x;
shadow += fetchesWeights[ 9] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[ 9].xy, coord.z ), slice ).x;
shadow += fetchesWeights[10] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[10].xy, coord.z ), slice ).x;
shadow += fetchesWeights[11] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[11].xy, coord.z ), slice ).x;
}
[loop]
for( i = 0; i < 1; i++ )
{
shadow += fetchesWeights[12] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[12].xy, coord.z ), slice ).x;
shadow += fetchesWeights[13] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[13].xy, coord.z ), slice ).x;
shadow += fetchesWeights[14] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[14].xy, coord.z ), slice ).x;
shadow += fetchesWeights[15] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[15].xy, coord.z ), slice ).x;
}
#else
for( int i = 0; i < 16; i++ )
{
shadow += fetchesWeights[i] * SAMPLE_TEXTURE2D_ARRAY_SHADOW( tex, compSamp, float3( fetchesUV[i].xy, coord.z ), slice ).x;
}
#endif
return shadow;
}

10
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/VolumeRendering.hlsl


return exp(-opticalDepth);
}
float TransmittanceIntegralOverHomogeneousInterval(float extinction, float start, float end)
{
return (exp(-extinction * start) - exp(-extinction * end)) / extinction;
}
float3 OpticalDepthHomogeneous(float3 extinction, float intervalLength)
{
return extinction * intervalLength;

{
return exp(-opticalDepth);
}
float3 TransmittanceIntegralOverHomogeneousInterval(float3 extinction, float start, float end)
{
return (exp(-extinction * start) - exp(-extinction * end)) / extinction;
}
float IsotropicPhaseFunction()

32
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ShaderLibrary/Wind.hlsl


void ApplyWind( inout float3 worldPos,
inout float3 worldNormal,
float3 rootWP,
float stiffness,
float drag,
float shiverDrag,
float shiverDirectionality,
float initialBend,
float shiverMask,
float4 time)
void ApplyWindDisplacement( inout float3 positionWS,
float3 normalWS,
float3 rootWP,
float stiffness,
float drag,
float shiverDrag,
float shiverDirectionality,
float initialBend,
float shiverMask,
float4 time)
WindData wind = GetAnalyticalWind(worldPos, rootWP, drag, shiverDrag, initialBend, time);
WindData wind = GetAnalyticalWind(positionWS, rootWP, drag, shiverDrag, initialBend, time);
if(wind.Strength > 0.0f)
if (wind.Strength > 0.0f)
float att = AttenuateTrunk(distance(worldPos, rootWP), stiffness);
float att = AttenuateTrunk(distance(positionWS, rootWP), stiffness);
worldPos = Rotate(rootWP, worldPos, rotAxis, (wind.Strength) * 0.001 * att);
positionWS = Rotate(rootWP, positionWS, rotAxis, (wind.Strength) * 0.001 * att);
float3 shiverDirection = normalize(lerp(worldNormal, normalize(wind.Direction + wind.ShiverDirection), shiverDirectionality));
worldPos += wind.ShiverStrength * shiverDirection * shiverMask;
float3 shiverDirection = normalize(lerp(normalWS, normalize(wind.Direction + wind.ShiverDirection), shiverDirectionality));
positionWS += wind.ShiverStrength * shiverDirection * shiverMask;
}
}

2
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Singleton.cs


using UnityEngine.SceneManagement;
namespace UnityEngine.Experimental.Rendering
{
[ExecuteInEditMode]

90
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/TextureCache.cs


{
protected int m_NumMipLevels;
#if UNITY_EDITOR
static int s_TextureCacheIdGenerator = 0;
int m_TextureCacheId = 0;
static bool s_ForceReinjectGlobalFirst = false;
static bool s_ForceReinjectGlobalSecond = false;
static int s_GlobalSecondSetByTexCacheID = -1;
// here we receive the in-editor updated textures. These must be reinjected into
// any texture cache which has a stale copy of it. However, we don't have a this-pointer to the texture cache
// so instead we defer this to NewFrame() where we force reinject.
// Ideally we'd build up a list here of textures which are to be reinjected but unfortunately the texture we receive
// is an intermediate one and not the final compressed one. So instead we will have to reinject all in NewFrame().
internal class AssetReloader : UnityEditor.AssetPostprocessor
{
void OnPostprocessTexture(Texture texture)
{
s_ForceReinjectGlobalFirst = true;
s_ForceReinjectGlobalSecond = false;
s_GlobalSecondSetByTexCacheID = -1;
}
}
#endif
public static bool isMobileBuildTarget
{
get

private struct SSliceEntry
{
public uint texId;
public uint countLRU;
public uint texId;
public uint countLRU;
#if UNITY_EDITOR
public Hash128 hash;
#endif
};
private int m_NumTextures;

return sliceIndex;
var texId = (uint)texture.GetInstanceID();
#if UNITY_EDITOR
var hash = texture.imageContentsHash;
#endif
//assert(TexID!=g_InvalidTexID);
if (texId == g_InvalidTexID) return 0;

// search for existing copy
if (m_LocatorInSliceArray.ContainsKey(texId))
int cachedSlice;
if (m_LocatorInSliceArray.TryGetValue(texId, out cachedSlice))
sliceIndex = m_LocatorInSliceArray[texId];
sliceIndex = cachedSlice;
Debug.Assert(m_SliceArray[sliceIndex].texId == texId);
//assert(m_SliceArray[sliceIndex].TexID==TexID);
#if UNITY_EDITOR
bSwapSlice = bSwapSlice || (m_SliceArray[sliceIndex].hash != hash);
#endif
}
// If no existing copy found in the array

}
}
//assert(bFoundAvailOrExistingSlice);
Debug.Assert(bFoundAvailOrExistingSlice, "The texture cache doesn't have enough space to store all textures. Please either increase the size of the texture cache, or use fewer unique textures.");
if (bFoundAvailOrExistingSlice)
{
m_SliceArray[sliceIndex].countLRU = 0; // mark slice as in use this frame

#if UNITY_EDITOR
m_SliceArray[sliceIndex].hash = hash;
#endif
// transfer new slice to sliceIndex from source texture
TransferToSlice(sliceIndex, texture);
}

//for(int q=1; q<m_numTextures; q++)
// assert(m_SliceArray[m_SortedIdxArray[q-1]].CountLRU>=m_SliceArray[m_SortedIdxArray[q]].CountLRU);
#if UNITY_EDITOR
// one or more textures got updated in editor. Unfortunately we do not know exactly which since
// OnPostprocessTexture() receives intermediate uncompressed textures. So we will have to reinject all slices to force an update.
if(s_ForceReinjectGlobalSecond && s_GlobalSecondSetByTexCacheID==m_TextureCacheId)
{
s_ForceReinjectGlobalSecond = false;
s_GlobalSecondSetByTexCacheID = -1;
}
if(s_ForceReinjectGlobalFirst)
{
s_ForceReinjectGlobalSecond = true;
s_GlobalSecondSetByTexCacheID = m_TextureCacheId;
s_ForceReinjectGlobalFirst = false;
}
if(s_ForceReinjectGlobalSecond)
{
// all texture caches must loop through and force a reinject on all entries when this is true.
for(int i = 0; i < m_NumTextures; i++)
{
var texID = m_SliceArray[i].texId;
if(texID!=g_InvalidTexID)
{
Texture texture = (Texture) EditorUtility.InstanceIDToObject((int) texID);
if(texture!=null) TransferToSlice(i, texture);
}
}
}
#endif
}
protected TextureCache()

#if UNITY_EDITOR
m_TextureCacheId = s_TextureCacheIdGenerator; // assign an ID so we can tell the caches apart
++s_TextureCacheIdGenerator; // static/global
#endif
}
public virtual void TransferToSlice(int sliceIndex, Texture texture)

28
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/LegacyShadersToLightweightPipelineUpgrader.cs


{
public class LegacyShadersToLightweightPipelineUpgrader
{
[MenuItem("RenderPipeline/LightweightPipeline/Material Upgraders/Upgrade Legacy Materials to LightweightPipeline - Project", false, 3)]
public static void UpgradeMaterialsToLDProject()
{
List<MaterialUpgrader> materialUpgraders = new List<MaterialUpgrader>();
GetUpgraders(ref materialUpgraders);
//[MenuItem("RenderPipeline/Lightweight Pipeline/Material Upgraders/Upgrade Legacy Materials to LightweightPipeline - Project", false, 3)]
//public static void UpgradeMaterialsToLDProject()
//{
// List<MaterialUpgrader> materialUpgraders = new List<MaterialUpgrader>();
// GetUpgraders(ref materialUpgraders);
MaterialUpgrader.UpgradeProjectFolder(materialUpgraders, "Upgrade to LD Materials");
}
// MaterialUpgrader.UpgradeProjectFolder(materialUpgraders, "Upgrade to LD Materials");
//}
[MenuItem("RenderPipeline/LightweightPipeline/Material Upgraders/Upgrade Legacy Materials to LightweightPipeline - Selection", false, 4)]
public static void UpgradeMaterialsToLDSelection()
{
List<MaterialUpgrader> materialUpgraders = new List<MaterialUpgrader>();
GetUpgraders(ref materialUpgraders);
//[MenuItem("RenderPipeline/Lightweight Pipeline/Material Upgraders/Upgrade Legacy Materials to LightweightPipeline - Selection", false, 4)]
//public static void UpgradeMaterialsToLDSelection()
//{
// List<MaterialUpgrader> materialUpgraders = new List<MaterialUpgrader>();
// GetUpgraders(ref materialUpgraders);
MaterialUpgrader.UpgradeSelection(materialUpgraders, "Upgrade to Lightweight Materials");
}
// MaterialUpgrader.UpgradeSelection(materialUpgraders, "Upgrade to Lightweight Materials");
//}
private static void GetUpgraders(ref List<MaterialUpgrader> materialUpgraders)
{

46
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/LightweightAssetInspector.cs


public static GUIContent renderingLabel = new GUIContent("Rendering");
public static GUIContent shadowLabel = new GUIContent("Shadows");
public static GUIContent defaults = new GUIContent("Defaults");
public static GUIContent linearRenderingLabel = new GUIContent("Linear Colorspace", "When enabled Lightweight shader will perform gamma to linear conversion when linear rendering is not supported or disabled");
public static GUIContent maxPixelLights = new GUIContent("Per-Object Pixel Lights",
"Max amount of dynamic per-object pixel lights.");
public static GUIContent renderScaleLabel = new GUIContent("Render Scale", "Allows game to render at a resolution different than native resolution. UI is always rendered at native resolution.");
public static GUIContent maxAdditionalPixelLightsLabel = new GUIContent("Max Additional Pixel Lights",
"Controls the additional per-pixel lights that run in fragment light loop.");
"Lightweight pipeline support at most 4 per-object lights between pixel and vertex. If value in pixel lights is set to max this settings has no effect.");
"If enabled, shades additional lights exceeding maxAdditionalPixelLights per-vertex up to the maximum of 8 lights.");
public static GUIContent enableLightmap = new GUIContent("Enable Lightmap",
"Enabled/Disable support for non-directional lightmaps.");
public static GUIContent enableAmbientProbe = new GUIContent("Enable Light Probes",
"Enables/Disable light probe support.");
public static GUIContent enableSoftParticles = new GUIContent("Enable Soft Particles", "By enabled this the pipeline will generate depth texture necessary for SoftParticles");
public static GUIContent shadowType = new GUIContent("Shadow Type",
"Single directional shadow supported. SOFT_SHADOWS applies shadow filtering.");

"Material to use when creating 3D objects");
public static GUIContent defaultParticleMaterial = new GUIContent("Default Particle Material",
"Material to use when creating Paticle Systems");
"Material to use when creating Particle Systems");
public static GUIContent defaultLineMaterial = new GUIContent("Default Line Material",
"Material to use when creating Line Renderers");

public static GUIContent defaultShader = new GUIContent("Default Shader",
"Shader to use when creating materials");
public static GUIContent msaaContent = new GUIContent("Anti Aliasing", "Controls the global anti aliasing quality. When set to disabled, MSAA will not be performed even if the camera allows it.");
public static GUIContent msaaContent = new GUIContent("Anti Aliasing (MSAA)", "Controls the global anti aliasing quality. When set to disabled, MSAA will not be performed even if the camera allows it.");
private SerializedProperty m_LinearRenderingProperty;
private SerializedProperty m_MaxPixelLights;
private int kMaxSupportedAdditionalPixelLights = 8;
private SerializedProperty m_RenderScale;
private SerializedProperty m_MaxAdditionalPixelLights;
private SerializedProperty m_EnableLightmapsProp;
private SerializedProperty m_EnableAmbientProbeProp;
private SerializedProperty m_SupportSoftParticlesProp;
private SerializedProperty m_ShadowTypeProp;
private SerializedProperty m_ShadowNearPlaneOffsetProp;
private SerializedProperty m_ShadowDistanceProp;

void OnEnable()
{
m_LinearRenderingProperty = serializedObject.FindProperty("m_LinearRendering");
m_MaxPixelLights = serializedObject.FindProperty("m_MaxPixelLights");
m_RenderScale = serializedObject.FindProperty("m_RenderScale");
m_MaxAdditionalPixelLights = serializedObject.FindProperty("m_MaxAdditionalPixelLights");
m_EnableLightmapsProp = serializedObject.FindProperty("m_EnableLightmaps");
m_EnableAmbientProbeProp = serializedObject.FindProperty("m_EnableAmbientProbe");
m_SupportSoftParticlesProp = serializedObject.FindProperty("m_SupportSoftParticles");
m_ShadowTypeProp = serializedObject.FindProperty("m_ShadowType");
m_ShadowNearPlaneOffsetProp = serializedObject.FindProperty("m_ShadowNearPlaneOffset");
m_ShadowDistanceProp = serializedObject.FindProperty("m_ShadowDistance");

EditorGUILayout.Space();
EditorGUILayout.LabelField(Styles.renderingLabel, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_LinearRenderingProperty, Styles.linearRenderingLabel);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(Styles.renderScaleLabel);
m_RenderScale.floatValue = EditorGUILayout.Slider(m_RenderScale.floatValue, 0.1f, 1.0f);
EditorGUILayout.EndHorizontal();
EditorGUILayout.LabelField(Styles.maxPixelLights);
m_MaxPixelLights.intValue = EditorGUILayout.IntSlider(m_MaxPixelLights.intValue, 0, 4);
EditorGUILayout.LabelField(Styles.maxAdditionalPixelLightsLabel);
m_MaxAdditionalPixelLights.intValue = EditorGUILayout.IntSlider(m_MaxAdditionalPixelLights.intValue, 0, kMaxSupportedAdditionalPixelLights);
EditorGUILayout.PropertyField(m_EnableLightmapsProp, Styles.enableLightmap);
EditorGUILayout.PropertyField(m_EnableAmbientProbeProp, Styles.enableAmbientProbe);
EditorGUILayout.PropertyField(m_SupportSoftParticlesProp, Styles.enableSoftParticles);
EditorGUILayout.PropertyField(m_MSAA, Styles.msaaContent);
EditorGUILayout.PropertyField(m_AttenuationTexture, Styles.attenuationTextureLabel);
EditorGUI.indentLevel--;

72
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/LightweightPipelineUpgraders.cs


using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering.LightweightPipeline;
namespace UnityEditor.Experimental.Rendering.LightweightPipeline
{

blendMode = UpgradeBlendMode.Opaque,
specularSource = SpecularSource.NoSpecular,
glosinessSource = GlossinessSource.BaseAlpha,
reflectionSource = ReflectionSource.NoReflection
};
static public UpgradeParams specularOpaque = new UpgradeParams()

glosinessSource = GlossinessSource.BaseAlpha,
reflectionSource = ReflectionSource.NoReflection
};
static public UpgradeParams diffuseAlpha = new UpgradeParams()

glosinessSource = GlossinessSource.SpecularAlpha,
reflectionSource = ReflectionSource.NoReflection
};
static public UpgradeParams specularAlpha = new UpgradeParams()

glosinessSource = GlossinessSource.SpecularAlpha,
reflectionSource = ReflectionSource.NoReflection
};
static public UpgradeParams diffuseAlphaCutout = new UpgradeParams()

glosinessSource = GlossinessSource.SpecularAlpha,
reflectionSource = ReflectionSource.NoReflection
};
static public UpgradeParams specularAlphaCutout = new UpgradeParams()

glosinessSource = GlossinessSource.SpecularAlpha,
reflectionSource = ReflectionSource.NoReflection
};
static public UpgradeParams diffuseCubemap = new UpgradeParams()

glosinessSource = GlossinessSource.BaseAlpha,
reflectionSource = ReflectionSource.Cubemap
};
static public UpgradeParams specularCubemap = new UpgradeParams()

glosinessSource = GlossinessSource.BaseAlpha,
reflectionSource = ReflectionSource.Cubemap
};
static public UpgradeParams diffuseCubemapAlpha = new UpgradeParams()

glosinessSource = GlossinessSource.BaseAlpha,
reflectionSource = ReflectionSource.Cubemap
};
static public UpgradeParams specularCubemapAlpha = new UpgradeParams()

glosinessSource = GlossinessSource.BaseAlpha,
reflectionSource = ReflectionSource.Cubemap
};
}

{
RenameShader(oldShaderName, "ScriptableRenderPipeline/LightweightPipeline/NonPBR", UpdateMaterialKeywords);
RenameShader(oldShaderName, LightweightPipelineAsset.m_SimpleLightShaderPath, UpdateMaterialKeywords);
SetFloat("_ReflectionSource", (float)upgradeParams.reflectionSource);
if (oldShaderName.Contains("Legacy Shaders/Self-Illumin"))
{

public static void UpdateMaterialKeywords(Material material)
{
material.shaderKeywords = null;
UpdateMaterialReflectionSource(material);
LightweightShaderHelper.SetKeyword(material, "_CUBEMAP_REFLECTION", material.GetTexture("_Cube"));
LightweightShaderHelper.SetKeyword(material, "_EMISSION", material.GetTexture("_EmissionMap"));
// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect
// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.
// The fixup routine makes sure that the material is in the correct state if/when changes are made to the mode or color.
MaterialEditor.FixupEmissiveFlag(material);
bool shouldEmissionBeEnabled = (material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
LightweightShaderHelper.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
}
private static void UpdateMaterialSpecularSource(Material material)

{
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP", false);
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP_BASE_ALPHA", false);
}
else if (specSource == SpecularSource.SpecularTextureAndColor && material.GetTexture("_SpecGlossMap"))
{
GlossinessSource glossSource = (GlossinessSource)material.GetFloat("_GlossinessSource");
if (glossSource == GlossinessSource.BaseAlpha)
{
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP", false);
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP_BASE_ALPHA", true);
}
else
{
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP", true);
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP_BASE_ALPHA", false);
}
LightweightShaderHelper.SetKeyword(material, "_SPECULAR_COLOR", false);
LightweightShaderHelper.SetKeyword(material, "_GLOSSINESS_FROM_BASE_ALPHA", false);
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP", false);
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP_BASE_ALPHA", false);
LightweightShaderHelper.SetKeyword(material, "_SPECULAR_COLOR", true);
}
}
private static void UpdateMaterialReflectionSource(Material material)
{
LightweightShaderHelper.SetKeyword(material, "_REFLECTION_CUBEMAP", false);
LightweightShaderHelper.SetKeyword(material, "_REFLECTION_PROBE", false);
ReflectionSource reflectionSource = (ReflectionSource)material.GetFloat("_ReflectionSource");
if (reflectionSource == ReflectionSource.Cubemap && material.GetTexture("_Cube"))
{
LightweightShaderHelper.SetKeyword(material, "_REFLECTION_CUBEMAP", true);
}
else if (reflectionSource == ReflectionSource.ReflectionProbe)
{
LightweightShaderHelper.SetKeyword(material, "_REFLECTION_PROBE", true);
GlossinessSource glossSource = (GlossinessSource)material.GetFloat("_GlossinessSource");
bool hasGlossMap = material.GetTexture("_SpecGlossMap");
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP", hasGlossMap);
LightweightShaderHelper.SetKeyword(material, "_SPECULAR_COLOR", !hasGlossMap);
LightweightShaderHelper.SetKeyword(material, "_GLOSSINESS_FROM_BASE_ALPHA", glossSource == GlossinessSource.BaseAlpha);
}
}
}

public StandardUpgrader(string oldShaderName)
{
RenameShader(oldShaderName, "ScriptableRenderPipeline/LightweightPipeline/NonPBR");
RenameShader(oldShaderName, LightweightPipelineAsset.m_StandardShaderPath);
}
}

{
RenameShader(oldShaderName, "ScriptableRenderPipeline/LightweightPipeline/NonPBR");
RenameShader(oldShaderName, LightweightPipelineAsset.m_StandardShaderPath);
SetFloat("_Shininess", 1.0f);
}
}

3
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/ShaderGUI/LightweightUnlitGUI.cs


using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor.Experimental.Rendering.LightweightPipeline;
public class LightweightUnlitGUI : ShaderGUI

{
blendModeProp = FindProperty("_Mode", properties);
mainTexProp = FindProperty("_MainTex", properties);
mainColorProp = FindProperty("_Color", properties);
mainColorProp = FindProperty("_MainColor", properties);
alphaCutoffProp = FindProperty("_Cutoff", properties);
}

8
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/StandardToLightweightMaterialUpgrader.cs


{
public class StandardToLightweightMaterialUpgrader
{
[MenuItem("RenderPipeline/LightweightPipeline/Material Upgraders/Upgrade Standard Materials to Lightweight Mobile - Project Folder", false, 1)]
[MenuItem("RenderPipeline/Lightweight Pipeline/Material Upgraders/Upgrade Project Materials", false, 1)]
MaterialUpgrader.UpgradeProjectFolder(upgraders, "Upgrade to LD Materials");
MaterialUpgrader.UpgradeProjectFolder(upgraders, "Upgrade to Lightweight Pipeline Materials");
[MenuItem("RenderPipeline/LightweightPipeline/Material Upgraders/Upgrade Standard Materials to Lightweight Mobile - Selection", false, 2)]
[MenuItem("RenderPipeline/Lightweight Pipeline/Material Upgraders/Upgrade Selected Materials", false, 2)]
MaterialUpgrader.UpgradeSelection(upgraders, "Upgrade to LD Materials");
MaterialUpgrader.UpgradeSelection(upgraders, "Upgrade to Lightweight Pipeline Materials");
}
private static void GetUpgraders(ref List<MaterialUpgrader> upgraders)

1
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/UpgradeCommon.cs


public UpgradeBlendMode blendMode;
public SpecularSource specularSource;
public GlossinessSource glosinessSource;
public ReflectionSource reflectionSource;
}
}

888
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipeline.cs


using System;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.XR;

public struct LightData
{
public int pixelLightsCount;
public int vertexLightsCount;
public int shadowLightIndex;
public bool isSingleLight;
public int pixelAdditionalLightsCount;
public int totalAdditionalLightsCount;
public int mainLightIndex;
public bool shadowsRendered;
}

// Max amount of visible lights. This controls the lights constant buffers in shader but not the max shaded lights.
// Lights are set per-object and the max shaded lights for each object are controlled by the max pixel lights in pipeline asset and kMaxVertexLights.
private static readonly int kMaxVisibleLights = 16;
private static readonly int kMaxPerObjectLights = 4;
// Maximum amount of visible lights the shader can process. This controls the constant global light buffer size.
// It must match the MAX_VISIBLE_LIGHTS in LightweightCore.cginc
private static readonly int kMaxVisibleAdditionalLights = 16;
private Vector4[] m_LightPositions = new Vector4[kMaxVisibleLights];
private Vector4[] m_LightColors = new Vector4[kMaxVisibleLights];
private Vector4[] m_LightAttenuations = new Vector4[kMaxVisibleLights];
private Vector4[] m_LightSpotDirections = new Vector4[kMaxVisibleLights];
// Lights are culled per-object. This holds the maximum amount of additional lights that can shade each object.
// The engine fills in the lights indices per-object in unity4_LightIndices0 and unity_4LightIndices1
private static readonly int kMaxPerObjectAdditionalLights = 8;
private Camera m_CurrCamera = null;
private LightType m_SingleLightType = LightType.Directional;
private Vector4[] m_LightPositions = new Vector4[kMaxVisibleAdditionalLights];
private Vector4[] m_LightColors = new Vector4[kMaxVisibleAdditionalLights];
private Vector4[] m_LightAttenuations = new Vector4[kMaxVisibleAdditionalLights];
private Vector4[] m_LightSpotDirections = new Vector4[kMaxVisibleAdditionalLights];
private int m_LightIndicesCount = 0;
private ComputeBuffer m_LightIndexListBuffer;
private Camera m_CurrCamera = null;
private int m_ShadowMapProperty;
private int m_CameraRTProperty;
private RenderTargetIdentifier m_ShadowMapRTID;
private RenderTargetIdentifier m_CameraRTID;
private int m_ShadowMapTexture;
private int m_CameraColorTexture;
private int m_CameraDepthTexture;
private int m_CameraCopyDepthTexture;
private RenderTargetIdentifier m_ShadowMapRT;
private RenderTargetIdentifier m_CameraColorRT;
private RenderTargetIdentifier m_CameraDepthRT;
private RenderTargetIdentifier m_CameraCopyDepthRT;
private bool m_RenderToIntermediateTarget = false;
private bool m_IntermediateTextureArray = false;
private const int kShadowDepthBufferBits = 16;

private static readonly ShaderPassName m_LitPassName = new ShaderPassName("LightweightForward");
private static readonly ShaderPassName m_UnlitPassName = new ShaderPassName("SRPDefaultUnlit");
private RenderTextureFormat m_ColorFormat = RenderTextureFormat.ARGB32;
private RenderTextureFormat m_ColorFormat;
private PostProcessLayer m_CameraPostProcessLayer;
private LightComparer m_LightCompararer = new LightComparer();
// Maps from sorted light indices to original unsorted. We need this for shadow rendering
// and per-object light lists.
private List<int> m_SortedLightIndexMap = new List<int>();
private Mesh m_BlitQuad;
private Material m_BlitMaterial;
private Material m_CopyDepthMaterial;
private int m_BlitTexID = Shader.PropertyToID("_BlitTex");
private CopyTextureSupport m_CopyTextureSupport;
public LightweightPipeline(LightweightPipelineAsset asset)
{

m_ShadowMapProperty = Shader.PropertyToID("_ShadowMap");
m_CameraRTProperty = Shader.PropertyToID("_CameraRT");
m_ShadowMapRTID = new RenderTargetIdentifier(m_ShadowMapProperty);
m_CameraRTID = new RenderTargetIdentifier(m_CameraRTProperty);
PerFrameBuffer._GlossyEnvironmentColor = Shader.PropertyToID("_GlossyEnvironmentColor");
PerFrameBuffer._AttenuationTexture = Shader.PropertyToID("_AttenuationTexture");
PerCameraBuffer._MainLightPosition = Shader.PropertyToID("_MainLightPosition");
PerCameraBuffer._MainLightColor = Shader.PropertyToID("_MainLightColor");
PerCameraBuffer._MainLightAttenuationParams = Shader.PropertyToID("_MainLightAttenuationParams");
PerCameraBuffer._MainLightSpotDir = Shader.PropertyToID("_MainLightSpotDir");
PerCameraBuffer._AdditionalLightCount = Shader.PropertyToID("_AdditionalLightCount");
PerCameraBuffer._AdditionalLightPosition = Shader.PropertyToID("_AdditionalLightPosition");
PerCameraBuffer._AdditionalLightColor = Shader.PropertyToID("_AdditionalLightColor");
PerCameraBuffer._AdditionalLightAttenuationParams = Shader.PropertyToID("_AdditionalLightAttenuationParams");
PerCameraBuffer._AdditionalLightSpotDir = Shader.PropertyToID("_AdditionalLightSpotDir");
m_ShadowMapTexture = Shader.PropertyToID("_ShadowMap");
m_CameraColorTexture = Shader.PropertyToID("_CameraColorTexture");
m_CameraDepthTexture = Shader.PropertyToID("_CameraDepthTexture");
m_CameraCopyDepthTexture = Shader.PropertyToID("_CameraCopyDepthTexture");
m_ShadowMapRT = new RenderTargetIdentifier(m_ShadowMapTexture);
m_CameraColorRT = new RenderTargetIdentifier(m_CameraColorTexture);
m_CameraDepthRT = new RenderTargetIdentifier(m_CameraDepthTexture);
m_CameraCopyDepthRT = new RenderTargetIdentifier(m_CameraCopyDepthTexture);
m_CopyTextureSupport = SystemInfo.copyTextureSupport;
// Let engine know we have MSAA on for cases where we support MSAA backbuffer
if (QualitySettings.antiAliasing != m_Asset.MSAASampleCount)

m_BlitQuad = LightweightUtils.CreateQuadMesh(false);
m_BlitMaterial = new Material(m_Asset.BlitShader)
{
hideFlags = HideFlags.HideAndDontSave
};
m_CopyDepthMaterial = new Material(m_Asset.CopyDepthShader)
{
hideFlags = HideFlags.HideAndDontSave
};
if (m_LightIndexListBuffer != null)
{
m_LightIndexListBuffer.Dispose();
m_LightIndexListBuffer = null;
m_LightIndicesCount = 0;
}
}
CullResults m_CullResults;

// instead this should be forced when using SRP, since all SRP use linear lighting.
GraphicsSettings.lightsUseLinearIntensity = true;
SetupPerFrameShaderConstants(ref context);
// Sort cameras array by camera depth
Array.Sort(cameras, m_CameraComparer);
foreach (Camera camera in cameras)
{

if (!CullResults.GetCullingParameters(m_CurrCamera, stereoEnabled, out cullingParameters))
continue;
cullingParameters.shadowDistance = Mathf.Min(m_ShadowSettings.maxShadowDistance, m_CurrCamera.farClipPlane);
CullResults.Cull(ref cullingParameters, context,ref m_CullResults);
cullingParameters.shadowDistance = Mathf.Min(m_ShadowSettings.maxShadowDistance,
m_CurrCamera.farClipPlane);
#if UNITY_EDITOR
// Emit scene view UI
if (camera.cameraType == CameraType.SceneView)
ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
#endif
CullResults.Cull(ref cullingParameters, context, ref m_CullResults);
// Render Shadow Map
if (lightData.shadowLightIndex > -1)
lightData.shadowsRendered = RenderShadows(ref m_CullResults, ref visibleLights[lightData.shadowLightIndex], lightData.shadowLightIndex, ref context);
ShadowPass(visibleLights, ref context, ref lightData);
ForwardPass(visibleLights, ref context, ref lightData, stereoEnabled);
// Setup camera matrices and RT
context.SetupCameraProperties(m_CurrCamera, stereoEnabled);
// Release temporary RT
var cmd = CommandBufferPool.Get("After Camera Render");
cmd.ReleaseTemporaryRT(m_ShadowMapTexture);
cmd.ReleaseTemporaryRT(m_CameraColorTexture);
cmd.ReleaseTemporaryRT(m_CameraDepthTexture);
cmd.ReleaseTemporaryRT(m_CameraCopyDepthTexture);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
// Setup light and shadow shader constants
SetupShaderLightConstants(visibleLights, ref lightData, ref m_CullResults, ref context);
if (lightData.shadowsRendered)
SetupShadowShaderConstants(ref context, ref visibleLights[lightData.shadowLightIndex], lightData.shadowLightIndex, m_ShadowCasterCascadesCount);
SetShaderKeywords(ref lightData, ref context);
context.Submit();
}
}
RendererConfiguration configuration = RendererConfiguration.PerObjectReflectionProbes;
if (m_Asset.EnableLightmap)
configuration |= RendererConfiguration.PerObjectLightmaps;
private void ShadowPass(VisibleLight[] visibleLights, ref ScriptableRenderContext context, ref LightData lightData)
{
if (m_Asset.AreShadowsEnabled() && lightData.mainLightIndex != -1)
{
VisibleLight mainLight = visibleLights[lightData.mainLightIndex];
if (m_Asset.EnableAmbientProbe)
configuration |= RendererConfiguration.PerObjectLightProbe;
if (mainLight.light.shadows != LightShadows.None)
{
if (!LightweightUtils.IsSupportedShadowType(mainLight.lightType))
{
Debug.LogWarning("Only directional and spot shadows are supported by LightweightPipeline.");
return;
}
if (!lightData.isSingleLight)
configuration |= RendererConfiguration.PerObjectLightIndices8;
// There's no way to map shadow light indices. We need to pass in the original unsorted index.
// If no additional lights then no light sorting is performed and the indices match.
int shadowOriginalIndex = (lightData.totalAdditionalLightsCount > 0) ? GetLightUnsortedIndex(lightData.mainLightIndex) : lightData.mainLightIndex;
lightData.shadowsRendered = RenderShadows(ref m_CullResults, ref mainLight,
shadowOriginalIndex, ref context);
}
}
}
PostProcessLayer postProcessLayer = GetCurrCameraPostProcessLayer();
bool postProcessEnabled = postProcessLayer != null && postProcessLayer.enabled;
m_RenderToIntermediateTarget = postProcessEnabled || GetRenderToIntermediateTarget();
private void ForwardPass(VisibleLight[] visibleLights, ref ScriptableRenderContext context, ref LightData lightData, bool stereoEnabled)
{
FrameRenderingConfiguration frameRenderingConfiguration;
SetupFrameRendering(out frameRenderingConfiguration);
SetupIntermediateResources(frameRenderingConfiguration, ref context);
SetupShaderConstants(visibleLights, ref context, ref lightData);
BeginForwardRendering(ref context, stereoEnabled);
// SetupCameraProperties does the following:
// Setup Camera RenderTarget and Viewport
// VR Camera Setup and SINGLE_PASS_STEREO props
// Setup camera view, proj and their inv matrices.
// Setup properties: _WorldSpaceCameraPos, _ProjectionParams, _ScreenParams, _ZBufferParams, unity_OrthoParams
// Setup camera world clip planes props
// setup HDR keyword
// Setup global time properties (_Time, _SinTime, _CosTime)
context.SetupCameraProperties(m_CurrCamera, stereoEnabled);
var litDrawSettings = new DrawRendererSettings(m_CurrCamera, m_LitPassName);
litDrawSettings.sorting.flags = SortFlags.CommonOpaque;
litDrawSettings.rendererConfiguration = configuration;
RendererConfiguration rendererSettings = GetRendererSettings(ref lightData);
var unlitDrawSettings = new DrawRendererSettings(m_CurrCamera, m_UnlitPassName);
unlitDrawSettings.sorting.flags = SortFlags.CommonTransparent;
BeginForwardRendering(ref context, frameRenderingConfiguration);
RenderOpaques(ref context, rendererSettings);
AfterOpaque(ref context, frameRenderingConfiguration);
RenderTransparents(ref context, rendererSettings);
AfterTransparent(ref context, frameRenderingConfiguration);
EndForwardRendering(ref context, frameRenderingConfiguration);
}
// Render Opaques
var opaqueFilterSettings = new FilterRenderersSettings(true) {renderQueueRange = RenderQueueRange.opaque};
private void RenderOpaques(ref ScriptableRenderContext context, RendererConfiguration settings)
{
var opaqueDrawSettings = new DrawRendererSettings(m_CurrCamera, m_LitPassName);
opaqueDrawSettings.sorting.flags = SortFlags.CommonOpaque;
opaqueDrawSettings.rendererConfiguration = settings;
context.DrawRenderers(m_CullResults.visibleRenderers, ref litDrawSettings, opaqueFilterSettings);
var opaqueFilterSettings = new FilterRenderersSettings(true)
{
renderQueueRange = RenderQueueRange.opaque
};
// TODO: Check skybox shader
context.DrawSkybox(m_CurrCamera);
context.DrawRenderers(m_CullResults.visibleRenderers, ref opaqueDrawSettings, opaqueFilterSettings);
context.DrawSkybox(m_CurrCamera);
}
// Render Alpha blended
var transparentFilterSettings = new FilterRenderersSettings(true) {renderQueueRange = RenderQueueRange.transparent};
private void AfterOpaque(ref ScriptableRenderContext context, FrameRenderingConfiguration config)
{
if (!LightweightUtils.HasFlag(config, FrameRenderingConfiguration.RequireDepth))
return;
litDrawSettings.sorting.flags = SortFlags.CommonTransparent;
context.DrawRenderers(m_CullResults.visibleRenderers, ref litDrawSettings, transparentFilterSettings);
context.DrawRenderers(m_CullResults.visibleRenderers, ref unlitDrawSettings, transparentFilterSettings);
CommandBuffer cmd = CommandBufferPool.Get("After Opaque");
cmd.SetGlobalTexture(m_CameraDepthTexture, m_CameraDepthRT);
if (postProcessEnabled)
RenderPostProcess(ref context, postProcessLayer);
// When soft particles are enabled we have to copy depth to another RT so we can read and write to depth
if (m_Asset.SupportsSoftParticles)
{
RenderTargetIdentifier colorRT = (m_CurrCamera.targetTexture != null) ? BuiltinRenderTextureType.CameraTarget : m_CameraColorRT;
CopyTexture(cmd, m_CameraDepthRT, m_CameraCopyDepthTexture);
SetupRenderTargets(cmd, colorRT, m_CameraCopyDepthRT);
}
EndForwardRendering(ref context, stereoEnabled, postProcessEnabled);
// Only takes effect if custom BeforeTransparent PostProcessing effects are active
if (LightweightUtils.HasFlag(config, FrameRenderingConfiguration.PostProcess))
RenderPostProcess(cmd , true);
// Release temporary RT
var discardRT = CommandBufferPool.Get();
discardRT.ReleaseTemporaryRT(m_ShadowMapProperty);
discardRT.ReleaseTemporaryRT(m_CameraRTProperty);
context.ExecuteCommandBuffer(discardRT);
CommandBufferPool.Release(discardRT);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
context.Submit();
private void AfterTransparent(ref ScriptableRenderContext context, FrameRenderingConfiguration config)
{
if (!LightweightUtils.HasFlag(config, FrameRenderingConfiguration.PostProcess))
return;
CommandBuffer cmd = CommandBufferPool.Get("After Transparent");
RenderPostProcess(cmd, false);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void RenderTransparents(ref ScriptableRenderContext context, RendererConfiguration config)
{
var transparentSettings = new DrawRendererSettings(m_CurrCamera, m_LitPassName);
transparentSettings.SetShaderPassName(1, m_UnlitPassName);
transparentSettings.sorting.flags = SortFlags.CommonTransparent;
transparentSettings.rendererConfiguration = config;
var transparentFilterSettings = new FilterRenderersSettings(true)
{
renderQueueRange = RenderQueueRange.transparent
};
context.DrawRenderers(m_CullResults.visibleRenderers, ref transparentSettings, transparentFilterSettings);
}
private void BuildShadowSettings()

}
}
private void InitializeLightData(VisibleLight[] lights, out LightData lightData)
private void SetupFrameRendering(out FrameRenderingConfiguration configuration)
int lightsCount = lights.Length;
int maxPerPixelLights = Math.Min(m_Asset.MaxSupportedPixelLights, kMaxPerObjectLights);
lightData.pixelLightsCount = Math.Min(lightsCount, maxPerPixelLights);
lightData.vertexLightsCount = (m_Asset.SupportsVertexLight) ? Math.Min(lightsCount - lightData.pixelLightsCount, kMaxPerObjectLights) : 0;
configuration = (XRSettings.enabled) ? FrameRenderingConfiguration.Stereo : FrameRenderingConfiguration.None;
if (XRSettings.enabled && XRSettings.eyeTextureDesc.dimension == TextureDimension.Tex2DArray)
m_IntermediateTextureArray = true;
else
m_IntermediateTextureArray = false;
bool intermediateTexture = m_CurrCamera.targetTexture != null || m_CurrCamera.cameraType == CameraType.SceneView ||
m_Asset.RenderScale < 1.0f || m_CurrCamera.allowHDR;
m_ColorFormat = m_CurrCamera.allowHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
m_CameraPostProcessLayer = m_CurrCamera.GetComponent<PostProcessLayer>();
bool postProcessEnabled = m_CameraPostProcessLayer != null && m_CameraPostProcessLayer.enabled;
if (postProcessEnabled || m_Asset.SupportsSoftParticles)
{
configuration |= FrameRenderingConfiguration.RequireDepth;
intermediateTexture = true;
if (postProcessEnabled)
configuration |= FrameRenderingConfiguration.PostProcess;
}
// When post process or soft particles are enabled we disable msaa due to lack of depth resolve
// One can still use PostFX AA
else if (m_CurrCamera.allowMSAA && m_Asset.MSAASampleCount > 1)
{
configuration |= FrameRenderingConfiguration.Msaa;
intermediateTexture = !LightweightUtils.PlatformSupportsMSAABackBuffer();
}
Rect cameraRect = m_CurrCamera.rect;
if (cameraRect.x > 0.0f || cameraRect.y > 0.0f || cameraRect.width < 1.0f || cameraRect.height < 1.0f)
intermediateTexture = true;
else
configuration |= FrameRenderingConfiguration.DefaultViewport;
if (intermediateTexture)
configuration |= FrameRenderingConfiguration.IntermediateTexture;
}
// TODO: Handle Vertex lights in this case
lightData.isSingleLight = lightData.pixelLightsCount <= 1;
if (lightData.isSingleLight)
m_SingleLightType = (lightData.pixelLightsCount == 1) ? lights[0].lightType : LightType.Directional;
private void SetupIntermediateResources(FrameRenderingConfiguration renderingConfig, ref ScriptableRenderContext context)
{
CommandBuffer cmd = CommandBufferPool.Get("Setup Intermediate Resources");
float renderScale = (m_CurrCamera.cameraType == CameraType.Game) ? m_Asset.RenderScale : 1.0f;
int rtWidth = (int)((float)m_CurrCamera.pixelWidth * renderScale);
int rtHeight = (int)((float)m_CurrCamera.pixelHeight * renderScale);
int msaaSamples = (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.Msaa)) ? m_Asset.MSAASampleCount : 1;
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.IntermediateTexture))
{
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.Stereo))
{
RenderTextureDescriptor rtDesc = new RenderTextureDescriptor();
rtDesc = XRSettings.eyeTextureDesc;
rtDesc.colorFormat = m_ColorFormat;
rtDesc.msaaSamples = msaaSamples;
cmd.GetTemporaryRT(m_CameraColorTexture, rtDesc, FilterMode.Bilinear);
}
else if (m_CurrCamera.targetTexture == null)
{
cmd.GetTemporaryRT(m_CameraColorTexture, rtWidth, rtHeight, kCameraDepthBufferBits,
FilterMode.Bilinear, m_ColorFormat, RenderTextureReadWrite.Default, msaaSamples);
}
}
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.RequireDepth))
{
cmd.GetTemporaryRT(m_CameraDepthTexture, rtWidth, rtHeight, kCameraDepthBufferBits, FilterMode.Bilinear, RenderTextureFormat.Depth);
if (m_Asset.SupportsSoftParticles)
cmd.GetTemporaryRT(m_CameraCopyDepthTexture, rtWidth, rtHeight, kCameraDepthBufferBits, FilterMode.Bilinear, RenderTextureFormat.Depth);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void SetupShaderConstants(VisibleLight[] visibleLights, ref ScriptableRenderContext context, ref LightData lightData)
{
CommandBuffer cmd = CommandBufferPool.Get("SetupShaderConstants");
SetupShaderLightConstants(cmd, visibleLights, ref lightData, ref m_CullResults, ref context);
SetShaderKeywords(cmd, ref lightData, visibleLights);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void InitializeLightData(VisibleLight[] visibleLights, out LightData lightData)
{
int visibleLightsCount = visibleLights.Length;
m_SortedLightIndexMap.Clear();
if (visibleLightsCount <= 1)
{
// If there's exactly one visible light that will be picked as main light.
// Otherwise we disable main light by setting its index to -1.
lightData.mainLightIndex = visibleLightsCount - 1;
lightData.pixelAdditionalLightsCount = 0;
lightData.totalAdditionalLightsCount = 0;
return;
}
InitializeMainShadowLightIndex(lights, out lightData.shadowLightIndex);
// We always support at least one per-pixel light, which is main light. Shade objects up to a limit of per-object
// pixel lights defined in the pipeline settings.
int maxSupportedPixelLights = Math.Min(m_Asset.MaxAdditionalPixelLights, kMaxPerObjectAdditionalLights) + 1;
int maxPixelLights = Math.Min(maxSupportedPixelLights, visibleLightsCount);
// If vertex lighting is enabled in the pipeline settings, then we shade the remaining visible lights per-vertex
// up to the maximum amount of per-object lights.
int vertexLights = (m_Asset.SupportsVertexLight) ? kMaxPerObjectAdditionalLights - maxPixelLights - 1: 0;
lightData.mainLightIndex = SortLights(visibleLights);
lightData.pixelAdditionalLightsCount = maxPixelLights - 1;
lightData.totalAdditionalLightsCount = lightData.pixelAdditionalLightsCount + vertexLights;
}
private int SortLights(VisibleLight[] visibleLights)
{
int totalVisibleLights = visibleLights.Length;
Dictionary<int, int> visibleLightsIDMap = new Dictionary<int, int>();
for (int i = 0; i < totalVisibleLights; ++i)
visibleLightsIDMap.Add(visibleLights[i].GetHashCode(), i);
// Sorts light so we have all directionals first, then local lights.
// Directionals are sorted further by shadow, cookie and intensity
// Locals are sorted further by shadow, cookie and distance to camera
m_LightCompararer.CurrCamera = m_CurrCamera;
Array.Sort(visibleLights, m_LightCompararer);
for (int i = 0; i < totalVisibleLights; ++i)
m_SortedLightIndexMap.Add(visibleLightsIDMap[visibleLights[i].GetHashCode()]);
return GetMainLight(visibleLights);
private void SetupShaderLightConstants(VisibleLight[] lights, ref LightData lightData, ref CullResults cullResults, ref ScriptableRenderContext context)
// How main light is decided:
// If shadows enabled, main light is always a shadow casting light. Directional has priority over local lights.
// Otherwise directional lights have priority based on cookie support and intensity
// If no directional light in the scene local lights based on cookie support and distance to camera
private int GetMainLight(VisibleLight[] visibleLights)
if (lightData.isSingleLight)
SetupShaderSingleLightConstants(lights, (lightData.pixelLightsCount > 0) ? 0 : -1, ref context);
else
SetupShaderLightListConstants(lights, ref lightData, ref context);
int totalVisibleLights = visibleLights.Length;
bool shadowsEnabled = m_Asset.AreShadowsEnabled();
// If shadows are supported and the first visible light has shadows then this is main light
if (shadowsEnabled && visibleLights[0].light.shadows != LightShadows.None)
return 0;
// We don't have any directional shadow casting light, skip until we find the first non directional light
int lightIndex = 0;
while (lightIndex < totalVisibleLights && visibleLights[lightIndex].lightType == LightType.Directional)
lightIndex++;
// If first non-directional light has shadows we return it, otherwise we return first light
return (lightIndex < totalVisibleLights && visibleLights[lightIndex].light.shadows != LightShadows.None) ? lightIndex : 0;
lightPos = Vector4.zero;
lightPos = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
// When no lights are available in the pipeline or maxPixelLights is set to 0
// In this case we want to initialize the lightData to default values and return
// When no lights are visible, main light will be set to -1.
// In this case we initialize it to default values and return
if (lightIndex < 0)
return;

Vector4 dir = light.localToWorld.GetColumn(2);
lightSpotDir = new Vector4(-dir.x, -dir.y, -dir.z, 0.0f);
// Spot Attenuation with a linear falloff can be defined as
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
// This can be rewritten as
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
// If we precompute the terms in a MAD instruction
float angleRange = cosInneAngle - cosOuterAngle;
lightAttenuationParams = new Vector4(cosOuterAngle,
Mathf.Approximately(angleRange, 0.0f) ? 1.0f : angleRange, quadAtten, rangeSq);
float smoothAngleRange = cosInneAngle - cosOuterAngle;
if (Mathf.Approximately(smoothAngleRange, 0.0f))
smoothAngleRange = 1.0f;
float invAngleRange = 1.0f / smoothAngleRange;
float add = -cosOuterAngle * invAngleRange;
lightAttenuationParams = new Vector4(invAngleRange, add, quadAtten, rangeSq);
lightAttenuationParams = new Vector4(-1.0f, 1.0f, quadAtten, rangeSq);
lightAttenuationParams = new Vector4(0.0f, 1.0f, quadAtten, rangeSq);
private void SetupShaderSingleLightConstants(VisibleLight[] lights, int lightIndex, ref ScriptableRenderContext context)
private void SetupPerFrameShaderConstants(ref ScriptableRenderContext context)
{
// When glossy reflections are OFF in the shader we set a constant color to use as indirect specular
SphericalHarmonicsL2 ambientSH = RenderSettings.ambientProbe;
Vector4 glossyEnvColor = new Vector4(ambientSH[0, 0], ambientSH[1, 0], ambientSH[2, 0]) * RenderSettings.reflectionIntensity;
CommandBuffer cmd = CommandBufferPool.Get("SetupPerFrameConstants");
cmd.SetGlobalVector(PerFrameBuffer._GlossyEnvironmentColor, glossyEnvColor);
if (m_Asset.AttenuationTexture != null) cmd.SetGlobalTexture(PerFrameBuffer._AttenuationTexture, m_Asset.AttenuationTexture);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release (cmd);
}
private void SetupShaderLightConstants(CommandBuffer cmd, VisibleLight[] lights, ref LightData lightData, ref CullResults cullResults, ref ScriptableRenderContext context)
{
// Main light has an optimized shader path for main light. This will benefit games that only care about a single light.
// Lightweight pipeline also supports only a single shadow light, if available it will be the main light.
SetupMainLightConstants(cmd, lights, lightData.mainLightIndex, ref context);
if (lightData.shadowsRendered)
SetupShadowShaderConstants(cmd, ref context, ref lights[lightData.mainLightIndex], m_ShadowCasterCascadesCount);
if (lightData.totalAdditionalLightsCount > 0)
SetupAdditionalListConstants(cmd, lights, ref lightData, ref context);
}
private void SetupMainLightConstants(CommandBuffer cmd, VisibleLight[] lights, int lightIndex, ref ScriptableRenderContext context)
CommandBuffer cmd = new CommandBuffer() { name = "SetupSingleLightConstants" };
cmd.SetGlobalVector("_LightPosition", lightPos);
cmd.SetGlobalColor("_LightColor", lightColor);
cmd.SetGlobalVector("_LightSpotDir", lightSpotDir);
cmd.SetGlobalVector("_LightAttenuationParams", lightAttenuationParams);
if (m_Asset.AttenuationTexture != null) cmd.SetGlobalTexture("_AttenuationTexture", m_Asset.AttenuationTexture);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
cmd.SetGlobalVector(PerCameraBuffer._MainLightPosition, lightPos);
cmd.SetGlobalColor(PerCameraBuffer._MainLightColor, lightColor);
cmd.SetGlobalVector(PerCameraBuffer._MainLightSpotDir, lightSpotDir);
cmd.SetGlobalVector(PerCameraBuffer._MainLightAttenuationParams, lightAttenuationParams);
private void SetupShaderLightListConstants(VisibleLight[] lights, ref LightData lightData, ref ScriptableRenderContext context)
private void SetupAdditionalListConstants(CommandBuffer cmd, VisibleLight[] lights, ref LightData lightData, ref ScriptableRenderContext context)
int maxLights = Math.Min(kMaxVisibleLights, lights.Length);
int additionalLightIndex = 0;
for (int i = 0; i < maxLights; ++i)
InitializeLightConstants(lights, i, out m_LightPositions[i], out m_LightColors[i], out m_LightSpotDirections[i], out m_LightAttenuations[i]);
// We need to update per-object light list with the proper map to our global additional light buffer
// First we initialize all lights in the map to -1 to tell the system to discard main light index and
// remaining lights in the scene that don't fit the max additional light buffer (kMaxVisibileAdditionalLights)
int[] perObjectLightIndexMap = m_CullResults.GetLightIndexMap();
for (int i = 0; i < lights.Length; ++i)
perObjectLightIndexMap[i] = -1;
// Lightweight pipeline only upload kMaxVisibleLights to shader cbuffer.
// We tell the pipe to disable remaining lights by setting it to -1.
int[] lightIndexMap = m_CullResults.GetLightIndexMap();
for (int i = kMaxVisibleLights; i < lightIndexMap.Length; ++i)
lightIndexMap[i] = -1;
m_CullResults.SetLightIndexMap(lightIndexMap);
for (int i = 0; i < lights.Length && additionalLightIndex < kMaxVisibleAdditionalLights; ++i)
{
if (i != lightData.mainLightIndex)
{
// The engine performs per-object light culling and initialize 8 light indices into two vec4 constants unity_4LightIndices0 and unity_4LightIndices1.
// In the shader we iterate over each visible light using the indices provided in these constants to index our global light buffer
// ex: first light position would be m_LightPosisitions[unity_4LightIndices[0]];
// However since we sorted the lights we need to tell the engine how to map the original/unsorted indices to our global buffer
// We do it by settings the perObjectLightIndexMap to the appropriate additionalLightIndex.
perObjectLightIndexMap[GetLightUnsortedIndex(i)] = additionalLightIndex;
InitializeLightConstants(lights, i, out m_LightPositions[additionalLightIndex],
out m_LightColors[additionalLightIndex],
out m_LightSpotDirections[additionalLightIndex],
out m_LightAttenuations[additionalLightIndex]);
additionalLightIndex++;
}
}
m_CullResults.SetLightIndexMap(perObjectLightIndexMap);
CommandBuffer cmd = CommandBufferPool.Get("SetupLightShaderConstants");
cmd.SetGlobalVector("globalLightCount", new Vector4 (lightData.pixelLightsCount, lightData.vertexLightsCount, 0.0f, 0.0f));
cmd.SetGlobalVectorArray ("globalLightPos", m_LightPositions);
cmd.SetGlobalVectorArray ("globalLightColor", m_LightColors);
cmd.SetGlobalVectorArray ("globalLightAtten", m_LightAttenuations);
cmd.SetGlobalVectorArray ("globalLightSpotDir", m_LightSpotDirections);
if (m_Asset.AttenuationTexture != null) cmd.SetGlobalTexture("_AttenuationTexture", m_Asset.AttenuationTexture);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
cmd.SetGlobalVector(PerCameraBuffer._AdditionalLightCount, new Vector4 (lightData.pixelAdditionalLightsCount,
lightData.totalAdditionalLightsCount, 0.0f, 0.0f));
cmd.SetGlobalVectorArray (PerCameraBuffer._AdditionalLightPosition, m_LightPositions);
cmd.SetGlobalVectorArray (PerCameraBuffer._AdditionalLightColor, m_LightColors);
cmd.SetGlobalVectorArray (PerCameraBuffer._AdditionalLightAttenuationParams, m_LightAttenuations);
cmd.SetGlobalVectorArray (PerCameraBuffer._AdditionalLightSpotDir, m_LightSpotDirections);
private void SetShaderKeywords(ref LightData lightData, ref ScriptableRenderContext context)
private void SetupShadowShaderConstants(CommandBuffer cmd, ref ScriptableRenderContext context, ref VisibleLight shadowLight, int cascadeCount)
CommandBuffer cmd = new CommandBuffer() { name = "SetShaderKeywords" };
SetShaderKeywords(cmd, lightData.shadowsRendered, lightData.isSingleLight, lightData.vertexLightsCount > 0);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
Vector3 shadowLightDir = Vector3.Normalize(shadowLight.localToWorld.GetColumn(2));
Light light = shadowLight.light;
float bias = light.shadowBias * 0.1f;
float normalBias = light.shadowNormalBias;
float shadowResolution = m_ShadowSlices[0].shadowResolution;
const int maxShadowCascades = 4;
Matrix4x4[] shadowMatrices = new Matrix4x4[maxShadowCascades];
for (int i = 0; i < cascadeCount; ++i)
shadowMatrices[i] = (cascadeCount >= i) ? m_ShadowSlices[i].shadowTransform : Matrix4x4.identity;
// TODO: shadow resolution per cascade in case cascades endup being supported.
float invShadowResolution = 1.0f / shadowResolution;
float[] pcfKernel =
{
-0.5f * invShadowResolution, 0.5f * invShadowResolution,
0.5f * invShadowResolution, 0.5f * invShadowResolution,
-0.5f * invShadowResolution, -0.5f * invShadowResolution,
0.5f * invShadowResolution, -0.5f * invShadowResolution
};
cmd.SetGlobalMatrixArray("_WorldToShadow", shadowMatrices);
cmd.SetGlobalVectorArray("_DirShadowSplitSpheres", m_DirectionalShadowSplitDistances);
cmd.SetGlobalVector("_ShadowLightDirection", new Vector4(-shadowLightDir.x, -shadowLightDir.y, -shadowLightDir.z, 0.0f));
cmd.SetGlobalVector("_ShadowData", new Vector4(0.0f, bias, normalBias, 0.0f));
cmd.SetGlobalFloatArray("_PCFKernel", pcfKernel);
}
private void SetShaderKeywords(CommandBuffer cmd, ref LightData lightData, VisibleLight[] visibleLights)
{
int vertexLightsCount = lightData.totalAdditionalLightsCount - lightData.pixelAdditionalLightsCount;
LightweightUtils.SetKeyword(cmd, "_VERTEX_LIGHTS", vertexLightsCount > 0);
int mainLightIndex = lightData.mainLightIndex;
LightweightUtils.SetKeyword (cmd, "_MAIN_DIRECTIONAL_LIGHT", mainLightIndex == -1 || visibleLights[mainLightIndex].lightType == LightType.Directional);
LightweightUtils.SetKeyword (cmd, "_MAIN_SPOT_LIGHT", mainLightIndex != -1 && visibleLights[mainLightIndex].lightType == LightType.Spot);
LightweightUtils.SetKeyword (cmd, "_MAIN_POINT_LIGHT", mainLightIndex != -1 && visibleLights[mainLightIndex].lightType == LightType.Point);
LightweightUtils.SetKeyword(cmd, "_ADDITIONAL_LIGHTS", lightData.totalAdditionalLightsCount > 0);
string[] shadowKeywords = new string[] { "_HARD_SHADOWS", "_SOFT_SHADOWS", "_HARD_SHADOWS_CASCADES", "_SOFT_SHADOWS_CASCADES" };
for (int i = 0; i < shadowKeywords.Length; ++i)
cmd.DisableShaderKeyword(shadowKeywords[i]);
if (m_Asset.AreShadowsEnabled() && lightData.shadowsRendered)
{
int keywordIndex = (int)m_Asset.ShadowSetting - 1;
if (m_Asset.CascadeCount > 1)
keywordIndex += 2;
cmd.EnableShaderKeyword(shadowKeywords[keywordIndex]);
}
LightweightUtils.SetKeyword(cmd, "SOFTPARTICLES_ON", m_Asset.SupportsSoftParticles);
}
private bool RenderShadows(ref CullResults cullResults, ref VisibleLight shadowLight, int shadowLightIndex, ref ScriptableRenderContext context)

var setRenderTargetCommandBuffer = CommandBufferPool.Get();
setRenderTargetCommandBuffer.name = "Render packed shadows";
setRenderTargetCommandBuffer.GetTemporaryRT(m_ShadowMapProperty, m_ShadowSettings.shadowAtlasWidth,
setRenderTargetCommandBuffer.GetTemporaryRT(m_ShadowMapTexture, m_ShadowSettings.shadowAtlasWidth,
setRenderTargetCommandBuffer.SetRenderTarget(m_ShadowMapRTID);
setRenderTargetCommandBuffer.SetRenderTarget(m_ShadowMapRT);
setRenderTargetCommandBuffer.ClearRenderTarget(true, true, Color.black);
context.ExecuteCommandBuffer(setRenderTargetCommandBuffer);
CommandBufferPool.Release(setRenderTargetCommandBuffer);

return resolution;
}
private void SetupShadowShaderConstants(ref ScriptableRenderContext context, ref VisibleLight shadowLight, int shadowLightIndex, int cascadeCount)
{
Vector3 shadowLightDir = Vector3.Normalize(shadowLight.localToWorld.GetColumn(2));
float bias = shadowLight.light.shadowBias * 0.1f;
float normalBias = shadowLight.light.shadowNormalBias;
float shadowResolution = m_ShadowSlices[0].shadowResolution;
const int maxShadowCascades = 4;
Matrix4x4[] shadowMatrices = new Matrix4x4[maxShadowCascades];
for (int i = 0; i < cascadeCount; ++i)
shadowMatrices[i] = (cascadeCount >= i) ? m_ShadowSlices[i].shadowTransform : Matrix4x4.identity;
// TODO: shadow resolution per cascade in case cascades endup being supported.
float invShadowResolution = 1.0f / shadowResolution;
float[] pcfKernel =
{
-0.5f * invShadowResolution, 0.5f * invShadowResolution,
0.5f * invShadowResolution, 0.5f * invShadowResolution,
-0.5f * invShadowResolution, -0.5f * invShadowResolution,
0.5f * invShadowResolution, -0.5f * invShadowResolution
};
var setupShadow = CommandBufferPool.Get("SetupShadowShaderConstants");
setupShadow.SetGlobalMatrixArray("_WorldToShadow", shadowMatrices);
setupShadow.SetGlobalVectorArray("_DirShadowSplitSpheres", m_DirectionalShadowSplitDistances);
setupShadow.SetGlobalVector("_ShadowLightDirection", new Vector4(-shadowLightDir.x, -shadowLightDir.y, -shadowLightDir.z, 0.0f));
setupShadow.SetGlobalVector("_ShadowData", new Vector4(shadowLightIndex, bias, normalBias, 0.0f));
setupShadow.SetGlobalFloatArray("_PCFKernel", pcfKernel);
context.ExecuteCommandBuffer(setupShadow);
CommandBufferPool.Release(setupShadow);
}
private void SetShaderKeywords(CommandBuffer cmd, bool renderShadows, bool singleLight, bool vertexLightSupport)
{
LightweightUtils.SetKeyword(cmd, "LIGHTWEIGHT_LINEAR", m_Asset.ForceLinearRendering);
LightweightUtils.SetKeyword(cmd, "_VERTEX_LIGHTS", vertexLightSupport);
LightweightUtils.SetKeyword(cmd, "_ATTENUATION_TEXTURE", m_Asset.AttenuationTexture != null);
LightweightUtils.SetKeyword(cmd, "_LIGHT_PROBES_ON", m_Asset.EnableAmbientProbe);
LightweightUtils.SetKeyword(cmd, "LIGHTWEIGHT_LINEAR", m_Asset.ForceLinearRendering);
if (!singleLight)
{
LightweightUtils.SetKeyword(cmd, "_SINGLE_DIRECTIONAL_LIGHT", false);
LightweightUtils.SetKeyword(cmd, "_SINGLE_SPOT_LIGHT", false);
LightweightUtils.SetKeyword(cmd, "_SINGLE_POINT_LIGHT", false);
}
else
{
switch (m_SingleLightType)
{
case LightType.Directional:
LightweightUtils.SetKeyword(cmd, "_SINGLE_DIRECTIONAL_LIGHT", true);
LightweightUtils.SetKeyword(cmd, "_SINGLE_SPOT_LIGHT", false);
LightweightUtils.SetKeyword(cmd, "_SINGLE_POINT_LIGHT", false);
break;
case LightType.Spot:
LightweightUtils.SetKeyword(cmd, "_SINGLE_DIRECTIONAL_LIGHT", false);
LightweightUtils.SetKeyword(cmd, "_SINGLE_SPOT_LIGHT", true);
LightweightUtils.SetKeyword(cmd, "_SINGLE_POINT_LIGHT", false);
break;
case LightType.Point:
LightweightUtils.SetKeyword(cmd, "_SINGLE_DIRECTIONAL_LIGHT", false);
LightweightUtils.SetKeyword(cmd, "_SINGLE_SPOT_LIGHT", false);
LightweightUtils.SetKeyword(cmd, "_SINGLE_POINT_LIGHT", true);
break;
}
}
string[] shadowKeywords = new string[] { "_HARD_SHADOWS", "_SOFT_SHADOWS", "_HARD_SHADOWS_CASCADES", "_SOFT_SHADOWS_CASCADES" };
for (int i = 0; i < shadowKeywords.Length; ++i)
cmd.DisableShaderKeyword(shadowKeywords[i]);
if (renderShadows && m_Asset.CurrShadowType != ShadowType.NO_SHADOW)
{
int keywordIndex = (int)m_Asset.CurrShadowType - 1;
if (m_Asset.CascadeCount > 1)
keywordIndex += 2;
cmd.EnableShaderKeyword(shadowKeywords[keywordIndex]);
}
}
private void InitializeMainShadowLightIndex(VisibleLight[] lights, out int shadowIndex)
private void BeginForwardRendering(ref ScriptableRenderContext context, FrameRenderingConfiguration renderingConfig)
shadowIndex = -1;
if (m_Asset.CurrShadowType == ShadowType.NO_SHADOW)
return;
RenderTargetIdentifier colorRT = BuiltinRenderTextureType.CameraTarget;
RenderTargetIdentifier depthRT = BuiltinRenderTextureType.None;
float maxIntensity = -1;
for (int i = 0; i < lights.Length; ++i)
{
Light light = lights[i].light;
if (light.shadows != LightShadows.None && IsSupportedShadowType(light.type) && light.intensity > maxIntensity)
{
shadowIndex = i;
maxIntensity = light.intensity;
}
}
}
private bool IsSupportedShadowType(LightType type)
{
return (type == LightType.Directional || type == LightType.Spot);
}
private void BeginForwardRendering(ref ScriptableRenderContext context, bool stereoEnabled)
{
if (stereoEnabled)
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.Stereo))
var cmd = CommandBufferPool.Get("SetCameraRenderTarget");
if (m_RenderToIntermediateTarget)
CommandBuffer cmd = CommandBufferPool.Get("SetCameraRenderTarget");
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.IntermediateTexture))
{
m_IntermediateTextureArray = false;
if (stereoEnabled)
{
RenderTextureDescriptor xrDesc = XRSettings.eyeTextureDesc;
xrDesc.depthBufferBits = kCameraDepthBufferBits;
xrDesc.colorFormat = m_ColorFormat;
xrDesc.msaaSamples = m_Asset.MSAASampleCount;
colorRT = m_CameraColorRT;
m_IntermediateTextureArray = (xrDesc.dimension == TextureDimension.Tex2DArray);
cmd.GetTemporaryRT(m_CameraRTProperty, xrDesc, FilterMode.Bilinear);
}
else
{
cmd.GetTemporaryRT(m_CameraRTProperty, Screen.width, Screen.height, kCameraDepthBufferBits,
FilterMode.Bilinear, m_ColorFormat, RenderTextureReadWrite.Default, m_Asset.MSAASampleCount);
}
if (m_IntermediateTextureArray)
cmd.SetRenderTarget(m_CameraRTID, 0, CubemapFace.Unknown, -1);
else
cmd.SetRenderTarget(m_CameraRTID);
}
else
{
cmd.SetRenderTarget(new RenderTargetIdentifier(m_CurrCamera.activeTexture));
}
}
else
{
cmd.SetRenderTarget(BuiltinRenderTextureType.CurrentActive);
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.RequireDepth))
depthRT = m_CameraDepthRT;
if (!stereoEnabled)
{
Rect viewport = m_CurrCamera.rect;
if (m_CurrCamera.targetTexture == null)
{
viewport.x *= Screen.width;
viewport.y *= Screen.height;
viewport.width *= Screen.width;
viewport.height *= Screen.height;
}
else
{
viewport = new Rect(0.0f, 0.0f, m_CurrCamera.targetTexture.width, m_CurrCamera.targetTexture.height);
}
cmd.SetViewport(viewport);
}
SetupRenderTargets(cmd, colorRT, depthRT);
// Clear RenderTarget to avoid tile initialization on mobile GPUs
// https://community.arm.com/graphics/b/blog/posts/mali-performance-2-how-to-correctly-handle-framebuffers

CommandBufferPool.Release(cmd);
}
private void EndForwardRendering(ref ScriptableRenderContext context, bool stereoEnabled, bool postProcessing)
private void EndForwardRendering(ref ScriptableRenderContext context, FrameRenderingConfiguration renderingConfig)
// No additional rendering needs to be done if this is an offscren rendering camera (unless camera is scene view)
if (m_CurrCamera.targetTexture != null && m_CurrCamera.cameraType != CameraType.SceneView)
return;
if (m_RenderToIntermediateTarget || postProcessing)
var cmd = CommandBufferPool.Get("Blit");
if (m_IntermediateTextureArray)
var cmd = CommandBufferPool.Get("Blit");
if (m_IntermediateTextureArray)
{
cmd.SetRenderTarget(BuiltinRenderTextureType.CameraTarget, 0, CubemapFace.Unknown, -1);
cmd.Blit(m_CameraRTID, BuiltinRenderTextureType.CurrentActive);
}
// If PostProcessing is enabled, it is already blitted to CameraTarget.
else if (!postProcessing)
cmd.Blit(BuiltinRenderTextureType.CurrentActive, BuiltinRenderTextureType.CameraTarget);
cmd.SetRenderTarget(BuiltinRenderTextureType.CameraTarget);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
cmd.SetRenderTarget(BuiltinRenderTextureType.CameraTarget, 0, CubemapFace.Unknown, -1);
cmd.Blit(m_CameraColorRT, BuiltinRenderTextureType.CurrentActive);
}
else if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.IntermediateTexture))
{
// If PostProcessing is enabled, it is already blit to CameraTarget.
if (!LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.PostProcess))
Blit(cmd, renderingConfig, BuiltinRenderTextureType.CurrentActive, BuiltinRenderTextureType.CameraTarget);
if (stereoEnabled)
SetupRenderTargets(cmd, BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.None);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.Stereo))
{
context.StopMultiEye(m_CurrCamera);
context.StereoEndRender(m_CurrCamera);

private void RenderPostProcess(ref ScriptableRenderContext renderContext, PostProcessLayer postProcessLayer)
RendererConfiguration GetRendererSettings(ref LightData lightData)
{
RendererConfiguration settings = RendererConfiguration.PerObjectReflectionProbes | RendererConfiguration.PerObjectLightmaps | RendererConfiguration.PerObjectLightProbe;
if (lightData.totalAdditionalLightsCount > 0)
settings |= RendererConfiguration.PerObjectLightIndices8;
return settings;
}
private void SetupRenderTargets(CommandBuffer cmd, RenderTargetIdentifier colorRT, RenderTargetIdentifier depthRT)
var postProcessCommand = CommandBufferPool.Get("Post Processing");
int depthSlice = (m_IntermediateTextureArray) ? -1 : 0;
if (depthRT != BuiltinRenderTextureType.None)
cmd.SetRenderTarget(colorRT, depthRT, 0, CubemapFace.Unknown, depthSlice);
else
cmd.SetRenderTarget(colorRT, 0, CubemapFace.Unknown, depthSlice);
}
private void RenderPostProcess(CommandBuffer cmd, bool opaqueOnly)
{
m_PostProcessRenderContext.command = postProcessCommand;
m_PostProcessRenderContext.command = cmd;
postProcessLayer.Render(m_PostProcessRenderContext);
renderContext.ExecuteCommandBuffer(postProcessCommand);
CommandBufferPool.Release(postProcessCommand);
if (opaqueOnly)
m_CameraPostProcessLayer.RenderOpaqueOnly(m_PostProcessRenderContext);
else
m_CameraPostProcessLayer.Render(m_PostProcessRenderContext);
private bool GetRenderToIntermediateTarget()
private int GetLightUnsortedIndex(int index)
{
Debug.Assert(index >= 0 && index < m_SortedLightIndexMap.Count, "Invalid index while accessing light index map. If you only have a single light in scene you should not try to map indices");
return m_SortedLightIndexMap[index];
}
private void Blit(CommandBuffer cmd, FrameRenderingConfiguration renderingConfig, RenderTargetIdentifier sourceRT, RenderTargetIdentifier destRT, Material material = null)
bool allowMSAA = m_CurrCamera.allowMSAA &&
m_Asset.MSAASampleCount > 1 &&
!LightweightUtils.PlatformSupportsMSAABackBuffer();
if (m_CurrCamera.cameraType == CameraType.SceneView || allowMSAA || m_CurrCamera.targetTexture != null)
return true;
if (LightweightUtils.HasFlag(renderingConfig, FrameRenderingConfiguration.DefaultViewport))
{
cmd.Blit(sourceRT, destRT, material);
}
else
{
if (m_BlitQuad == null)
m_BlitQuad = LightweightUtils.CreateQuadMesh(false);
return false;
cmd.SetGlobalTexture(m_BlitTexID, sourceRT);
cmd.SetRenderTarget(destRT);
cmd.SetViewport(m_CurrCamera.pixelRect);
cmd.DrawMesh(m_BlitQuad, Matrix4x4.identity, m_BlitMaterial);
}
private PostProcessLayer GetCurrCameraPostProcessLayer()
private void CopyTexture(CommandBuffer cmd, RenderTargetIdentifier sourceRT, RenderTargetIdentifier destRT)
return m_CurrCamera.GetComponent<PostProcessLayer>();
if (m_CopyTextureSupport != CopyTextureSupport.None)
cmd.CopyTexture(m_CameraDepthRT, m_CameraCopyDepthRT);
else
cmd.Blit(m_CameraDepthRT, m_CameraCopyDepthRT, m_CopyDepthMaterial);
}
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset


m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3}
m_Name: LightweightPipelineAsset
m_EditorClassIdentifier:
m_MaxPixelLights: 4
m_SupportsVertexLight: 1
m_EnableLightmaps: 1
m_EnableAmbientProbe: 1
m_MaxAdditionalPixelLights: 4
m_SupportsVertexLight: 0
m_SupportSoftParticles: 1
m_RenderScale: 1
m_ShadowType: 1
m_ShadowAtlasResolution: 1024
m_ShadowNearPlaneOffset: 2

m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467}
m_LinearRendering: 1
m_DefaultDiffuseMaterial: {fileID: 2100000, guid: 6a1143ee683302f4aa628c052723efc1,
m_DefaultDiffuseMaterial: {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d,
type: 2}
m_DefaultParticleMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d,
type: 2}

type: 2}
m_DefaultUIMaterial: {fileID: 2100000, guid: 786cc499ea3906946b10ab7d24c8d0e7, type: 2}
m_DefaultShader: {fileID: 4800000, guid: 8d2bb70cbf9db8d4da26e15b26e74248, type: 3}
m_DefaultShader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}

98
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.cs


public class LightweightPipelineAsset : RenderPipelineAsset
{
private static readonly string m_PipelineFolder = "Assets/ScriptableRenderPipeline/LightweightPipeline";
public static readonly string m_SimpleLightShaderPath = "LightweightPipeline/Standard (Simple Lighting)";
public static readonly string m_StandardShaderPath = "LightweightPipeline/Standard (Physically Based)";
public static readonly string m_BlitShaderPath = "Hidden/LightweightPipeline/Blit";
public static readonly string m_CopyDephPath = "Hidden/LightweightPipeline/CopyDepth";
private static readonly string m_PipelineFolder = "Assets/LightweightPipeline";
[SerializeField] private int m_MaxAdditionalPixelLights = 1;
[SerializeField] private bool m_SupportsVertexLight = true;
[SerializeField] private bool m_SupportSoftParticles = false;
[SerializeField] private MSAAQuality m_MSAA = MSAAQuality.Disabled;
[SerializeField] private float m_RenderScale = 1.0f;
[SerializeField] private ShadowType m_ShadowType = ShadowType.HARD_SHADOWS;
[SerializeField] private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._1024;
[SerializeField] private float m_ShadowNearPlaneOffset = 2.0f;
[SerializeField] private float m_ShadowDistance = 50.0f;
[SerializeField] private ShadowCascades m_ShadowCascades = ShadowCascades.NO_CASCADES;
[SerializeField] private float m_Cascade2Split = 0.25f;
[SerializeField] private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f);
[SerializeField] private Texture2D m_AttenuationTexture;
[SerializeField] private Material m_DefaultDiffuseMaterial;
[SerializeField] private Material m_DefaultParticleMaterial;
[SerializeField] private Material m_DefaultLineMaterial;
[SerializeField] private Material m_DefaultSpriteMaterial;
[SerializeField] private Material m_DefaultUIMaterial;
[SerializeField] private Shader m_DefaultShader;
[UnityEditor.MenuItem("RenderPipeline/LightweightPipeline/Create Pipeline Asset", false, 15)]
[UnityEditor.MenuItem("RenderPipeline/Lightweight Pipeline/Create Pipeline Asset", false, 15)]
static void CreateLightweightPipeline()
{
var instance = ScriptableObject.CreateInstance<LightweightPipelineAsset>();

DestroyCreatedInstances();
}
#region PipelineAssetSettings
[SerializeField] private int m_MaxPixelLights = 1;
[SerializeField] private bool m_SupportsVertexLight = true;
[SerializeField] private bool m_EnableLightmaps = true;
[SerializeField] private bool m_EnableAmbientProbe = true;
[SerializeField] private MSAAQuality m_MSAA = MSAAQuality.Disabled;
[SerializeField] private ShadowType m_ShadowType = ShadowType.HARD_SHADOWS;
[SerializeField] private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._1024;
[SerializeField] private float m_ShadowNearPlaneOffset = 2.0f;
[SerializeField] private float m_ShadowDistance = 50.0f;
[SerializeField] private ShadowCascades m_ShadowCascades = ShadowCascades.NO_CASCADES;
[SerializeField] private float m_Cascade2Split = 0.25f;
[SerializeField] private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f);
[SerializeField] private bool m_LinearRendering = true;
[SerializeField] private Texture2D m_AttenuationTexture;
[SerializeField] private Material m_DefaultDiffuseMaterial;
[SerializeField] private Material m_DefaultParticleMaterial;
[SerializeField] private Material m_DefaultLineMaterial;
[SerializeField] private Material m_DefaultSpriteMaterial;
[SerializeField] private Material m_DefaultUIMaterial;
[SerializeField] private Shader m_DefaultShader;
public bool AreShadowsEnabled()
{
return ShadowSetting != ShadowType.NO_SHADOW;
}
public int MaxSupportedPixelLights
public int MaxAdditionalPixelLights
get { return m_MaxPixelLights; }
private set { m_MaxPixelLights = value; }
get { return m_MaxAdditionalPixelLights; }
private set { m_SupportsVertexLight = value; }
public bool EnableLightmap
public bool SupportsSoftParticles
get { return m_EnableLightmaps; }
private set { m_EnableLightmaps = value; }
get { return m_SupportSoftParticles; }
public bool EnableAmbientProbe
public int MSAASampleCount
get { return m_EnableAmbientProbe; }
private set { m_EnableAmbientProbe = value; }
get { return (int)m_MSAA; }
set { m_MSAA = (MSAAQuality)value; }
public int MSAASampleCount
public float RenderScale
get { return (int)m_MSAA; }
set { m_MSAA = (MSAAQuality)value; }
get { return m_RenderScale; }
set { m_RenderScale = value; }
public ShadowType CurrShadowType
public ShadowType ShadowSetting
{
get { return m_ShadowType; }
private set { m_ShadowType = value; }

private set { m_Cascade4Split = value; }
}
public bool ForceLinearRendering
{
get { return m_LinearRendering; }
set { m_LinearRendering = value; }
}
public Texture2D AttenuationTexture
{
get { return m_AttenuationTexture; }

#endregion
public override Material GetDefaultMaterial()
{
return m_DefaultDiffuseMaterial;

public override Shader GetDefaultShader()
{
return m_DefaultShader;
}
public Shader BlitShader
{
get { return Shader.Find(LightweightPipelineAsset.m_BlitShaderPath); }
}
public Shader CopyDepthShader
{
get { return Shader.Find(LightweightPipelineAsset.m_CopyDephPath); }
}
}
}

106
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineUtils.cs


using System.Collections.Generic;
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline

}
}
public class LightComparer : IComparer<VisibleLight>
{
public Camera CurrCamera { get; set; }
// Sorts on the following priority:
// Directionals have priority over local lights
// ShadowLight type
// Has Cookie
// Intensity if Directional, Distance to camera otherwise
public int Compare(VisibleLight lhs, VisibleLight rhs)
{
Light lhsLight = lhs.light;
Light rhsLight = rhs.light;
if (lhs.lightType != rhs.lightType)
{
if (lhs.lightType == LightType.Directional) return -1;
if (rhs.lightType == LightType.Directional) return 1;
}
// Particle Lights have the Light reference set to null
// They are at the end of the priority
if (lhsLight == null) return 1;
if (rhsLight == null) return -1;
// In the following priority: Soft, Hard, None
if (lhsLight.shadows != rhsLight.shadows)
return (int)rhsLight.shadows - (int)lhsLight.shadows;
if (lhsLight.cookie != rhsLight.cookie)
return (lhsLight.cookie != null) ? -1 : 1;
if (lhs.lightType == LightType.Directional)
return (int)(lhsLight.intensity*100.0f) - (int)(rhsLight.intensity*100.0f);
else
return (int)(SquaredDistanceToCamera(lhsLight.transform.position) - SquaredDistanceToCamera(rhsLight.transform.position));
}
public float SquaredDistanceToCamera(Vector3 lightPos)
{
Vector3 lightCameraVector = lightPos - CurrCamera.transform.position;
return Vector3.Dot(lightCameraVector, lightCameraVector);
}
}
[Flags]
public enum FrameRenderingConfiguration
{
None = 0,
Stereo = (1 << 0),
Msaa = (1 << 1),
PostProcess = (1 << 2),
RequireDepth = (1 << 3),
DefaultViewport = (1 << 4),
IntermediateTexture = (1 << 5),
}
public static class LightweightUtils
{
public static void SetKeyword(CommandBuffer cmd, string keyword, bool enable)

cmd.DisableShaderKeyword(keyword);
}
public static bool IsSupportedShadowType(LightType lightType)
{
return lightType == LightType.Directional || lightType == LightType.Spot;
}
public static bool PlatformSupportsMSAABackBuffer()
{
#if UNITY_ANDROID || UNITY_IPHONE || UNITY_TVOS || UNITY_SAMSUNGTV

#endif
}
public static bool HasFlag(FrameRenderingConfiguration mask, FrameRenderingConfiguration flag)
{
return (mask & flag) != 0;
}
public static Mesh CreateQuadMesh(bool uvStartsAtTop)
{
float topV, bottomV;
if (uvStartsAtTop)
{
topV = 0.0f;
bottomV = 1.0f;
}
else
{
topV = 1.0f;
bottomV = 0.0f;
}
Mesh mesh = new Mesh();
mesh.vertices = new Vector3[]
{
new Vector3(-1.0f, -1.0f, 0.0f),
new Vector3(-1.0f, 1.0f, 0.0f),
new Vector3( 1.0f, -1.0f, 0.0f),
new Vector3( 1.0f, 1.0f, 0.0f)
};
mesh.uv = new Vector2[]
{
new Vector2(0.0f, bottomV),
new Vector2(0.0f, topV),
new Vector2(1.0f, bottomV),
new Vector2(1.0f, topV)
};
mesh.triangles = new int[] { 0, 1, 2, 2, 1, 3 };
return mesh;
}
}
}

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Materials/Lightweight-DefaultParticle.mat


m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Lightweight-DefaultParticle
m_Shader: {fileID: 207, guid: 0000000000000000f000000000000000, type: 0}
m_Shader: {fileID: 202, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0

m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Texture: {fileID: 10300, guid: 0000000000000000f000000000000000, type: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:

2
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Materials/Lightweight-StandardShader.mat


m_PrefabInternal: {fileID: 0}
m_Name: Lightweight-StandardShader
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_ShaderKeywords: _GLOSSYREFLECTIONS_ON _METALLIC_SETUP _SPECULARHIGHLIGHTS_ON
m_ShaderKeywords: _METALLIC_SETUP
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0

4
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Materials/Lightweight-StandardSimpleLighting.mat


m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Lightweight-Default
m_Name: Lightweight-StandardSimpleLighting
m_ShaderKeywords: _SPECULAR_COLOR
m_ShaderKeywords: _GLOSSINESS_FROM_BASE_ALPHA _SPECULAR_COLOR
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0

67
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightUnlit.shader


Shader "ScriptableRenderPipeline/LightweightPipeline/Unlit"
Shader "LightweightPipeline/Unlit"
_Color("Color", Color) = (1, 1, 1, 1)
_MainColor("MainColor", Color) = (1, 1, 1, 1)
_Cutoff("AlphaCutout", Range(0.0, 1.0)) = 0.5
// BlendMode

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "CGIncludes/LightweightUnlit.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex;
float4 _MainTex_ST;
half4 _MainColor;
half _Cutoff;
v2f vert(appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
#pragma vertex LightweightVertexUnlit
#pragma fragment LightweightFragmentUnlit
fixed4 frag(v2f i) : SV_Target
{
fixed4 texColor = tex2D(_MainTex, i.uv);
fixed alpha = texColor.a * _MainColor.a;
fixed3 color = texColor.rgb * _MainColor.rgb;
void DefineSurface(LightweightVertexOutputUnlit i, inout SurfaceUnlit s)
{
// Albedo
float4 c = tex2D(_MainTex, i.meshUV0);
s.Color = c.rgb * _Color.rgb;
// Alpha
s.Alpha = c.a * _Color.a;
clip(s.Alpha - _Cutoff);
clip(alpha - _Cutoff);
}
UNITY_APPLY_FOG(i.fogCoord, color);
#ifdef _ALPHABLEND_ON
return fixed4(color, alpha);
#else
return fixed4(color, 1.0);
#endif
}
ENDCG
}
}

84
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Templates/lightweightSubshaderPBR.template


CGPROGRAM
#pragma target 3.0
#pragma multi_compile _ _SINGLE_DIRECTIONAL_LIGHT _SINGLE_SPOT_LIGHT _SINGLE_POINT_LIGHT
#pragma multi_compile _ LIGHTWEIGHT_LINEAR
#pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ _LIGHT_PROBES_ON
#pragma multi_compile _ _HARD_SHADOWS _SOFT_SHADOWS _HARD_SHADOWS_CASCADES _SOFT_SHADOWS_CASCADES
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile_fog
#pragma multi_compile_instancing
#pragma multi_compile _MAIN_DIRECTIONAL_LIGHT _MAIN_SPOT_LIGHT _MAIN_POINT_LIGHT
#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ _HARD_SHADOWS _SOFT_SHADOWS _HARD_SHADOWS_CASCADES _SOFT_SHADOWS_CASCADES
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile_fog
#pragma multi_compile_instancing
#include "UnityCG.cginc"
#include "CGIncludes/LightweightPBR.cginc"
#include "LightweightLighting.cginc"
struct GraphVertexOutput
{

Emission = Emission * Emission;
#endif
return FragmentLightingPBR(
return LightweightFragmentPBR(
IN.lwCustom,
worldSpacePosition,
worldSpaceNormal,

IN.fogCoord,
IN.fogCoord.x,
Albedo,
Metallic,

}
Pass
{
Tags{"Lightmode" = "ShadowCaster"}
ZWrite On ZTest LEqual
{
Tags{"Lightmode" = "ShadowCaster"}
ZWrite On ZTest LEqual
CGPROGRAM
#pragma target 2.0
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
#include "UnityCG.cginc"
#include "LightweightPassShadow.cginc"
ENDCG
}
Pass
{
Tags{"Lightmode" = "DepthOnly"}
ZWrite On
CGPROGRAM
#pragma target 2.0
#pragma vertex vert
#pragma fragment frag
CGPROGRAM
#pragma target 2.0
#include "UnityCG.cginc"
#include "CGIncludes/LightweightPass.cginc"
#pragma vertex shadowVert
#pragma fragment shadowFrag
ENDCG
}
#include "UnityCG.cginc"
Pass
{
Tags{"Lightmode" = "DepthOnly"}
ZWrite On
float4 vert(float4 pos : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(pos);
}
CGPROGRAM
#pragma target 2.0
#include "UnityCG.cginc"
#include "CGIncludes/LightweightPass.cginc"
#pragma vertex depthVert
#pragma fragment depthFrag
ENDCG
}
half4 frag() : SV_TARGET
{
return 0;
}
ENDCG
}
}

6
MaterialGraphProject/Packages/manifest.json


{
"registry": "https://staging-packages.unity.com",
"dependencies": {
"com.unity.postprocessing": "0.1.0"
}
"dependencies": {
}
}

8
MaterialGraphProject/Assets/SRP/PostProcessing.meta


fileFormatVersion: 2
guid: 38d8e45b559f16145a6d92d0fff86c50
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

249
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/CoreUtils.cs


using System;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
namespace UnityEngine.Experimental.Rendering
{
using UnityObject = UnityEngine.Object;
[Flags]
public enum ClearFlag
{
None = 0,
Color = 1,
Depth = 2,
All = Depth | Color
}
public static class CoreUtils
{
// Render Target Management.
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier buffer, ClearFlag clearFlag, Color clearColor, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
{
cmd.SetRenderTarget(buffer, miplevel, cubemapFace);
if (clearFlag != ClearFlag.None)
cmd.ClearRenderTarget((clearFlag & ClearFlag.Depth) != 0, (clearFlag & ClearFlag.Color) != 0, clearColor);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier buffer, ClearFlag clearFlag = ClearFlag.None, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
{
SetRenderTarget(cmd, buffer, clearFlag, Color.black, miplevel, cubemapFace);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
{
SetRenderTarget(cmd, colorBuffer, depthBuffer, ClearFlag.None, Color.black, miplevel, cubemapFace);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
{
SetRenderTarget(cmd, colorBuffer, depthBuffer, clearFlag, Color.black, miplevel, cubemapFace);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
{
cmd.SetRenderTarget(colorBuffer, depthBuffer, miplevel, cubemapFace);
if (clearFlag != ClearFlag.None)
cmd.ClearRenderTarget((clearFlag & ClearFlag.Depth) != 0, (clearFlag & ClearFlag.Color) != 0, clearColor);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer)
{
SetRenderTarget(cmd, colorBuffers, depthBuffer, ClearFlag.None, Color.black);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag = ClearFlag.None)
{
SetRenderTarget(cmd, colorBuffers, depthBuffer, clearFlag, Color.black);
}
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor)
{
cmd.SetRenderTarget(colorBuffers, depthBuffer);
if (clearFlag != ClearFlag.None)
cmd.ClearRenderTarget((clearFlag & ClearFlag.Depth) != 0, (clearFlag & ClearFlag.Color) != 0, clearColor);
}
public static void ClearCubemap(CommandBuffer cmd, RenderTargetIdentifier buffer, Color clearColor)
{
for(int i = 0; i < 6; ++i)
SetRenderTarget(cmd, buffer, ClearFlag.Color, Color.black, 0, (CubemapFace)i);
}
// Draws a full screen triangle as a faster alternative to drawing a full screen quad.
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
MaterialPropertyBlock properties = null, int shaderPassId = 0)
{
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
}
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
RenderTargetIdentifier colorBuffer,
MaterialPropertyBlock properties = null, int shaderPassId = 0)
{
commandBuffer.SetRenderTarget(colorBuffer);
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
}
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthStencilBuffer,
MaterialPropertyBlock properties = null, int shaderPassId = 0)
{
commandBuffer.SetRenderTarget(colorBuffer, depthStencilBuffer);
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
}
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthStencilBuffer,
MaterialPropertyBlock properties = null, int shaderPassId = 0)
{
commandBuffer.SetRenderTarget(colorBuffers, depthStencilBuffer);
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
}
// Important: the first RenderTarget must be created with 0 depth bits!
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
RenderTargetIdentifier[] colorBuffers,
MaterialPropertyBlock properties = null, int shaderPassId = 0)
{
// It is currently not possible to have MRT without also setting a depth target.
// To work around this deficiency of the CommandBuffer.SetRenderTarget() API,
// we pass the first color target as the depth target. If it has 0 depth bits,
// no depth target ends up being bound.
DrawFullScreen(commandBuffer, material, colorBuffers, colorBuffers[0], properties, shaderPassId);
}
// Post-processing misc
public static bool IsPostProcessingActive(PostProcessLayer layer)
{
return layer != null
&& layer.enabled;
}
public static bool IsTemporalAntialiasingActive(PostProcessLayer layer)
{
return IsPostProcessingActive(layer)
&& layer.antialiasingMode == PostProcessLayer.Antialiasing.TemporalAntialiasing
&& layer.temporalAntialiasing.IsSupported();
}
// Unity specifics
public static Material CreateEngineMaterial(string shaderPath)
{
var mat = new Material(Shader.Find(shaderPath))
{
hideFlags = HideFlags.HideAndDontSave
};
return mat;
}
public static Material CreateEngineMaterial(Shader shader)
{
var mat = new Material(shader)
{
hideFlags = HideFlags.HideAndDontSave
};
return mat;
}
public static void SetKeyword(Material m, string keyword, bool state)
{
if (state)
m.EnableKeyword(keyword);
else
m.DisableKeyword(keyword);
}
public static void SelectKeyword(Material material, string keyword1, string keyword2, bool enableFirst)
{
material.EnableKeyword(enableFirst ? keyword1 : keyword2);
material.DisableKeyword(enableFirst ? keyword2 : keyword1);
}
public static void SelectKeyword(Material material, string[] keywords, int enabledKeywordIndex)
{
material.EnableKeyword(keywords[enabledKeywordIndex]);
for (int i = 0; i < keywords.Length; i++)
{
if (i != enabledKeywordIndex)
material.DisableKeyword(keywords[i]);
}
}
public static void Destroy(UnityObject obj)
{
if (obj != null)
{
#if UNITY_EDITOR
if (Application.isPlaying)
UnityObject.Destroy(obj);
else
UnityObject.DestroyImmediate(obj);
#else
UnityObject.Destroy(obj);
#endif
}
}
public static void Destroy(params UnityObject[] objs)
{
if (objs == null)
return;
foreach (var o in objs)
Destroy(o);
}
public static void SafeRelease(ComputeBuffer buffer)
{
if (buffer != null)
buffer.Release();
}
// Just a sort function that doesn't allocate memory
// Note: Shoud be repalc by a radix sort for positive integer
public static int Partition(uint[] numbers, int left, int right)
{
uint pivot = numbers[left];
while (true)
{
while (numbers[left] < pivot)
left++;
while (numbers[right] > pivot)
right--;
if (left < right)
{
uint temp = numbers[right];
numbers[right] = numbers[left];
numbers[left] = temp;
}
else
{
return right;
}
}
}
public static void QuickSort(uint[] arr, int left, int right)
{
// For Recusrion
if (left < right)
{
int pivot = Partition(arr, left, right);
if (pivot > 1)
QuickSort(arr, left, pivot - 1);
if (pivot + 1 < right)
QuickSort(arr, pivot + 1, right);
}
}
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/CoreUtils.cs.meta


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

121
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/CoreEditorUtils.cs


using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using UnityEngine;
namespace UnityEditor.Experimental.Rendering
{
public static class CoreEditorUtils
{
// Serialization helpers
public static string FindProperty<T, TValue>(Expression<Func<T, TValue>> expr)
{
// Get the field path as a string
MemberExpression me;
switch (expr.Body.NodeType)
{
case ExpressionType.MemberAccess:
me = expr.Body as MemberExpression;
break;
default:
throw new InvalidOperationException();
}
var members = new List<string>();
while (me != null)
{
members.Add(me.Member.Name);
me = me.Expression as MemberExpression;
}
var sb = new StringBuilder();
for (int i = members.Count - 1; i >= 0; i--)
{
sb.Append(members[i]);
if (i > 0) sb.Append('.');
}
return sb.ToString();
}
// UI Helpers
public static void DrawSplitter()
{
var rect = GUILayoutUtility.GetRect(1f, 1f);
// Splitter rect should be full-width
rect.xMin = 0f;
rect.width += 4f;
if (Event.current.type != EventType.Repaint)
return;
EditorGUI.DrawRect(rect, !EditorGUIUtility.isProSkin
? new Color(0.6f, 0.6f, 0.6f, 1.333f)
: new Color(0.12f, 0.12f, 0.12f, 1.333f));
}
public static void DrawHeader(string title)
{
var backgroundRect = GUILayoutUtility.GetRect(1f, 17f);
var labelRect = backgroundRect;
labelRect.xMin += 16f;
labelRect.xMax -= 20f;
var foldoutRect = backgroundRect;
foldoutRect.y += 1f;
foldoutRect.width = 13f;
foldoutRect.height = 13f;
// Background rect should be full-width
backgroundRect.xMin = 0f;
backgroundRect.width += 4f;
// Background
float backgroundTint = EditorGUIUtility.isProSkin ? 0.1f : 1f;
EditorGUI.DrawRect(backgroundRect, new Color(backgroundTint, backgroundTint, backgroundTint, 0.2f));
// Title
EditorGUI.LabelField(labelRect, title, EditorStyles.boldLabel);
}
public static bool DrawHeaderFoldout(string title, bool state)
{
var backgroundRect = GUILayoutUtility.GetRect(1f, 17f);
var labelRect = backgroundRect;
labelRect.xMin += 16f;
labelRect.xMax -= 20f;
var foldoutRect = backgroundRect;
foldoutRect.y += 1f;
foldoutRect.width = 13f;
foldoutRect.height = 13f;
// Background rect should be full-width
backgroundRect.xMin = 0f;
backgroundRect.width += 4f;
// Background
float backgroundTint = EditorGUIUtility.isProSkin ? 0.1f : 1f;
EditorGUI.DrawRect(backgroundRect, new Color(backgroundTint, backgroundTint, backgroundTint, 0.2f));
// Title
EditorGUI.LabelField(labelRect, title, EditorStyles.boldLabel);
// Active checkbox
state = GUI.Toggle(foldoutRect, state, GUIContent.none, EditorStyles.foldout);
var e = Event.current;
if (e.type == EventType.MouseDown && backgroundRect.Contains(e.mousePosition) && e.button == 0)
{
state = !state;
e.Use();
}
return state;
}
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/CoreEditorUtils.cs.meta


fileFormatVersion: 2
guid: 744ceabda269e6c469964dda8c490d0d
timeCreated: 1507109827
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

60
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/PropertyFetcher.cs


using System;
using System.Linq.Expressions;
using UnityEngine.Assertions;
namespace UnityEditor.Experimental.Rendering
{
public sealed class PropertyFetcher<T> : IDisposable
{
public readonly SerializedObject obj;
public PropertyFetcher(SerializedObject obj)
{
Assert.IsNotNull(obj);
this.obj = obj;
}
public SerializedProperty Find(string str)
{
return obj.FindProperty(str);
}
public SerializedProperty Find<TValue>(Expression<Func<T, TValue>> expr)
{
string path = CoreEditorUtils.FindProperty(expr);
return obj.FindProperty(path);
}
public void Dispose()
{
// Nothing to do here, still needed so we can rely on the using/IDisposable pattern
}
}
public sealed class RelativePropertyFetcher<T> : IDisposable
{
public readonly SerializedProperty obj;
public RelativePropertyFetcher(SerializedProperty obj)
{
Assert.IsNotNull(obj);
this.obj = obj;
}
public SerializedProperty Find(string str)
{
return obj.FindPropertyRelative(str);
}
public SerializedProperty Find<TValue>(Expression<Func<T, TValue>> expr)
{
string path = CoreEditorUtils.FindProperty(expr);
return obj.FindPropertyRelative(path);
}
public void Dispose()
{
// Nothing to do here, still needed so we can rely on the using/IDisposable pattern
}
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Editor/PropertyFetcher.cs.meta


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

10
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Inputs.meta


fileFormatVersion: 2
guid: edb108228f2caa44ca8154fd4985e101
folderAsset: yes
timeCreated: 1504859102
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

60
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ProfilingSample.cs


using System;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering
{
public struct ProfilingSample : IDisposable
{
public readonly CommandBuffer cmd;
public readonly string name;
bool m_Disposed;
public ProfilingSample(CommandBuffer cmd, string name)
{
this.cmd = cmd;
this.name = name;
m_Disposed = false;
cmd.BeginSample(name);
}
// Shortcut to string.Format() using only one argument (reduces Gen0 GC pressure)
public ProfilingSample(CommandBuffer cmd, string format, object arg)
{
this.cmd = cmd;
name = string.Format(format, arg);
m_Disposed = false;
cmd.BeginSample(name);
}
// Shortcut to string.Format() with variable amount of arguments - for performance critical
// code you should pre-build & cache the marker name instead of using this
public ProfilingSample(CommandBuffer cmd, string format, params object[] args)
{
this.cmd = cmd;
name = string.Format(format, args);
m_Disposed = false;
cmd.BeginSample(name);
}
public void Dispose()
{
Dispose(true);
}
// Protected implementation of Dispose pattern.
void Dispose(bool disposing)
{
if (m_Disposed)
return;
// As this is a struct, it could have been initialized using an empty constructor so we
// need to make sure `cmd` isn't null to avoid a crash. Switching to a class would fix
// this but will generate garbage on every frame (and this struct is used quite a lot).
if (disposing && cmd != null)
cmd.EndSample(name);
m_Disposed = true;
}
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/ProfilingSample.cs.meta


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

10
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/Editor.meta


fileFormatVersion: 2
guid: f00a25194233f5c4392fa05f23ecc076
folderAsset: yes
timeCreated: 1507130547
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

23
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.compute


// Autogenerated file. Do not edit by hand
#include "../ShaderLibrary/Common.hlsl"
SamplerState sampler_LinearClamp;
CBUFFER_START(cb)
float4 _Size;
CBUFFER_END
RWTexture2D<float1> _Result1;
Texture2D<float4> _Source4;
#pragma kernel KSampleCopy4_1_x
[numthreads(8, 8, 1)]
void KSampleCopy4_1_x(uint2 dispatchThreadId : SV_DispatchThreadID)
{
_Result1[dispatchThreadId] = _Source4.SampleLevel(sampler_LinearClamp, float2(dispatchThreadId) * _Size.zw, 0.0).x;
}

10
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.compute.meta


fileFormatVersion: 2
guid: a68d8aaeb0956234d94e389f196381ee
timeCreated: 1507123133
licenseType: Pro
ComputeShaderImporter:
externalObjects: {}
currentAPIMask: 4
userData:
assetBundleName:
assetBundleVariant:

33
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.cs


// Autogenerated file. Do not edit by hand
using System;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering
{
public class GPUCopy
{
ComputeShader m_Shader;
int k_SampleKernel_xyzw2x;
public GPUCopy(ComputeShader shader)
{
m_Shader = shader;
k_SampleKernel_xyzw2x = m_Shader.FindKernel("KSampleCopy4_1_x");
}
static readonly int _Result1 = Shader.PropertyToID("_Result1");
static readonly int _Source4 = Shader.PropertyToID("_Source4");
static readonly int _Size = Shader.PropertyToID("_Size");
public void SampleCopyChannel_xyzw2x(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier target, Vector2 size)
{
if (size.x < 8 || size.y < 8)
Debug.LogWarning("Trying to copy a channel from a texture smaller than 8x* or *x8. ComputeShader cannot perform it.");
var s = new Vector4(size.x, size.y, 1f / size.x, 1f / size.y);
cmd.SetComputeVectorParam(m_Shader, _Size, s);
cmd.SetComputeTextureParam(m_Shader, k_SampleKernel_xyzw2x, _Source4, source);
cmd.SetComputeTextureParam(m_Shader, k_SampleKernel_xyzw2x, _Result1, target);
cmd.DispatchCompute(m_Shader, k_SampleKernel_xyzw2x, (int)(size.x) / 8, (int)(size.y) / 8, 1);
}
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopy.cs.meta


fileFormatVersion: 2
guid: 584fa1be28adb3344ab9eec18571f46b
timeCreated: 1507123133
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

164
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyAsset.cs


using System;
using System.Collections.Generic;
using System.Text;
namespace UnityEngine.Experimental.Rendering
{
/// <summary>
/// Declares what should be generated in utility code.
/// It will generate a compute shader and a C# class to use the compute shader with a ComputeBuffer
///
/// Exemple:
/// - I add a CopyOperation { sourceChannel = 4, targetChannel = 2, subscript = "zx" }
/// => a Kernel will be generated to copy from a TextureRGBA the AR channels into a TextureRG
/// => A method will be added to call the kernel in the C# class GPUCopy (SampleCopy_xyzw2zx)
///
/// C# Exemple:
/// // Initialize the gpucopy
/// var gpuCopy = new CPUCopy(generatedComputeShaderAsset);
///
/// CommandBuffer cmb = ...
/// gpuCopy.SampleCopyChannel_xyzw2x(cmb, _SourceTexture, _TargetTexture, new Vector2(targetWidth, targetHeight));
///
/// Initialization:
/// - You must set the generated ComputeShader as argument of the constructor of the generated GPUCopy C# class
/// </summary>
public class GPUCopyAsset : ScriptableObject
{
static string[] k_ChannelIDS = { "x", "xy", "xyz", "xyzw" };
const int k_KernelSize = 8;
[Serializable]
public struct CopyOperation
{
public string subscript;
public int sourceChannel;
public int targetChannel;
}
[SerializeField]
CopyOperation[] m_CopyOperation = new CopyOperation[0];
public void Generate(out string computeShader, out string csharp)
{
var operations = m_CopyOperation;
var sources = new HashSet<int>();
var targets = new HashSet<int>();
var cc = new StringBuilder(); // Compute Shader out
var ccp = new StringBuilder(); // Compute properties
var cck = new StringBuilder(); // Compute kernel
var cs = new StringBuilder(); // CSharp out
var csm = new StringBuilder(); // CSharp methods
var csc = new StringBuilder(); // CSharp constructor
var csp = new StringBuilder(); // CSharp properties
for (var i = 0; i < operations.Length; i++)
{
var o = operations[i];
sources.Add(o.sourceChannel);
targets.Add(o.targetChannel);
}
ccp.AppendLine();
foreach (var target in targets)
{
ccp.AppendLine(string.Format("RWTexture2D<float{0}> _Result{0};", target.ToString()));
csm.AppendLine(string.Format(" static readonly int _Result{0} = Shader.PropertyToID(\"_Result{0}\");", target.ToString()));
}
ccp.AppendLine();
foreach (var source in sources)
{
ccp.AppendLine(string.Format("Texture2D<float{0}> _Source{0};", source.ToString()));
csm.AppendLine(string.Format(" static readonly int _Source{0} = Shader.PropertyToID(\"_Source{0}\");", source.ToString()));
}
ccp.AppendLine();
csc.AppendLine(" public GPUCopy(ComputeShader shader)");
csc.AppendLine(" {");
csc.AppendLine(" m_Shader = shader;");
csm.AppendLine(" static readonly int _Size = Shader.PropertyToID(\"_Size\");");
for (var i = 0; i < operations.Length; i++)
{
var o = operations[i];
// Compute kernel
var kernelName = string.Format("KSampleCopy{0}_{1}_{2}", o.sourceChannel.ToString(), o.targetChannel.ToString(), o.subscript);
cck.AppendLine(string.Format("#pragma kernel {0}", kernelName));
cck.AppendLine(string.Format(@"[numthreads({0}, {0}, 1)]",
k_KernelSize.ToString(), k_KernelSize.ToString()));
cck.AppendLine(string.Format(@"void {0}(uint2 dispatchThreadId : SV_DispatchThreadID)", kernelName));
cck.AppendLine("{");
cck.AppendLine(string.Format(" _Result{0}[dispatchThreadId] = _Source{1}.SampleLevel(sampler_LinearClamp, float2(dispatchThreadId) * _Size.zw, 0.0).{2};",
o.targetChannel.ToString(), o.sourceChannel.ToString(), o.subscript));
cck.AppendLine("}");
cck.AppendLine();
// CSharp kernel index
var channelName = k_ChannelIDS[o.sourceChannel - 1];
var kernelIndexName = string.Format("k_SampleKernel_{0}2{1}", channelName, o.subscript);
csp.AppendLine(string.Format(" int {0};", kernelIndexName));
// CSharp constructor
csc.AppendLine(string.Format(" {0} = m_Shader.FindKernel(\"{1}\");", kernelIndexName, kernelName));
// CSharp method
csm.AppendLine(string.Format(@" public void SampleCopyChannel_{0}2{1}(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier target, Vector2 size)", channelName, o.subscript));
csm.AppendLine(" {");
csm.AppendLine(string.Format(" if (size.x < {0} || size.y < {0})", k_KernelSize.ToString()));
csm.AppendLine(" Debug.LogWarning(\"Trying to copy a channel from a texture smaller than 8x* or *x8. ComputeShader cannot perform it.\");");
csm.AppendLine(" var s = new Vector4(size.x, size.y, 1f / size.x, 1f / size.y);");
csm.AppendLine(" cmd.SetComputeVectorParam(m_Shader, _Size, s);");
csm.AppendLine(string.Format(" cmd.SetComputeTextureParam(m_Shader, {0}, _Source{1}, source);", kernelIndexName, o.sourceChannel.ToString()));
csm.AppendLine(string.Format(" cmd.SetComputeTextureParam(m_Shader, {0}, _Result{1}, target);", kernelIndexName, o.targetChannel.ToString()));
csm.AppendLine(string.Format(" cmd.DispatchCompute(m_Shader, {0}, (int)(size.x) / {1}, (int)(size.y) / {1}, 1);", kernelIndexName, k_KernelSize.ToString()));
csm.AppendLine(" }");
}
csc.AppendLine(" }");
// Compute Shader
cc.AppendLine(@"// Autogenerated file. Do not edit by hand");
cc.AppendLine();
cc.AppendLine(@"#include ""../ShaderLibrary/Common.hlsl""");
cc.AppendLine();
cc.AppendLine(@"SamplerState sampler_LinearClamp;");
cc.AppendLine();
cc.AppendLine(@"CBUFFER_START(cb)");
cc.AppendLine(@" float4 _Size;");
cc.AppendLine(@"CBUFFER_END");
cc.AppendLine(ccp.ToString()); // Properties
cc.AppendLine(cck.ToString()); // Kernels
// CSharp
cs.AppendLine(@"// Autogenerated file. Do not edit by hand");
cs.AppendLine(@"using System;");
cs.AppendLine(@"using UnityEngine.Rendering;");
cs.AppendLine();
cs.AppendLine(@"namespace UnityEngine.Experimental.Rendering");
cs.AppendLine("{");
cs.AppendLine(" public class GPUCopy");
cs.AppendLine(" {");
cs.AppendLine(" ComputeShader m_Shader;");
cs.AppendLine(csp.ToString()); // Properties
cs.AppendLine(csc.ToString()); // Constructor
cs.AppendLine(csm.ToString()); // methods
cs.AppendLine(" }");
cs.AppendLine("}");
computeShader = cc.ToString();
csharp = cs.ToString();
}
void OnValidate()
{
for (var i = 0; i < m_CopyOperation.Length; i++)
{
var o = m_CopyOperation[i];
o.sourceChannel = Mathf.Clamp(o.sourceChannel, 1, k_ChannelIDS.Length);
o.targetChannel = Mathf.Clamp(o.targetChannel, 1, k_ChannelIDS.Length);
m_CopyOperation[i] = o;
}
}
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyAsset.cs.meta


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

17
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyDefinition.asset


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d6592d54c1ab4694eaabc84e14cc6385, type: 3}
m_Name: GPUCopyDefinition
m_EditorClassIdentifier:
m_CopyOperation:
- subscript: x
sourceChannel: 4
targetChannel: 1

10
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Resources/GPUCopyDefinition.asset.meta


fileFormatVersion: 2
guid: 6aece293b43f5fb4fb5ace0d22b0035a
timeCreated: 1507122722
licenseType: Pro
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

9
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/Core/Shadow.meta


fileFormatVersion: 2
guid: d49f97c73daab8a4a8d389c977c2345f
folderAsset: yes
timeCreated: 1491321440
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

437
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/ShaderGUI/LightweightStandardGUI.cs


using System;
using UnityEditor.Experimental.Rendering.LightweightPipeline;
using UnityEngine;
namespace UnityEditor
{
internal class LightweightStandardGUI : ShaderGUI
{
public enum WorkflowMode : int
{
Specular = 0,
Metallic
}
public enum BlendMode : int
{
Opaque,
Cutout,
Fade, // Old school alpha-blending mode, fresnel does not affect amount of transparency
Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply
}
public enum SmoothnessMapChannel : int
{
SpecularMetallicAlpha,
AlbedoAlpha,
}
private static class Styles
{
public static GUIContent uvSetLabel = new GUIContent("UV Set");
public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
public static GUIContent specularMapText = new GUIContent("Specular", "Specular (RGB) and Smoothness (A)");
public static GUIContent metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)");
public static GUIContent smoothnessText = new GUIContent("Smoothness", "Smoothness value");
public static GUIContent smoothnessScaleText = new GUIContent("Smoothness", "Smoothness scale factor");
public static GUIContent smoothnessMapChannelText = new GUIContent("Source", "Smoothness texture and channel");
public static GUIContent highlightsText = new GUIContent("Specular Highlights", "Specular Highlights");
public static GUIContent reflectionsText = new GUIContent("Reflections", "Glossy Reflections");
public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
public static GUIContent heightMapText = new GUIContent("Height Map", "Height Map (G)");
public static GUIContent occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
public static GUIContent emissionText = new GUIContent("Color", "Emission (RGB)");
public static GUIContent detailMaskText = new GUIContent("Detail Mask", "Mask for Secondary Maps (A)");
public static GUIContent detailAlbedoText = new GUIContent("Detail Albedo x2", "Albedo (RGB) multiplied by 2");
public static GUIContent detailNormalMapText = new GUIContent("Normal Map", "Normal Map");
public static string primaryMapsText = "Main Maps";
public static string secondaryMapsText = "Secondary Maps";
public static string forwardText = "Forward Rendering Options";
public static string workflowModeText = "Workflow Mode";
public static string renderingMode = "Rendering Mode";
public static string advancedText = "Advanced Options";
public static readonly string[] workflowNames = Enum.GetNames(typeof(WorkflowMode));
public static readonly string[] blendNames = Enum.GetNames(typeof(BlendMode));
public static readonly string[] metallicSmoothnessChannelNames = {"Metallic Alpha", "Albedo Alpha"};
public static readonly string[] specularSmoothnessChannelNames = {"Specular Alpha", "Albedo Alpha"};
}
#pragma warning disable 0414
private MaterialProperty workflowMode = null;
private MaterialProperty blendMode = null;
private MaterialProperty albedoColor = null;
private MaterialProperty albedoMap = null;
private MaterialProperty alphaCutoff = null;
private MaterialProperty smoothness = null;
private MaterialProperty smoothnessScale = null;
private MaterialProperty smoothnessMapChannel = null;
private MaterialProperty metallic = null;
private MaterialProperty specColor = null;
private MaterialProperty metallicGlossMap = null;
private MaterialProperty specGlossMap = null;
private MaterialProperty highlights = null;
private MaterialProperty reflections = null;
private MaterialProperty bumpScale = null;
private MaterialProperty bumpMap = null;
private MaterialProperty occlusionStrength = null;
private MaterialProperty occlusionMap = null;
private MaterialProperty heigtMapScale = null;
private MaterialProperty heightMap = null;
private MaterialProperty emissionColorForRendering = null;
private MaterialProperty emissionMap = null;
private MaterialProperty detailMask = null;
private MaterialProperty detailAlbedoMap = null;
private MaterialProperty detailNormalMapScale = null;
private MaterialProperty detailNormalMap = null;
private MaterialProperty uvSetSecondary = null;
private MaterialEditor m_MaterialEditor;
private const float kMaxfp16 = 65536f; // Clamp to a value that fits into fp16.
private ColorPickerHDRConfig m_ColorPickerHDRConfig = new ColorPickerHDRConfig(0f, kMaxfp16, 1 / kMaxfp16, 3f);
private bool m_FirstTimeApply = true;
#pragma warning restore 0414
public void FindProperties(MaterialProperty[] props)
{
workflowMode = FindProperty("_WorkflowMode", props);
blendMode = FindProperty("_Mode", props);
albedoColor = FindProperty("_Color", props);
albedoMap = FindProperty("_MainTex", props);
alphaCutoff = FindProperty("_Cutoff", props);
smoothness = FindProperty("_Glossiness", props);
smoothnessScale = FindProperty("_GlossMapScale", props, false);
smoothnessMapChannel = FindProperty("_SmoothnessTextureChannel", props, false);
metallic = FindProperty("_Metallic", props);
specColor = FindProperty("_SpecColor", props);
metallicGlossMap = FindProperty("_MetallicGlossMap", props);
specGlossMap = FindProperty("_SpecGlossMap", props);
highlights = FindProperty("_SpecularHighlights", props);
reflections = FindProperty("_GlossyReflections", props);
bumpScale = FindProperty("_BumpScale", props);
bumpMap = FindProperty("_BumpMap", props);
heigtMapScale = FindProperty("_Parallax", props);
heightMap = FindProperty("_ParallaxMap", props);
occlusionStrength = FindProperty("_OcclusionStrength", props);
occlusionMap = FindProperty("_OcclusionMap", props);
emissionColorForRendering = FindProperty("_EmissionColor", props);
emissionMap = FindProperty("_EmissionMap", props);
detailMask = FindProperty("_DetailMask", props);
detailAlbedoMap = FindProperty("_DetailAlbedoMap", props);
detailNormalMapScale = FindProperty("_DetailNormalMapScale", props);
detailNormalMap = FindProperty("_DetailNormalMap", props);
uvSetSecondary = FindProperty("_UVSec", props);
}
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
{
FindProperties(props); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
m_MaterialEditor = materialEditor;
Material material = materialEditor.target as Material;
// Make sure that needed setup (ie keywords/renderqueue) are set up if we're switching some existing
// material to a lightweight shader.
if (m_FirstTimeApply)
{
MaterialChanged(material);
m_FirstTimeApply = false;
}
ShaderPropertiesGUI(material);
}
public void ShaderPropertiesGUI(Material material)
{
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
{
DoPopup(Styles.workflowModeText, workflowMode, Styles.workflowNames);
DoPopup(Styles.renderingMode, blendMode, Styles.blendNames);
// Primary properties
GUILayout.Label(Styles.primaryMapsText, EditorStyles.boldLabel);
DoAlbedoArea(material);
DoMetallicSpecularArea();
DoNormalArea();
m_MaterialEditor.TexturePropertySingleLine(Styles.occlusionText, occlusionMap, occlusionMap.textureValue != null ? occlusionStrength : null);
DoEmissionArea(material);
EditorGUI.BeginChangeCheck();
m_MaterialEditor.TextureScaleOffsetProperty(albedoMap);
if (EditorGUI.EndChangeCheck())
emissionMap.textureScaleAndOffset = albedoMap.textureScaleAndOffset; // Apply the main texture scale and offset to the emission texture as well, for Enlighten's sake
EditorGUILayout.Space();
m_MaterialEditor.ShaderProperty(highlights, Styles.highlightsText);
m_MaterialEditor.ShaderProperty(reflections, Styles.reflectionsText);
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendMode.targets)
MaterialChanged((Material)obj);
}
EditorGUILayout.Space();
// NB renderqueue editor is not shown on purpose: we want to override it based on blend mode
GUILayout.Label(Styles.advancedText, EditorStyles.boldLabel);
m_MaterialEditor.EnableInstancingField();
m_MaterialEditor.DoubleSidedGIField();
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
// _Emission property is lost after assigning Standard shader to the material
// thus transfer it before assigning the new shader
if (material.HasProperty("_Emission"))
{
material.SetColor("_EmissionColor", material.GetColor("_Emission"));
}
base.AssignNewShaderToMaterial(material, oldShader, newShader);
if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/"))
{
SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));
return;
}
BlendMode blendMode = BlendMode.Opaque;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
blendMode = BlendMode.Cutout;
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
blendMode = BlendMode.Fade;
}
material.SetFloat("_Mode", (float)blendMode);
if (oldShader.name.Equals("Standard (Specular setup)"))
{
material.SetFloat("_WorkflowMode", (float) WorkflowMode.Specular);
Texture texture = material.GetTexture("_SpecGlossMap");
if (texture != null)
material.SetTexture("_MetallicSpecGlossMap", texture);
}
else
{
material.SetFloat("_WorkflowMode", (float) WorkflowMode.Metallic);
Texture texture = material.GetTexture("_MetallicGlossMap");
if (texture != null)
material.SetTexture("_MetallicSpecGlossMap", texture);
}
MaterialChanged(material);
}
private void DoPopup(string label, MaterialProperty property, string[] options)
{
EditorGUI.showMixedValue = property.hasMixedValue;
var mode = property.floatValue;
EditorGUI.BeginChangeCheck();
mode = EditorGUILayout.Popup(label, (int) mode, options);
if (EditorGUI.EndChangeCheck())
{
m_MaterialEditor.RegisterPropertyChangeUndo(label);
property.floatValue = (float)mode;
}
EditorGUI.showMixedValue = false;
}
void DoNormalArea()
{
m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap);
}
void DoAlbedoArea(Material material)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor);
if (((BlendMode)material.GetFloat("_Mode") == BlendMode.Cutout))
{
m_MaterialEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);
}
}
void DoEmissionArea(Material material)
{
// Emission for GI?
if (m_MaterialEditor.EmissionEnabledProperty())
{
bool hadEmissionTexture = emissionMap.textureValue != null;
// Texture and HDR color controls
m_MaterialEditor.TexturePropertyWithHDRColor(Styles.emissionText, emissionMap, emissionColorForRendering, m_ColorPickerHDRConfig, false);
// If texture was assigned and color was black set color to white
float brightness = emissionColorForRendering.colorValue.maxColorComponent;
if (emissionMap.textureValue != null && !hadEmissionTexture && brightness <= 0f)
emissionColorForRendering.colorValue = Color.white;
// LW does not support RealtimeEmissive. We set it to bake emissive and handle the emissive is black right.
material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.BakedEmissive;
if (brightness <= 0f)
material.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;
}
}
void DoMetallicSpecularArea()
{
string[] metallicSpecSmoothnessChannelName;
bool hasGlossMap = false;
if ((WorkflowMode) workflowMode.floatValue == WorkflowMode.Metallic)
{
hasGlossMap = metallicGlossMap.textureValue != null;
metallicSpecSmoothnessChannelName = Styles.metallicSmoothnessChannelNames;
m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicGlossMap,
hasGlossMap ? null : metallic);
}
else
{
hasGlossMap = specGlossMap.textureValue != null;
metallicSpecSmoothnessChannelName = Styles.specularSmoothnessChannelNames;
m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specGlossMap,
hasGlossMap ? null : specColor);
}
bool showSmoothnessScale = hasGlossMap;
if (smoothnessMapChannel != null)
{
int smoothnessChannel = (int)smoothnessMapChannel.floatValue;
if (smoothnessChannel == (int)SmoothnessMapChannel.AlbedoAlpha)
showSmoothnessScale = true;
}
int indentation = 2; // align with labels of texture properties
m_MaterialEditor.ShaderProperty(showSmoothnessScale ? smoothnessScale : smoothness, showSmoothnessScale ? Styles.smoothnessScaleText : Styles.smoothnessText, indentation);
int prevIndentLevel = EditorGUI.indentLevel;
EditorGUI.indentLevel = 3;
if (smoothnessMapChannel != null)
DoPopup(Styles.smoothnessMapChannelText.text, smoothnessMapChannel, metallicSpecSmoothnessChannelName);
EditorGUI.indentLevel = prevIndentLevel;
}
public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
{
switch (blendMode)
{
case BlendMode.Opaque:
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
case BlendMode.Cutout:
material.SetOverrideTag("RenderType", "TransparentCutout");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
break;
case BlendMode.Fade:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
case BlendMode.Transparent:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
}
}
static SmoothnessMapChannel GetSmoothnessMapChannel(Material material)
{
int ch = (int)material.GetFloat("_SmoothnessTextureChannel");
if (ch == (int)SmoothnessMapChannel.AlbedoAlpha)
return SmoothnessMapChannel.AlbedoAlpha;
else
return SmoothnessMapChannel.SpecularMetallicAlpha;
}
static void SetMaterialKeywords(Material material)
{
// Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation
// (MaterialProperty value might come from renderer material property block)
bool isSpecularWorkFlow = (WorkflowMode)material.GetFloat("_WorkflowMode") == WorkflowMode.Specular;
bool hasGlossMap = false;
if (isSpecularWorkFlow)
hasGlossMap = material.GetTexture("_SpecGlossMap");
else
hasGlossMap = material.GetTexture("_MetallicGlossMap");
LightweightShaderHelper.SetKeyword(material, "_SPECULAR_SETUP", isSpecularWorkFlow);
LightweightShaderHelper.SetKeyword(material, "_METALLIC_SETUP", !isSpecularWorkFlow);
LightweightShaderHelper.SetKeyword(material, "_METALLICSPECGLOSSMAP", hasGlossMap);
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP", hasGlossMap && isSpecularWorkFlow);
LightweightShaderHelper.SetKeyword(material, "_METALLICGLOSSMAP", hasGlossMap && !isSpecularWorkFlow);
LightweightShaderHelper.SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap"));
LightweightShaderHelper.SetKeyword(material, "_SPECULARHIGHLIGHTS_OFF", material.GetFloat("_SpecularHighlights") == 0.0f);
LightweightShaderHelper.SetKeyword(material, "_GLOSSYREFLECTIONS_OFF", material.GetFloat("_GlossyReflections") == 0.0f);
LightweightShaderHelper.SetKeyword(material, "_OCCLUSIONMAP", material.GetTexture("_OcclusionMap"));
LightweightShaderHelper.SetKeyword(material, "_PARALLAXMAP", material.GetTexture("_ParallaxMap"));
LightweightShaderHelper.SetKeyword(material, "_DETAIL_MULX2", material.GetTexture("_DetailAlbedoMap") || material.GetTexture("_DetailNormalMap"));
// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect
// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.
// The fixup routine makes sure that the material is in the correct state if/when changes are made to the mode or color.
MaterialEditor.FixupEmissiveFlag(material);
bool shouldEmissionBeEnabled = (material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
LightweightShaderHelper.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
if (material.HasProperty("_SmoothnessTextureChannel"))
{
LightweightShaderHelper.SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha);
}
}
static void MaterialChanged(Material material)
{
material.shaderKeywords = null;
SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));
SetMaterialKeywords(material);
}
}
}

253
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Editor/ShaderGUI/LightweightStandardSimpleLightingGUI.cs


using System;
using UnityEditor;
using UnityEngine;
using UnityEditor.Experimental.Rendering.LightweightPipeline;
public class LightweightStandardSimpleLightingGUI : ShaderGUI
{
private const float kMinShininessValue = 0.01f;
private MaterialProperty blendModeProp = null;
private MaterialProperty albedoMapProp = null;
private MaterialProperty albedoColorProp = null;
private MaterialProperty alphaCutoffProp = null;
private MaterialProperty specularSourceProp = null;
private MaterialProperty glossinessSourceProp = null;
private MaterialProperty specularGlossMapProp = null;
private MaterialProperty specularColorProp = null;
private MaterialProperty shininessProp = null;
private MaterialProperty bumpMapProp = null;
private MaterialProperty emissionMapProp = null;
private MaterialProperty emissionColorProp = null;
private MaterialEditor m_MaterialEditor = null;
private const float kMaxfp16 = 65536f; // Clamp to a value that fits into fp16.
private ColorPickerHDRConfig m_ColorPickerHDRConfig = new ColorPickerHDRConfig(0f, kMaxfp16, 1 / kMaxfp16, 3f);
private static class Styles
{
public static GUIContent[] albedoGlosinessLabels =
{
new GUIContent("Base (RGB) Glossiness (A)", "Base Color (RGB) and Glossiness (A)"),
new GUIContent("Base (RGB)", "Base Color (RGB)")
};
public static GUIContent albedoAlphaLabel = new GUIContent("Base (RGB) Alpha (A)",
"Base Color (RGB) and Transparency (A)");
public static GUIContent[] specularGlossMapLabels =
{
new GUIContent("Specular Map (RGB)", "Specular Color (RGB)"),
new GUIContent("Specular Map (RGB) Glossiness (A)", "Specular Color (RGB) Glossiness (A)")
};
public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
public static GUIContent emissionMapLabel = new GUIContent("Emission Map", "Emission Map");
public static readonly string[] blendNames = Enum.GetNames(typeof(UpgradeBlendMode));
public static readonly string[] glossinessSourceNames = Enum.GetNames(typeof(GlossinessSource));
public static string renderingModeLabel = "Rendering Mode";
public static string specularSourceLabel = "Specular";
public static string glossinessSourceLabel = "Glossiness Source";
public static string glossinessSource = "Glossiness Source";
public static string albedoColorLabel = "Base Color";
public static string albedoMapAlphaLabel = "Base(RGB) Alpha(A)";
public static string albedoMapGlossinessLabel = "Base(RGB) Glossiness (A)";
public static string alphaCutoffLabel = "Alpha Cutoff";
public static string shininessLabel = "Shininess";
public static string normalMapLabel = "Normal map";
public static string emissionColorLabel = "Emission Color";
}
private void FindMaterialProperties(MaterialProperty[] properties)
{
blendModeProp = FindProperty("_Mode", properties);
albedoMapProp = FindProperty("_MainTex", properties);
albedoColorProp = FindProperty("_Color", properties);
alphaCutoffProp = FindProperty("_Cutoff", properties);
specularSourceProp = FindProperty("_SpecSource", properties);
glossinessSourceProp = FindProperty("_GlossinessSource", properties);
specularGlossMapProp = FindProperty("_SpecGlossMap", properties);
specularColorProp = FindProperty("_SpecColor", properties);
shininessProp = FindProperty("_Shininess", properties);
bumpMapProp = FindProperty("_BumpMap", properties);
emissionMapProp = FindProperty("_EmissionMap", properties);
emissionColorProp = FindProperty("_EmissionColor", properties);
}
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
Material material = materialEditor.target as Material;
m_MaterialEditor = materialEditor;
FindMaterialProperties(properties);
EditorGUI.BeginChangeCheck();
{
DoBlendMode();
EditorGUILayout.Space();
DoSpecular();
EditorGUILayout.Space();
m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMapProp);
EditorGUILayout.Space();
DoEmissionArea(material);
EditorGUI.BeginChangeCheck();
m_MaterialEditor.TextureScaleOffsetProperty(albedoMapProp);
if (EditorGUI.EndChangeCheck())
emissionMapProp.textureScaleAndOffset = albedoMapProp.textureScaleAndOffset; // Apply the main texture scale and offset to the emission texture as well, for Enlighten's sake
}
if (EditorGUI.EndChangeCheck())
LegacyBlinnPhongUpgrader.UpdateMaterialKeywords(material);
EditorGUILayout.Space();
EditorGUILayout.Space();
materialEditor.RenderQueueField();
EditorGUILayout.Space();
EditorGUILayout.Space();
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
base.AssignNewShaderToMaterial(material, oldShader, newShader);
// Shininess value cannot be zero since it will produce undefined values for cases where pow(0, 0).
float shininess = material.GetFloat("_Shininess");
material.SetFloat("_Shininess", Mathf.Clamp(shininess, kMinShininessValue, 1.0f));
string oldShaderName = oldShader.name;
string[] shaderStrings = oldShaderName.Split('/');
if (shaderStrings[0].Equals("Legacy Shaders") || shaderStrings[0].Equals("Mobile"))
{
ConvertFromLegacy(material, oldShaderName);
}
LegacyBlinnPhongUpgrader.UpdateMaterialKeywords(material);
}
private void DoBlendMode()
{
int modeValue = (int)blendModeProp.floatValue;
EditorGUI.BeginChangeCheck();
modeValue = EditorGUILayout.Popup(Styles.renderingModeLabel, modeValue, Styles.blendNames);
if (EditorGUI.EndChangeCheck())
blendModeProp.floatValue = modeValue;
UpgradeBlendMode mode = (UpgradeBlendMode)blendModeProp.floatValue;
EditorGUILayout.Space();
if (mode == UpgradeBlendMode.Opaque)
{
int glossSource = (int)glossinessSourceProp.floatValue;
m_MaterialEditor.TexturePropertySingleLine(Styles.albedoGlosinessLabels[glossSource], albedoMapProp,
albedoColorProp);
m_MaterialEditor.TextureScaleOffsetProperty(albedoMapProp);}
else
{
m_MaterialEditor.TexturePropertySingleLine(Styles.albedoAlphaLabel, albedoMapProp, albedoColorProp);
if (mode == UpgradeBlendMode.Cutout)
m_MaterialEditor.RangeProperty(alphaCutoffProp, "Cutoff");
}
}
private void DoSpecular()
{
EditorGUILayout.Space();
SpecularSource specularSource = (SpecularSource)specularSourceProp.floatValue;
EditorGUI.BeginChangeCheck();
bool enabled = EditorGUILayout.Toggle(Styles.specularSourceLabel, specularSource == SpecularSource.SpecularTextureAndColor);
if (EditorGUI.EndChangeCheck())
specularSourceProp.floatValue = enabled ? (float)SpecularSource.SpecularTextureAndColor : (float)SpecularSource.NoSpecular;
SpecularSource specSource = (SpecularSource)specularSourceProp.floatValue;
if (specSource != SpecularSource.NoSpecular)
{
bool hasSpecularMap = specularGlossMapProp.textureValue != null;
m_MaterialEditor.TexturePropertySingleLine(Styles.specularGlossMapLabels[(int)glossinessSourceProp.floatValue], specularGlossMapProp, hasSpecularMap ? null : specularColorProp);
EditorGUI.indentLevel += 2;
GUI.enabled = hasSpecularMap;
int glossinessSource = hasSpecularMap ? (int)glossinessSourceProp.floatValue : (int)GlossinessSource.BaseAlpha;
EditorGUI.BeginChangeCheck();
glossinessSource = EditorGUILayout.Popup(Styles.glossinessSourceLabel, glossinessSource, Styles.glossinessSourceNames);
if (EditorGUI.EndChangeCheck())
glossinessSourceProp.floatValue = glossinessSource;
GUI.enabled = true;
EditorGUI.BeginChangeCheck();
float shininess = EditorGUILayout.Slider(Styles.shininessLabel, shininessProp.floatValue,
kMinShininessValue, 1.0f);
if (EditorGUI.EndChangeCheck())
shininessProp.floatValue = shininess;
EditorGUI.indentLevel -= 2;
}
}
void DoEmissionArea(Material material)
{
// Emission for GI?
if (m_MaterialEditor.EmissionEnabledProperty())
{
bool hadEmissionTexture = emissionMapProp.textureValue != null;
// Texture and HDR color controls
m_MaterialEditor.TexturePropertyWithHDRColor(Styles.emissionMapLabel, emissionMapProp, emissionColorProp, m_ColorPickerHDRConfig, false);
// If texture was assigned and color was black set color to white
float brightness = emissionColorProp.colorValue.maxColorComponent;
if (emissionMapProp.textureValue != null && !hadEmissionTexture && brightness <= 0f)
emissionColorProp.colorValue = Color.white;
// LW does not support RealtimeEmissive. We set it to bake emissive and handle the emissive is black right.
material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.BakedEmissive;
if (brightness <= 0f)
material.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;
}
}
private void ConvertFromLegacy(Material material, string oldShaderName)
{
UpgradeParams shaderUpgradeParams;
if (oldShaderName.Contains("Transp"))
{
shaderUpgradeParams.blendMode = UpgradeBlendMode.Alpha;
shaderUpgradeParams.glosinessSource = GlossinessSource.SpecularAlpha;
}
else if (oldShaderName.Contains("Cutout"))
{
shaderUpgradeParams.blendMode = UpgradeBlendMode.Cutout;
shaderUpgradeParams.glosinessSource = GlossinessSource.SpecularAlpha;
}
else
{
shaderUpgradeParams.blendMode = UpgradeBlendMode.Opaque;
shaderUpgradeParams.glosinessSource = GlossinessSource.BaseAlpha;
}
if (oldShaderName.Contains("Spec"))
shaderUpgradeParams.specularSource = SpecularSource.SpecularTextureAndColor;
else
shaderUpgradeParams.specularSource = SpecularSource.NoSpecular;
material.SetFloat("_Mode", (float)shaderUpgradeParams.blendMode);
material.SetFloat("_SpecSource", (float)shaderUpgradeParams.specularSource);
material.SetFloat("_GlossinessSource", (float)shaderUpgradeParams.glosinessSource);
if (oldShaderName.Contains("Self-Illumin"))
{
material.SetTexture("_EmissionMap", material.GetTexture("_MainTex"));
material.SetTexture("_MainTex", null);
material.SetColor("_EmissionColor", Color.white);
}
}
}

24
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightConstantBuffer.cs


using UnityEngine;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
{
public static class PerFrameBuffer
{
public static int _GlossyEnvironmentColor;
public static int _AttenuationTexture;
}
public static class PerCameraBuffer
{
public static int _MainLightPosition;
public static int _MainLightColor;
public static int _MainLightAttenuationParams;
public static int _MainLightSpotDir;
public static int _AdditionalLightCount;
public static int _AdditionalLightPosition;
public static int _AdditionalLightColor;
public static int _AdditionalLightAttenuationParams;
public static int _AdditionalLightSpotDir;
}
}

13
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/LightweightConstantBuffer.cs.meta


fileFormatVersion: 2
guid: 2462b9b2044ad4b62a8c7fcd6f012f8e
timeCreated: 1506514389
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

46
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightBlit.shader


Shader "Hidden/LightweightPipeline/Blit"
{
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline"}
LOD 100
Pass
{
Tags { "LightMode" = "LightweightForward"}
CGPROGRAM
#pragma vertex Vertex
#pragma fragment Fragment
struct VertexInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct VertexOutput
{
half4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
};
sampler2D _BlitTex;
VertexOutput Vertex(VertexInput i)
{
VertexOutput o;
o.pos = half4(i.vertex.xyz, 1.0);
o.uv = i.uv;
return o;
}
fixed4 Fragment(VertexOutput i) : SV_Target
{
fixed4 col = tex2D(_BlitTex, i.uv);
return col;
}
ENDCG
}
}
}

10
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightBlit.shader.meta


fileFormatVersion: 2
guid: c17132b1f77d20942aa75f8429c0f8bc
timeCreated: 1505729520
licenseType: Pro
ShaderImporter:
externalObjects: {}
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

46
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCopyDepth.shader


Shader "Hidden/LightweightPipeline/CopyDepth"
{
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "LightiweightPipeline"}
Pass
{
ColorMask 0
ZTest Always
ZWrite On
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D_float _CameraDepthTexture;
struct VertexInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct VertexOutput
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
VertexOutput vert(VertexInput i)
{
VertexOutput o;
o.uv = i.uv;
o.position = UnityObjectToClipPos(i.vertex);
return o;
}
float frag(VertexOutput i) : SV_Depth
{
return tex2D(_CameraDepthTexture, i.uv).r;
}
ENDCG
}
}
}

10
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCopyDepth.shader.meta


fileFormatVersion: 2
guid: d6dae50ee9e1bfa4db75f19f99355220
timeCreated: 1506692614
licenseType: Pro
ShaderImporter:
externalObjects: {}
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

135
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.cginc


#ifndef LIGHTWEIGHT_PIPELINE_CORE_INCLUDED
#define LIGHTWEIGHT_PIPELINE_CORE_INCLUDED
#include "UnityCG.cginc"
#ifdef _SPECULAR_SETUP
#define SAMPLE_METALLICSPECULAR(uv) tex2D(_SpecGlossMap, uv)
#else
#define SAMPLE_METALLICSPECULAR(uv) tex2D(_MetallicGlossMap, uv)
#endif
half3 TangentToWorldNormal(half3 normalTangent, half3 tangent, half3 binormal, half3 normal)
{
half3x3 tangentToWorld = half3x3(tangent, binormal, normal);
return normalize(mul(normalTangent, tangentToWorld));
}
float ComputeFogFactor(float z)
{
float clipZ_01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(z);
#if defined(FOG_LINEAR)
// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w);
return half(fogFactor);
#elif defined(FOG_EXP)
// factor = exp(-density*z)
float unityFogFactor = unity_FogParams.y * clipZ_01;
return half(saturate(exp2(-unityFogFactor)));
#elif defined(FOG_EXP2)
// factor = exp(-(density*z)^2)
float unityFogFactor = unity_FogParams.x * clipZ_01;
return half(saturate(exp2(-unityFogFactor*unityFogFactor)));
#else
return 0.0h;
#endif
}
inline half Alpha(half albedoAlpha)
{
#if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A)
half alpha = _Color.a;
#else
half alpha = albedoAlpha * _Color.a;
#endif
#if defined(_ALPHATEST_ON)
clip(alpha - _Cutoff);
#endif
return alpha;
}
half3 Normal(float2 uv)
{
#if _NORMALMAP
return UnpackNormal(tex2D(_BumpMap, uv));
#else
return half3(0.0h, 0.0h, 1.0h);
#endif
}
inline void SpecularGloss(half2 uv, half alpha, out half4 specularGloss)
{
specularGloss = half4(0, 0, 0, 1);
#ifdef _SPECGLOSSMAP
specularGloss = tex2D(_SpecGlossMap, uv);
specularGloss.rgb = LIGHTWEIGHT_GAMMA_TO_LINEAR(specularGloss.rgb);
#elif defined(_SPECULAR_COLOR)
specularGloss = _SpecColor;
#endif
#ifdef _GLOSSINESS_FROM_BASE_ALPHA
specularGloss.a = alpha;
#endif
}
half4 MetallicSpecGloss(float2 uv, half albedoAlpha)
{
half4 specGloss;
#ifdef _METALLICSPECGLOSSMAP
specGloss = specGloss = SAMPLE_METALLICSPECULAR(uv);
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
specGloss.a = albedoAlpha * _GlossMapScale;
#else
specGloss.a *= _GlossMapScale;
#endif
#else // _METALLICSPECGLOSSMAP
#if _METALLIC_SETUP
specGloss.rgb = _Metallic.rrr;
#else
specGloss.rgb = _SpecColor.rgb;
#endif
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
specGloss.a = albedoAlpha * _GlossMapScale;
#else
specGloss.a = _Glossiness;
#endif
#endif
return specGloss;
}
half OcclusionLW(float2 uv)
{
#ifdef _OCCLUSIONMAP
#if (SHADER_TARGET < 30)
// SM20: instruction count limitation
// SM20: simpler occlusion
return tex2D(_OcclusionMap, uv).g;
#else
half occ = tex2D(_OcclusionMap, uv).g;
return LerpOneTo(occ, _OcclusionStrength);
#endif
#else
return 1.0;
#endif
}
half3 EmissionLW(float2 uv)
{
#ifndef _EMISSION
return 0;
#else
return LIGHTWEIGHT_GAMMA_TO_LINEAR(tex2D(_EmissionMap, uv).rgb) * _EmissionColor.rgb;
#endif
}
#endif

380
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.cginc


#ifndef LIGHTWEIGHT_LIGHTING_INCLUDED
#define LIGHTWEIGHT_LIGHTING_INCLUDED
#include "UnityCG.cginc"
#include "UnityStandardInput.cginc"
#include "LightweightShadows.cginc"
#define PI 3.14159265359f
#define kDieletricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
#define MAX_VISIBLE_LIGHTS 16
CBUFFER_START(_PerObject)
half4 unity_LightIndicesOffsetAndCount;
half4 unity_4LightIndices0;
half4 unity_4LightIndices1;
half _Shininess;
CBUFFER_END
CBUFFER_START(_PerCamera)
float4 _MainLightPosition;
half4 _MainLightColor;
float4 _MainLightAttenuationParams;
half4 _MainLightSpotDir;
half4 _AdditionalLightCount;
float4 _AdditionalLightPosition[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightColor[MAX_VISIBLE_LIGHTS];
float4 _AdditionalLightAttenuationParams[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightSpotDir[MAX_VISIBLE_LIGHTS];
CBUFFER_END
CBUFFER_START(_PerFrame)
half4 _GlossyEnvironmentColor;
sampler2D _AttenuationTexture;
CBUFFER_END
#if defined(UNITY_COLORSPACE_GAMMA)
#define LIGHTWEIGHT_GAMMA_TO_LINEAR(gammaColor) gammaColor * gammaColor
#define LIGHTWEIGHT_LINEAR_TO_GAMMA(linColor) sqrt(color)
#else
#define LIGHTWEIGHT_GAMMA_TO_LINEAR(color) color
#define LIGHTWEIGHT_LINEAR_TO_GAMMA(color) color
#endif
// Main light initialized without indexing
#define INITIALIZE_MAIN_LIGHT(light) \
light.pos = _MainLightPosition; \
light.color = _MainLightColor; \
light.atten = _MainLightAttenuationParams; \
light.spotDir = _MainLightSpotDir;
// Indexing might have a performance hit for old mobile hardware
#define INITIALIZE_LIGHT(light, i) \
half4 indices = (i < 4) ? unity_4LightIndices0 : unity_4LightIndices1; \
int index = (i < 4) ? i : i - 4; \
int lightIndex = indices[index]; \
light.pos = _AdditionalLightPosition[lightIndex]; \
light.color = _AdditionalLightColor[lightIndex]; \
light.atten = _AdditionalLightAttenuationParams[lightIndex]; \
light.spotDir = _AdditionalLightSpotDir[lightIndex]
struct LightInput
{
float4 pos;
half4 color;
float4 atten;
half4 spotDir;
};
struct SurfaceData
{
half3 albedo;
half3 specular;
half metallic;
half smoothness;
half3 normal;
half3 emission;
half occlusion;
half alpha;
};
struct SurfaceInput
{
float4 lightmapUV;
half3 normalWS;
half3 tangentWS;
half3 bitangentWS;
float3 positionWS;
half3 viewDirectionWS;
half fogFactor;
};
struct BRDFData
{
half3 diffuse;
half3 specular;
half perceptualRoughness;
half roughness;
half grazingTerm;
};
inline void InitializeSurfaceData(out SurfaceData outSurfaceData)
{
outSurfaceData.albedo = half3(1.0h, 1.0h, 1.0h);
outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h);
outSurfaceData.metallic = 1.0h;
outSurfaceData.smoothness = 0.5h;
outSurfaceData.normal = half3(0.0h, 0.0h, 1.0h);
outSurfaceData.occlusion = 1.0h;
outSurfaceData.emission = half3(0.0h, 0.0h, 0.0h);
outSurfaceData.alpha = 1.0h;
}
half SpecularReflectivity(half3 specular)
{
#if (SHADER_TARGET < 30)
// SM2.0: instruction count limitation
// SM2.0: simplified SpecularStrength
return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint
#else
return max(max(specular.r, specular.g), specular.b);
#endif
}
void ApplyFog(inout half3 color, half fogFactor)
{
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
color = lerp(unity_FogColor, color, fogFactor);
#endif
}
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData)
{
// BRDF SETUP
#ifdef _METALLIC_SETUP
// We'll need oneMinusReflectivity, so
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
// store (1-dielectricSpec) in kDieletricSpec.a, then
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
// = alpha - metallic * alpha
half oneMinusDielectricSpec = kDieletricSpec.a;
half oneMinusReflectivity = oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
half reflectivity = 1.0 - oneMinusReflectivity;
outBRDFData.diffuse = albedo * oneMinusReflectivity;
outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic);
#else
half reflectivity = SpecularReflectivity(specular);
outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular);
outBRDFData.specular = specular;
#endif
outBRDFData.grazingTerm = saturate(smoothness + reflectivity);
outBRDFData.perceptualRoughness = 1.0h - smoothness;
outBRDFData.roughness = outBRDFData.perceptualRoughness * outBRDFData.perceptualRoughness;
#ifdef _ALPHAPREMULTIPLY_ON
outBRDFData.diffuse *= alpha;
alpha = reflectivity + alpha * (1.0 - reflectivity);
#endif
}
// Based on Minimalist CookTorrance BRDF
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
//
// * NDF [Modified] GGX
// * Modified Kelemen and Szirmay-​Kalos for Visibility term
// * Fresnel approximated with 1/LdotH
half3 LightweightBDRF(BRDFData brdfData, half roughness2, half3 normal, half3 lightDirection, half3 viewDir)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
half3 halfDir = Unity_SafeNormalize(lightDirection + viewDir);
half NoH = saturate(dot(normal, halfDir));
half LoH = saturate(dot(lightDirection, halfDir));
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
// https://community.arm.com/events/1155
half d = NoH * NoH * (roughness2 - 1.h) + 1.00001h;
half LoH2 = LoH * LoH;
half specularTerm = roughness2 / ((d * d) * max(0.1h, LoH2) * (brdfData.roughness + 0.5h) * 4);
// on mobiles (where half actually means something) denominator have risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
#if defined (SHADER_API_MOBILE)
specularTerm = specularTerm - 1e-4h;
#endif
#if defined (SHADER_API_MOBILE)
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
#endif
half3 color = specularTerm * brdfData.specular + brdfData.diffuse;
return color;
#else
return brdfData.diffuse;
#endif
}
half3 LightweightBRDFIndirect(BRDFData brdfData, UnityIndirect indirect, half roughness2, half fresnelTerm)
{
half3 c = indirect.diffuse * brdfData.diffuse;
float surfaceReduction = 1.0 / (roughness2 + 1.0);
c += surfaceReduction * indirect.specular * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm);
return c;
}
UnityIndirect LightweightGI(float4 lightmapUV, half3 normalWorld, half3 reflectVec, half occlusion, half perceptualRoughness)
{
UnityIndirect o = (UnityIndirect)0;
#ifdef LIGHTMAP_ON
o.diffuse += (DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, lightmapUV.xy))) * occlusion;
#else
o.diffuse = ShadeSH9(half4(normalWorld, 1.0)) * occlusion;
#endif
#ifndef _GLOSSYREFLECTIONS_OFF
Unity_GlossyEnvironmentData g;
g.roughness = perceptualRoughness;
g.reflUVW = reflectVec;
o.specular = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, g) * occlusion;
#else
o.specular = _GlossyEnvironmentColor * occlusion;
#endif
return o;
}
half SpotAttenuation(half3 spotDirection, half3 lightDirection, float4 attenuationParams)
{
// Spot Attenuation with a linear falloff can be defined as
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
// This can be rewritten as
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
// If we precompute the terms in a MAD instruction
half SdotL = dot(spotDirection, lightDirection);
// attenuationParams.x = invAngleRange
// attenuationParams.y = (-cosOuterAngle invAngleRange)
return saturate(SdotL * attenuationParams.x + attenuationParams.y);
}
// In per-vertex falloff there's no smooth falloff to light range. A hard cut will be noticed
inline half ComputeVertexLightAttenuation(LightInput lightInput, half3 normal, float3 worldPos, out half3 lightDirection)
{
float4 attenuationParams = lightInput.atten;
float3 posToLightVec = lightInput.pos - worldPos * lightInput.pos.w;
float distanceSqr = max(dot(posToLightVec, posToLightVec), 0.001);
// normalized light dir
lightDirection = half3(posToLightVec * rsqrt(distanceSqr));
// attenuationParams.z = kQuadFallOff = (25.0) / (lightRange * lightRange)
// attenuationParams.w = lightRange * lightRange
half lightAtten = half(1.0 / (1.0 + distanceSqr * attenuationParams.z));
lightAtten *= SpotAttenuation(lightInput.spotDir.xyz, lightDirection, attenuationParams);
return lightAtten;
}
// In per-pixel falloff attenuation smoothly decreases to light range.
inline half ComputePixelLightAttenuation(LightInput lightInput, half3 normal, float3 worldPos, out half3 lightDirection)
{
float4 attenuationParams = lightInput.atten;
float3 posToLightVec = lightInput.pos.xyz - worldPos * lightInput.pos.w;
float distanceSqr = max(dot(posToLightVec, posToLightVec), 0.001);
// normalized light dir
lightDirection = half3(posToLightVec * rsqrt(distanceSqr));
float u = (distanceSqr * attenuationParams.z) / attenuationParams.w;
half lightAtten = tex2D(_AttenuationTexture, float2(u, 0.0)).a;
lightAtten *= SpotAttenuation(lightInput.spotDir.xyz, lightDirection, attenuationParams);
return lightAtten;
}
inline half ComputeMainLightAttenuation(LightInput lightInput, half3 normal, float3 worldPos, out half3 lightDirection)
{
#ifdef _MAIN_DIRECTIONAL_LIGHT
// Light pos holds normalized light dir
lightDirection = lightInput.pos;
return 1.0;
#else
return ComputePixelLightAttenuation(lightInput, normal, worldPos, lightDirection);
#endif
}
inline half3 LightingLambert(half3 diffuseColor, half3 lightDir, half3 normal, half atten)
{
half NdotL = saturate(dot(normal, lightDir));
return diffuseColor * (NdotL * atten);
}
inline half3 LightingBlinnPhong(half3 diffuseColor, half4 specularGloss, half3 lightDir, half3 normal, half3 viewDir, half atten)
{
half NdotL = saturate(dot(normal, lightDir));
half3 diffuse = diffuseColor * NdotL;
half3 halfVec = normalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));
half3 specular = specularGloss.rgb * pow(NdotH, _Shininess * 128.0) * specularGloss.a;
return (diffuse + specular) * atten;
}
half3 TangentToWorldNormal(half3 normalTangent, half3 tangent, half3 binormal, half3 normal)
{
half3x3 tangentToWorld = half3x3(tangent, binormal, normal);
return normalize(mul(normalTangent, tangentToWorld));
}
half4 OutputColor(half3 color, half alpha)
{
#if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)
return half4(LIGHTWEIGHT_LINEAR_TO_GAMMA(color), alpha);
#else
return half4(LIGHTWEIGHT_LINEAR_TO_GAMMA(color), 1);
#endif
}
half4 LightweightFragmentPBR(half4 lightmapUV, float3 positionWS, half3 normalWS, half3 tangentWS, half3 bitangentWS,
half3 viewDirectionWS, half fogFactor, half3 albedo, half metallic, half3 specular, half smoothness,
half3 normalTS, half ambientOcclusion, half3 emission, half alpha)
{
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
half3 vertexNormal = normalWS;
#if _NORMALMAP
normalWS = TangentToWorldNormal(normalTS, tangentWS, bitangentWS, normalWS);
#else
normalWS = normalize(normalWS);
#endif
half3 reflectVec = reflect(-viewDirectionWS, normalWS);
half roughness2 = brdfData.roughness * brdfData.roughness;
UnityIndirect indirectLight = LightweightGI(lightmapUV, normalWS, reflectVec, ambientOcclusion, brdfData.perceptualRoughness);
// PBS
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
half3 color = LightweightBRDFIndirect(brdfData, indirectLight, roughness2, fresnelTerm);
half3 lightDirectionWS;
LightInput light;
INITIALIZE_MAIN_LIGHT(light);
half lightAtten = ComputeMainLightAttenuation(light, normalWS, positionWS, lightDirectionWS);
lightAtten *= LIGHTWEIGHT_SHADOW_ATTENUATION(positionWS, normalize(vertexNormal), _ShadowLightDirection.xyz);
half NdotL = saturate(dot(normalWS, lightDirectionWS));
half3 radiance = light.color * (lightAtten * NdotL);
color += LightweightBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput light;
INITIALIZE_LIGHT(light, lightIter);
half lightAtten = ComputePixelLightAttenuation(light, normalWS, positionWS, lightDirectionWS);
half NdotL = saturate(dot(normalWS, lightDirectionWS));
half3 radiance = light.color * (lightAtten * NdotL);
color += LightweightBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
}
#endif
color += emission;
// Computes fog factor per-vertex
ApplyFog(color, fogFactor);
return OutputColor(color, alpha);
}
#endif

226
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.cginc


#ifndef LIGHTWEIGHT_PASS_LIT_INCLUDED
#define LIGHTWEIGHT_PASS_LIT_INCLUDED
#include "LightweightLighting.cginc"
struct LightweightVertexInput
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 texcoord : TEXCOORD0;
float2 lightmapUV : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct LightweightVertexOutput
{
float2 uv : TEXCOORD0;
float4 ambientOrLightmapUV : TEXCOORD1; // xy: lightmapUV, zw: dynamicLightmapUV OR color from SH
float4 posWS : TEXCOORD2;
#if _NORMALMAP
half3 tangent : TEXCOORD3;
half3 binormal : TEXCOORD4;
half3 normal : TEXCOORD5;
#else
half3 normal : TEXCOORD3;
#endif
half4 viewDir : TEXCOORD6; // xyz: viewDir
half4 fogFactorAndVertexLight : TEXCOORD7; // x: fogFactor, yzw: vertex light
float4 clipPos : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO
};
inline void InitializeStandardLitSurfaceData(LightweightVertexOutput IN, out SurfaceData outSurfaceData)
{
float2 uv = IN.uv;
half4 albedoAlpha = tex2D(_MainTex, uv);
half4 specGloss = MetallicSpecGloss(uv, albedoAlpha);
outSurfaceData.albedo = LIGHTWEIGHT_GAMMA_TO_LINEAR(albedoAlpha.rgb) * _Color.rgb;
#if _METALLIC_SETUP
outSurfaceData.metallic = specGloss.r;
outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h);
#else
outSurfaceData.metallic = 1.0h;
outSurfaceData.specular = specGloss.rgb;
#endif
outSurfaceData.smoothness = specGloss.a;
outSurfaceData.normal = Normal(uv);
outSurfaceData.occlusion = OcclusionLW(uv);
outSurfaceData.emission = EmissionLW(uv);
outSurfaceData.emission += IN.fogFactorAndVertexLight.yzw;
outSurfaceData.alpha = Alpha(albedoAlpha.a);
}
void InitializeSurfaceInput(LightweightVertexOutput IN, out SurfaceInput outSurfaceInput)
{
#if LIGHTMAP_ON
outSurfaceInput.lightmapUV = float4(IN.ambientOrLightmapUV.xy, 0.0, 0.0);
#else
outSurfaceInput.lightmapUV = float4(0.0, 0.0, 0.0, 0.0);
#endif
#if _NORMALMAP
outSurfaceInput.tangentWS = IN.tangent;
outSurfaceInput.bitangentWS = IN.binormal;
#else
outSurfaceInput.tangentWS = half3(1.0h, 0.0h, 0.0h);
outSurfaceInput.bitangentWS = half3(0.0h, 1.0h, 0.0h);
#endif
outSurfaceInput.normalWS = IN.normal;
outSurfaceInput.positionWS = IN.posWS;
outSurfaceInput.viewDirectionWS = IN.viewDir;
outSurfaceInput.fogFactor = IN.fogFactorAndVertexLight.x;
}
LightweightVertexOutput LitPassVertex(LightweightVertexInput v)
{
LightweightVertexOutput o = (LightweightVertexOutput)0;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.posWS.xyz = worldPos;
half3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
o.viewDir.xyz = viewDir;
half3 normal = normalize(UnityObjectToWorldNormal(v.normal));
#if _NORMALMAP
half sign = v.tangent.w * unity_WorldTransformParams.w;
o.tangent = normalize(mul((half3x3)unity_ObjectToWorld, v.tangent.xyz));
o.binormal = cross(normal, o.tangent) * sign;
o.normal = normal;
#else
o.normal = normal;
#endif
#ifdef LIGHTMAP_ON
o.ambientOrLightmapUV.xy = v.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
// TODO: Dynamic Lightmap
o.ambientOrLightmapUV.zw = float2(0.0, 0.0);
// TODO: Currently there's no way to pass in ambient contribution to fragmentPBR.
// We should allow to create custom ambient computation for things like SH evaluation, lightmap, ambient color etc.
//#else
// o.ambientOrLightmapUV = half4(SHEvalLinearL2(half4(normal, 1.0)), 0.0h);
#endif
o.fogFactorAndVertexLight.yzw = half3(0.0h, 0.0h, 0.0h);
#if defined(_VERTEX_LIGHTS)
half3 diffuse = half3(1.0, 1.0, 1.0);
int vertexLightStart = _AdditionalLightCount.x;
int vertexLightEnd = min(_AdditionalLightCount.y, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = vertexLightStart; lightIter < vertexLightEnd; ++lightIter)
{
LightInput lightData;
INITIALIZE_LIGHT(lightData, lightIter);
half3 lightDirection;
half atten = ComputeVertexLightAttenuation(lightData, normal, worldPos, lightDirection);
o.fogFactorAndVertexLight.yzw += LightingLambert(diffuse, lightDirection, normal, atten) * lightData.color;
}
#endif
float4 clipPos = UnityObjectToClipPos(v.vertex);
o.fogFactorAndVertexLight.x = ComputeFogFactor(clipPos.z);
o.clipPos = clipPos;
return o;
}
half4 LitPassFragment(LightweightVertexOutput IN) : SV_Target
{
SurfaceData surfaceData;
InitializeStandardLitSurfaceData(IN, surfaceData);
SurfaceInput surfaceInput;
InitializeSurfaceInput(IN, surfaceInput);
return LightweightFragmentPBR(surfaceInput.lightmapUV, surfaceInput.positionWS, surfaceInput.normalWS, surfaceInput.tangentWS, surfaceInput.bitangentWS, surfaceInput.viewDirectionWS, surfaceInput.fogFactor, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.normal, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha);
}
half4 LitPassFragmentSimple(LightweightVertexOutput IN) : SV_Target
{
float2 uv = IN.uv;
half4 diffuseAlpha = tex2D(_MainTex, uv);
half3 diffuse = LIGHTWEIGHT_GAMMA_TO_LINEAR(diffuseAlpha.rgb) * _Color.rgb;
#ifdef _GLOSSINESS_FROM_BASE_ALPHA
half alpha = _Color.a;
#else
half alpha = diffuseAlpha.a * _Color.a;
#endif
// Keep for compatibility reasons. Shader Inpector throws a warning when using cutoff
// due overdraw performance impact.
#ifdef _ALPHATEST_ON
clip(alpha - _Cutoff);
#endif
#if _NORMALMAP
half3 normalTangent = Normal(uv);
half3 normalWorld = TangentToWorldNormal(normalTangent, IN.tangent, IN.binormal, IN.normal);
#else
half3 normalWorld = normalize(IN.normal);
#endif
half4 specularGloss;
SpecularGloss(uv, alpha, specularGloss);
half3 viewDir = IN.viewDir.xyz;
float3 worldPos = IN.posWS.xyz;
half3 lightDirection;
#if defined(LIGHTMAP_ON)
half3 color = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, IN.ambientOrLightmapUV.xy)) * diffuse;
#else
half3 color = (ShadeSH9(half4(normalWorld, 1.0)) + IN.ambientOrLightmapUV.xyz) * diffuse;
#endif
LightInput lightInput;
INITIALIZE_MAIN_LIGHT(lightInput);
half lightAtten = ComputeMainLightAttenuation(lightInput, normalWorld, worldPos, lightDirection);
lightAtten *= LIGHTWEIGHT_SHADOW_ATTENUATION(worldPos, normalize(IN.normal), _ShadowLightDirection.xyz);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
color += LightingBlinnPhong(diffuse, specularGloss, lightDirection, normalWorld, viewDir, lightAtten) * lightInput.color;
#else
color += LightingLambert(diffuse, lightDirection, normalWorld, lightAtten) * lightInput.color;
#endif
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput lightData;
INITIALIZE_LIGHT(lightData, lightIter);
half lightAtten = ComputePixelLightAttenuation(lightData, normalWorld, worldPos, lightDirection);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
color += LightingBlinnPhong(diffuse, specularGloss, lightDirection, normalWorld, viewDir, lightAtten) * lightData.color;
#else
color += LightingLambert(diffuse, lightDirection, normalWorld, lightAtten) * lightData.color;
#endif
}
#endif // _ADDITIONAL_LIGHTS
color += EmissionLW(uv);
color += IN.fogFactorAndVertexLight.yzw;
// Computes Fog Factor per vextex
ApplyFog(color, IN.fogFactorAndVertexLight.x);
return OutputColor(color, alpha);
};
#endif

9
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.cginc.meta


fileFormatVersion: 2
guid: 116bd973269b9f741b7177c8523b9e50
timeCreated: 1488965025
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

20
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.cginc


#ifndef LIGHTWEIGHT_PASS_SHADOW_INCLUDED
#define LIGHTWEIGHT_PASS_SHADOW_INCLUDED
float4 ShadowPassVertex(float4 pos : POSITION) : SV_POSITION
{
float4 clipPos = UnityObjectToClipPos(pos);
#if defined(UNITY_REVERSED_Z)
clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE);
#else
clipPos.z = max(clipPos.z, UNITY_NEAR_CLIP_VALUE);
#endif
return clipPos;
}
half4 ShadowPassFragment() : SV_TARGET
{
return 0;
}
#endif

9
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.cginc.meta


fileFormatVersion: 2
guid: 9a48a2987a0e11645adf07fe4a8d5ec9
timeCreated: 1488965025
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

93
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShadows.cginc


#ifndef LIGHTWEIGHT_SHADOWS_INCLUDED
#define LIGHTWEIGHT_SHADOWS_INCLUDED
#define MAX_SHADOW_CASCADES 4
#if defined(_HARD_SHADOWS) || defined(_SOFT_SHADOWS) || defined(_HARD_SHADOWS_CASCADES) || defined(_SOFT_SHADOWS_CASCADES)
#define _SHADOWS
#endif
#if defined(_HARD_SHADOWS_CASCADES) || defined(_SOFT_SHADOWS_CASCADES)
#define _SHADOW_CASCADES
#endif
#ifdef _SHADOWS
#define LIGHTWEIGHT_SHADOW_ATTENUATION(posWorld, vertexNormal, shadowDir) ComputeShadowAttenuation(posWorld, vertexNormal, shadowDir)
#else
#define LIGHTWEIGHT_SHADOW_ATTENUATION(posWorld, vertexNormal, shadowDir) 1.0h
#endif
sampler2D_float _ShadowMap;
float _PCFKernel[8];
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES];
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES];
half4 _ShadowData;
half4 _ShadowLightDirection;
inline half ShadowAttenuation(float3 shadowCoord)
{
if (shadowCoord.x <= 0 || shadowCoord.x >= 1 || shadowCoord.y <= 0 || shadowCoord.y >= 1)
return 1;
float depth = tex2D(_ShadowMap, shadowCoord).r;
#if defined(UNITY_REVERSED_Z)
return step(depth - _ShadowData.y, shadowCoord.z);
#else
return step(shadowCoord.z, depth + _ShadowData.y);
#endif
}
inline half ComputeCascadeIndex(float3 wpos)
{
float3 fromCenter0 = wpos.xyz - _DirShadowSplitSpheres[0].xyz;
float3 fromCenter1 = wpos.xyz - _DirShadowSplitSpheres[1].xyz;
float3 fromCenter2 = wpos.xyz - _DirShadowSplitSpheres[2].xyz;
float3 fromCenter3 = wpos.xyz - _DirShadowSplitSpheres[3].xyz;
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3));
float4 vDirShadowSplitSphereSqRadii;
vDirShadowSplitSphereSqRadii.x = _DirShadowSplitSpheres[0].w;
vDirShadowSplitSphereSqRadii.y = _DirShadowSplitSpheres[1].w;
vDirShadowSplitSphereSqRadii.z = _DirShadowSplitSpheres[2].w;
vDirShadowSplitSphereSqRadii.w = _DirShadowSplitSpheres[3].w;
fixed4 weights = fixed4(distances2 < vDirShadowSplitSphereSqRadii);
weights.yzw = saturate(weights.yzw - weights.xyz);
return 4 - dot(weights, fixed4(4, 3, 2, 1));
}
inline half ShadowPCF(half3 shadowCoord)
{
// TODO: simulate textureGatherOffset not available, simulate it
half2 offset = half2(0, 0);
half attenuation = ShadowAttenuation(half3(shadowCoord.xy + half2(_PCFKernel[0], _PCFKernel[1]) + offset, shadowCoord.z)) +
ShadowAttenuation(half3(shadowCoord.xy + half2(_PCFKernel[2], _PCFKernel[3]) + offset, shadowCoord.z)) +
ShadowAttenuation(half3(shadowCoord.xy + half2(_PCFKernel[4], _PCFKernel[5]) + offset, shadowCoord.z)) +
ShadowAttenuation(half3(shadowCoord.xy + half2(_PCFKernel[6], _PCFKernel[7]) + offset, shadowCoord.z));
return attenuation * 0.25;
}
inline half ComputeShadowAttenuation(float3 posWorld, half3 vertexNormal, half3 shadowDir)
{
half NdotL = dot(vertexNormal, shadowDir);
half bias = saturate(1.0 - NdotL) * _ShadowData.z;
float3 posWorldOffsetNormal = posWorld + vertexNormal * bias;
int cascadeIndex = 0;
#ifdef _SHADOW_CASCADES
cascadeIndex = ComputeCascadeIndex(posWorldOffsetNormal);
if (cascadeIndex >= MAX_SHADOW_CASCADES)
return 1.0;
#endif
float4 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorldOffsetNormal, 1.0));
shadowCoord.xyz /= shadowCoord.w;
shadowCoord.z = saturate(shadowCoord.z);
#if defined(_SOFT_SHADOWS) || defined(_SOFT_SHADOWS_CASCADES)
return ShadowPCF(shadowCoord.xyz);
#else
return ShadowAttenuation(shadowCoord.xyz);
#endif
}
#endif

142
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandard.shader


Shader "LightweightPipeline/Standard (Physically Based)"
{
Properties
{
// Specular vs Metallic workflow
[HideInInspector] _WorkflowMode("WorkflowMode", Float) = 1.0
_Color("Color", Color) = (1,1,1,1)
_MainTex("Albedo", 2D) = "white" {}
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
_Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
_GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0
_SmoothnessTextureChannel("Smoothness texture channel", Float) = 0
[Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
_MetallicGlossMap("Metallic", 2D) = "white" {}
_SpecColor("Specular", Color) = (0.2, 0.2, 0.2)
_SpecGlossMap("Specular", 2D) = "white" {}
[Toggle] _SpecularHighlights("Specular Highlights", Float) = 1.0
[Toggle] _GlossyReflections("Glossy Reflections", Float) = 1.0
_BumpScale("Scale", Float) = 1.0
_BumpMap("Normal Map", 2D) = "bump" {}
_Parallax("Height Scale", Range(0.005, 0.08)) = 0.02
_ParallaxMap("Height Map", 2D) = "black" {}
_OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
_OcclusionMap("Occlusion", 2D) = "white" {}
_EmissionColor("Color", Color) = (0,0,0)
_EmissionMap("Emission", 2D) = "white" {}
_DetailMask("Detail Mask", 2D) = "white" {}
_DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
_DetailNormalMapScale("Scale", Float) = 1.0
_DetailNormalMap("Normal Map", 2D) = "bump" {}
[Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0
// Blending state
[HideInInspector] _Mode("__mode", Float) = 0.0
[HideInInspector] _SrcBlend("__src", Float) = 1.0
[HideInInspector] _DstBlend("__dst", Float) = 0.0
[HideInInspector] _ZWrite("__zw", Float) = 1.0
}
SubShader
{
Tags{"RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline"}
LOD 300
// ------------------------------------------------------------------
// Base forward pass (directional light, emission, lightmaps, ...)
Pass
{
Tags{"LightMode" = "LightweightForward"}
Blend[_SrcBlend][_DstBlend]
ZWrite[_ZWrite]
CGPROGRAM
#pragma target 3.0
// -------------------------------------
#pragma shader_feature _METALLIC_SETUP _SPECULAR_SETUP
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICSPECGLOSSMAP
#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _GLOSSYREFLECTIONS_OFF
#pragma shader_feature _OCCLUSIONMAP
#pragma multi_compile _MAIN_DIRECTIONAL_LIGHT _MAIN_SPOT_LIGHT _MAIN_POINT_LIGHT
#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ _HARD_SHADOWS _SOFT_SHADOWS _HARD_SHADOWS_CASCADES _SOFT_SHADOWS_CASCADES
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile_fog
#pragma multi_compile_instancing
#pragma vertex LitPassVertex
#pragma fragment LitPassFragment
#include "UnityStandardInput.cginc"
#include "LightweightPassLit.cginc"
ENDCG
}
Pass
{
Tags{"Lightmode" = "ShadowCaster"}
ZWrite On ZTest LEqual
CGPROGRAM
#pragma target 2.0
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
#include "UnityCG.cginc"
#include "LightweightPassShadow.cginc"
ENDCG
}
Pass
{
Tags{"Lightmode" = "DepthOnly"}
ZWrite On
CGPROGRAM
#pragma target 2.0
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float4 vert(float4 pos : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(pos);
}
half4 frag() : SV_TARGET
{
return 0;
}
ENDCG
}
}
FallBack "Standard"
CustomEditor "LightweightStandardGUI"
}

172
MaterialGraphProject/Assets/SRP/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardSimpleLighting.shader


// Shader targeted for low end devices. Single Pass Forward Rendering. Shader Model 2
Shader "LightweightPipeline/Standard (Simple Lighting)"
{
// Keep properties of StandardSpecular shader for upgrade reasons.
Properties
{
_Color("Color", Color) = (1,1,1,1)
_MainTex("Base (RGB) Glossiness / Alpha (A)", 2D) = "white" {}
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
_Shininess("Shininess", Range(0.01, 1.0)) = 1.0
_GlossMapScale("Smoothness Factor", Range(0.0, 1.0)) = 1.0
_Glossiness("Glossiness", Range(0.0, 1.0)) = 0.5
[Enum(Specular Alpha,0,Albedo Alpha,1)] _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0
[HideInInspector] _SpecSource("Specular Color Source", Float) = 0.0
_SpecColor("Specular", Color) = (1.0, 1.0, 1.0)
_SpecGlossMap("Specular", 2D) = "white" {}
[HideInInspector] _GlossinessSource("Glossiness Source", Float) = 0.0
[ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0
[ToggleOff] _GlossyReflections("Glossy Reflections", Float) = 1.0
[HideInInspector] _BumpScale("Scale", Float) = 1.0
[NoScaleOffset] _BumpMap("Normal Map", 2D) = "bump" {}
_Parallax("Height Scale", Range(0.005, 0.08)) = 0.02
_ParallaxMap("Height Map", 2D) = "black" {}
_EmissionColor("Emission Color", Color) = (0,0,0)
_EmissionMap("Emission", 2D) = "white" {}
_DetailMask("Detail Mask", 2D) = "white" {}
_DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
_DetailNormalMapScale("Scale", Float) = 1.0
_DetailNormalMap("Normal Map", 2D) = "bump" {}
[Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0
// Blending state
[HideInInspector] _Mode("__mode", Float) = 0.0
[HideInInspector] _SrcBlend("__src", Float) = 1.0
[HideInInspector] _DstBlend("__dst", Float) = 0.0
[HideInInspector] _ZWrite("__zw", Float) = 1.0
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline" }
LOD 300
Pass
{
Tags { "LightMode" = "LightweightForward" }
// Use same blending / depth states as Standard shader
Blend[_SrcBlend][_DstBlend]
ZWrite[_ZWrite]
CGPROGRAM
#pragma target 3.0
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON
#pragma shader_feature _ _SPECGLOSSMAP _SPECULAR_COLOR
#pragma shader_feature _ _GLOSSINESS_FROM_BASE_ALPHA
#pragma shader_feature _NORMALMAP
#pragma shader_feature _EMISSION
#pragma multi_compile _MAIN_DIRECTIONAL_LIGHT _MAIN_SPOT_LIGHT _MAIN_POINT_LIGHT
#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ _HARD_SHADOWS _SOFT_SHADOWS _HARD_SHADOWS_CASCADES _SOFT_SHADOWS_CASCADES
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile_fog
#pragma multi_compile_instancing
#pragma vertex LitPassVertex
#pragma fragment LitPassFragmentSimple
#include "UnityStandardInput.cginc"
#include "LightweightPassLit.cginc"
ENDCG
}
Pass
{
Tags{"Lightmode" = "ShadowCaster"}
ZWrite On ZTest LEqual
CGPROGRAM
#pragma target 2.0
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
#include "UnityCG.cginc"
#include "LightweightPassShadow.cginc"
ENDCG
}
Pass
{
Tags{"Lightmode" = "DepthOnly"}
ZWrite On
CGPROGRAM
#pragma target 2.0
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float4 vert(float4 pos : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(pos);
}
half4 frag() : SV_TARGET
{
return 0;
}
ENDCG
}
// This pass it not used during regular rendering, only for lightmap baking.
Pass
{
Tags{ "LightMode" = "Meta" }
Cull Off
CGPROGRAM
#define UNITY_SETUP_BRDF_INPUT SpecularSetup
#pragma vertex vert_meta
#pragma fragment frag_meta_ld
#pragma shader_feature _EMISSION
#pragma shader_feature _SPECGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature EDITOR_VISUALIZATION
#include "UnityStandardMeta.cginc"
#include "LightweightCore.cginc"
fixed4 frag_meta_ld(v2f_meta i) : SV_Target
{
UnityMetaInput o;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o);
o.Albedo = Albedo(i.uv);
half4 specularColor;
SpecularGloss(i.uv.xy, 1.0, specularColor);
o.SpecularColor = specularColor;
#ifdef _EMISSION
o.Emission += LIGHTWEIGHT_GAMMA_TO_LINEAR(tex2D(_EmissionMap, i.uv).rgb) * _EmissionColor;
#else
o.Emission += _EmissionColor;
#endif
return UnityMetaFragment(o);
}
ENDCG
}
}
Fallback "Standard (Specular setup)"
CustomEditor "LightweightStandardSimpleLightingGUI"
}

39
MaterialGraphProject/Assets/SRP/PostProcessing/.gitignore


# Unity stuff
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/Assets/AssetStoreTools*
# Autogenerated VS/MD solution and project files
[Ee]xported[Oo]bj/
*.csproj
*.unityproj
*.sln*
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
# Unity3D generated meta files
*.pidb.meta
LICENSE.meta
PostProcessing.meta
README.md.meta
package.json.meta
# Unity3D Generated File On Crash Reports
sysinfo.txt
# OS generated
.DS_Store*
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
[Tt]humbs.db

0
MaterialGraphProject/Assets/SRP/PostProcessing/.npmignore

21
MaterialGraphProject/Assets/SRP/PostProcessing/LICENSE


The MIT License (MIT)
Copyright (c) 2014-2017, Unity Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

8
MaterialGraphProject/Assets/SRP/PostProcessing/PostProcessing/Editor.meta


fileFormatVersion: 2
guid: d92c086ad7fe8fc408422746b8052530
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存