浏览代码

Merge pull request #832 from Unity-Technologies/LightweightPipeline

Lightweight pipeline
/main
GitHub 7 年前
当前提交
c05bd70c
共有 27 个文件被更改,包括 3033 次插入3188 次删除
  1. 245
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSampling.hlsl
  2. 110
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Data/LightweightPipelineAsset.cs
  3. 13
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightConstantBuffer.cs
  4. 124
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs
  5. 11
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Input.hlsl
  6. 4
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/InputSurface.hlsl
  7. 118
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Lighting.hlsl
  8. 82
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassLit.hlsl
  9. 22
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Particles.hlsl
  10. 80
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Shadows.hlsl
  11. 1
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandard.shader
  12. 18
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardParticles.shader
  13. 60
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardTerrain.shader
  14. 5
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardUnlit.shader
  15. 4
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset
  16. 3
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset.meta
  17. 65
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/LightingData.asset
  18. 2
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/LightingData.asset.meta
  19. 999
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-0_comp_dir.png
  20. 1001
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-0_comp_light.exr
  21. 999
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-1_comp_dir.png
  22. 1001
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-1_comp_light.exr
  23. 1001
      Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/ReflectionProbe-0.exr
  24. 244
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl
  25. 9
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl.meta
  26. 0
      /ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardUnlit.shader.meta
  27. 0
      /ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardUnlit.shader

245
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSampling.hlsl


// Various shadow sampling logic.
// Again two versions, one for dynamic resource indexing, one for static resource access.
// ------------------------------------------------------------------
// PCF Filtering helpers
// ------------------------------------------------------------------
// Assuming a isoceles right angled triangle of height "triangleHeight" (as drawn below).
// This function return the area of the triangle above the first texel.
//
// |\ <-- 45 degree slop isosceles right angled triangle
// | \
// ---- <-- length of this side is "triangleHeight"
// _ _ _ _ <-- texels
real SampleShadow_GetTriangleTexelArea(real triangleHeight)
{
return triangleHeight - 0.5;
}
// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
// This function return the area of the triangle above each of those texels.
// | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center
// / \ <-- 45 degree slop isosceles triangle (ie tent projected in 2D)
// / \
// _ _ _ _ <-- texels
// X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw)
void SampleShadow_GetTexelAreas_Tent_3x3(real offset, out real4 computedArea, out real4 computedAreaUncut)
{
// Compute the exterior areas
real offset01SquaredHalved = (offset + 0.5) * (offset + 0.5) * 0.5;
computedAreaUncut.x = computedArea.x = offset01SquaredHalved - offset;
computedAreaUncut.w = computedArea.w = offset01SquaredHalved;
// Compute the middle areas
// For Y : We find the area in Y of as if the left section of the isoceles triangle would
// intersect the axis between Y and Z (ie where offset = 0).
computedAreaUncut.y = SampleShadow_GetTriangleTexelArea(1.5 - offset);
// This area is superior to the one we are looking for if (offset < 0) thus we need to
// subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5).
real clampedOffsetLeft = min(offset,0);
real areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft;
computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle;
// We do the same for the Z but with the right part of the isoceles triangle
computedAreaUncut.z = SampleShadow_GetTriangleTexelArea(1.5 + offset);
real clampedOffsetRight = max(offset,0);
real areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight;
computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle;
}
// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
// This function return the weight of each texels area relative to the full triangle area.
void SampleShadow_GetTexelWeights_Tent_3x3(real offset, out real4 computedWeight)
{
real4 dummy;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedWeight, dummy);
computedWeight *= 0.44444;//0.44 == 1/(the triangle area)
}
// Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels.
// This function return the weight of each texels area relative to the full triangle area.
// / \
// _ _ _ _ _ _ <-- texels
// 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[])
void SampleShadow_GetTexelWeights_Tent_5x5(real offset, out real3 texelsWeightsA, out real3 texelsWeightsB)
{
// See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
real4 computedArea_From3texelTriangle;
real4 computedAreaUncut_From3texelTriangle;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
// Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
// the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel.
// 0.16 is 1/(the triangle area)
texelsWeightsA.x = 0.16 * (computedArea_From3texelTriangle.x);
texelsWeightsA.y = 0.16 * (computedAreaUncut_From3texelTriangle.y);
texelsWeightsA.z = 0.16 * (computedArea_From3texelTriangle.y + 1);
texelsWeightsB.x = 0.16 * (computedArea_From3texelTriangle.z + 1);
texelsWeightsB.y = 0.16 * (computedAreaUncut_From3texelTriangle.z);
texelsWeightsB.z = 0.16 * (computedArea_From3texelTriangle.w);
}
// Assuming a isoceles triangle of 3.5 texel height and 7 texels wide lying on 8 texels.
// This function return the weight of each texels area relative to the full triangle area.
// / \
// _ _ _ _ _ _ _ _ <-- texels
// 0 1 2 3 4 5 6 7 <-- computed area indices (in texelsWeights[])
void SampleShadow_GetTexelWeights_Tent_7x7(real offset, out real4 texelsWeightsA, out real4 texelsWeightsB)
{
// See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
real4 computedArea_From3texelTriangle;
real4 computedAreaUncut_From3texelTriangle;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
// Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
// the 7 texel wide triangle can be seen as the 3 texel wide one but shifted up by two unit/texel.
// 0.081632 is 1/(the triangle area)
texelsWeightsA.x = 0.081632 * (computedArea_From3texelTriangle.x);
texelsWeightsA.y = 0.081632 * (computedAreaUncut_From3texelTriangle.y);
texelsWeightsA.z = 0.081632 * (computedAreaUncut_From3texelTriangle.y + 1);
texelsWeightsA.w = 0.081632 * (computedArea_From3texelTriangle.y + 2);
texelsWeightsB.x = 0.081632 * (computedArea_From3texelTriangle.z + 2);
texelsWeightsB.y = 0.081632 * (computedAreaUncut_From3texelTriangle.z + 1);
texelsWeightsB.z = 0.081632 * (computedAreaUncut_From3texelTriangle.z);
texelsWeightsB.w = 0.081632 * (computedArea_From3texelTriangle.w);
}
// 3x3 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_3x3(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[4], out real2 fetchesUV[4])
{
// tent base is 3x3 base thus covering from 9 to 12 texels, thus we need 4 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based
real4 texelsWeightsU, texelsWeightsV;
SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU);
SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real2 fetchesWeightsU = texelsWeightsU.xz + texelsWeightsU.yw;
real2 fetchesWeightsV = texelsWeightsV.xz + texelsWeightsV.yw;
// move the PCF bilinear fetches to respect texels weights
real2 fetchesOffsetsU = texelsWeightsU.yw / fetchesWeightsU.xy + real2(-1.5,0.5);
real2 fetchesOffsetsV = texelsWeightsV.yw / fetchesWeightsV.xy + real2(-1.5,0.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[3] = fetchesWeightsU.y * fetchesWeightsV.y;
}
// 5x5 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_5x5(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[9], out real2 fetchesUV[9])
{
// tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
real3 texelsWeightsU_A, texelsWeightsU_B;
real3 texelsWeightsV_A, texelsWeightsV_B;
SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real3 fetchesWeightsU = real3(texelsWeightsU_A.xz, texelsWeightsU_B.y) + real3(texelsWeightsU_A.y, texelsWeightsU_B.xz);
real3 fetchesWeightsV = real3(texelsWeightsV_A.xz, texelsWeightsV_B.y) + real3(texelsWeightsV_A.y, texelsWeightsV_B.xz);
// move the PCF bilinear fetches to respect texels weights
real3 fetchesOffsetsU = real3(texelsWeightsU_A.y, texelsWeightsU_B.xz) / fetchesWeightsU.xyz + real3(-2.5,-0.5,1.5);
real3 fetchesOffsetsV = real3(texelsWeightsV_A.y, texelsWeightsV_B.xz) / fetchesWeightsV.xyz + real3(-2.5,-0.5,1.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xxx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yyy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
fetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y;
fetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y;
fetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z;
fetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z;
fetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z;
}
// 7x7 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_7x7(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[16], out real2 fetchesUV[16])
{
// tent base is 7x7 base thus covering from 49 to 64 texels, thus we need 16 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
real4 texelsWeightsU_A, texelsWeightsU_B;
real4 texelsWeightsV_A, texelsWeightsV_B;
SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real4 fetchesWeightsU = real4(texelsWeightsU_A.xz, texelsWeightsU_B.xz) + real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw);
real4 fetchesWeightsV = real4(texelsWeightsV_A.xz, texelsWeightsV_B.xz) + real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw);
// move the PCF bilinear fetches to respect texels weights
real4 fetchesOffsetsU = real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw) / fetchesWeightsU.xyzw + real4(-3.5,-1.5,0.5,2.5);
real4 fetchesOffsetsV = real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw) / fetchesWeightsV.xyzw + real4(-3.5,-1.5,0.5,2.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xxxx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yyyy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.x);
fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.y);
fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
fetchesUV[9] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
fetchesUV[10] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
fetchesUV[11] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.z);
fetchesUV[12] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.w);
fetchesUV[13] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.w);
fetchesUV[14] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.w);
fetchesUV[15] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.w);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
fetchesWeights[3] = fetchesWeightsU.w * fetchesWeightsV.x;
fetchesWeights[4] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[5] = fetchesWeightsU.y * fetchesWeightsV.y;
fetchesWeights[6] = fetchesWeightsU.z * fetchesWeightsV.y;
fetchesWeights[7] = fetchesWeightsU.w * fetchesWeightsV.y;
fetchesWeights[8] = fetchesWeightsU.x * fetchesWeightsV.z;
fetchesWeights[9] = fetchesWeightsU.y * fetchesWeightsV.z;
fetchesWeights[10] = fetchesWeightsU.z * fetchesWeightsV.z;
fetchesWeights[11] = fetchesWeightsU.w * fetchesWeightsV.z;
fetchesWeights[12] = fetchesWeightsU.x * fetchesWeightsV.w;
fetchesWeights[13] = fetchesWeightsU.y * fetchesWeightsV.w;
fetchesWeights[14] = fetchesWeightsU.z * fetchesWeightsV.w;
fetchesWeights[15] = fetchesWeightsU.w * fetchesWeightsV.w;
}
#include "CoreRP/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl"
// ------------------------------------------------------------------
// PCF Filtering methods

110
ScriptableRenderPipeline/LightweightPipeline/LWRP/Data/LightweightPipelineAsset.cs


_8x = 8
}
public enum DefaultMaterialType
{
Standard = 0,
Particle,
Terrain,
UnityBuiltinDefault
}
private Shader m_DefaultShader;
[SerializeField] private float kAssetVersion = 1.0f;
[SerializeField] private int kAssetVersion = 2;
[SerializeField] private int m_MaxPixelLights = 4;
[SerializeField] private bool m_SupportsVertexLight = false;
[SerializeField] private bool m_RequireDepthTexture = false;

[SerializeField] private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f);
// Resources
[SerializeField] private Shader m_DefaultShader;
[SerializeField] private LightweightPipelineResource m_ResourceAsset;
private LightweightPipelineResource m_ResourceAsset;
[MenuItem("Assets/Create/Render Pipeline/Lightweight/Pipeline Asset", priority = CoreUtils.assetCreateMenuPriority1)]
static void CreateLightweightPipeline()

public override void Action(int instanceId, string pathName, string resourceFile)
{
var instance = CreateInstance<LightweightPipelineAsset>();
string[] guids = AssetDatabase.FindAssets("LightweightPipelineResource t:scriptableobject", m_SearchPaths);
LightweightPipelineResource resourceAsset = null;
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
resourceAsset = AssetDatabase.LoadAssetAtPath<LightweightPipelineResource>(path);
if (resourceAsset != null)
break;
}
// There's currently an issue that prevents FindAssets from find resources withing the package folder.
if (resourceAsset == null)
{
string path = m_SearchPaths[PACKAGE_MANAGER_PATH_INDEX] + "/LWRP/Data/LightweightPipelineResource.asset";
resourceAsset = AssetDatabase.LoadAssetAtPath<LightweightPipelineResource>(path);
}
instance.m_ResourceAsset = resourceAsset;
instance.m_DefaultShader = Shader.Find(LightweightShaderUtils.GetShaderPath(ShaderPathID.STANDARD_PBS));
instance.m_BlitShader = Shader.Find(LightweightShaderUtils.GetShaderPath(ShaderPathID.HIDDEN_BLIT));
instance.m_CopyDepthShader = Shader.Find(LightweightShaderUtils.GetShaderPath(ShaderPathID.HIDDEN_DEPTH_COPY));

private void LoadResourceFile()
{
string[] guids = AssetDatabase.FindAssets("LightweightPipelineResource t:scriptableobject", m_SearchPaths);
LightweightPipelineResource resourceAsset = null;
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
m_ResourceAsset = AssetDatabase.LoadAssetAtPath<LightweightPipelineResource>(path);
if (m_ResourceAsset != null)
break;
}
// There's currently an issue that prevents FindAssets from find resources withing the package folder.
if (m_ResourceAsset == null)
{
string path = m_SearchPaths[PACKAGE_MANAGER_PATH_INDEX] + "/LWRP/Data/LightweightPipelineResource.asset";
m_ResourceAsset = AssetDatabase.LoadAssetAtPath<LightweightPipelineResource>(path);
}
}
#endif
protected override IRenderPipeline InternalCreatePipeline()

DestroyCreatedInstances();
}
private Material GetMaterial(DefaultMaterialType materialType)
{
#if UNITY_EDITOR
if (m_ResourceAsset == null)
LoadResourceFile();
switch (materialType)
{
case DefaultMaterialType.Standard:
return m_ResourceAsset.DefaultMaterial;
case DefaultMaterialType.Particle:
return m_ResourceAsset.DefaultParticleMaterial;
case DefaultMaterialType.Terrain:
return m_ResourceAsset.DefaultTerrainMaterial;
// Unity Builtin Default
default:
return null;
}
#else
return null;
#endif
}
public bool AreShadowsEnabled()
{
return ShadowSetting != ShadowType.NO_SHADOW;

public override Material GetDefaultMaterial()
{
#if UNITY_EDITOR
if (m_ResourceAsset != null)
return m_ResourceAsset.DefaultMaterial;
#endif
return null;
return GetMaterial(DefaultMaterialType.Standard);
#if UNITY_EDITOR
if (m_ResourceAsset != null)
return m_ResourceAsset.DefaultParticleMaterial;
#endif
return null;
return GetMaterial(DefaultMaterialType.Particle);
return null;
return GetMaterial(DefaultMaterialType.UnityBuiltinDefault);
#if UNITY_EDITOR
if (m_ResourceAsset != null)
return m_ResourceAsset.DefaultTerrainMaterial;
#endif
return null;
return GetMaterial(DefaultMaterialType.Terrain);
return null;
return GetMaterial(DefaultMaterialType.UnityBuiltinDefault);
return null;
return GetMaterial(DefaultMaterialType.UnityBuiltinDefault);
return null;
return GetMaterial(DefaultMaterialType.UnityBuiltinDefault);
return null;
return GetMaterial(DefaultMaterialType.UnityBuiltinDefault);
if (m_DefaultShader == null)
m_DefaultShader = Shader.Find(LightweightShaderUtils.GetShaderPath(ShaderPathID.STANDARD_PBS));
return m_DefaultShader;
}

13
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightConstantBuffer.cs


public static int _AdditionalLightSpotDir;
public static int _AdditionalLightSpotAttenuation;
}
public static class ShadowConstantBuffer
{
public static int _WorldToShadow;
public static int _ShadowData;
public static int _DirShadowSplitSpheres;
public static int _DirShadowSplitSphereRadii;
public static int _ShadowOffset0;
public static int _ShadowOffset1;
public static int _ShadowOffset2;
public static int _ShadowOffset3;
public static int _ShadowmapSize;
}
}

124
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs


private bool m_IsOffscreenCamera;
private Vector4 kDefaultLightPosition = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
private Vector4 kDefaultLightColor = Color.black;
private Vector4 kDefaultLightAttenuation = new Vector4(0.0f, 1.0f, 0.0f, 1.0f);
private Vector4 kDefaultLightSpotDirection = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
private Vector4 kDefaultLightSpotAttenuation = new Vector4(0.0f, 1.0f, 0.0f, 0.0f);
private Vector4[] m_LightPositions = new Vector4[kMaxVisibleLights];
private Vector4[] m_LightColors = new Vector4[kMaxVisibleLights];
private Vector4[] m_LightDistanceAttenuations = new Vector4[kMaxVisibleLights];

PerCameraBuffer._AdditionalLightDistanceAttenuation = Shader.PropertyToID("_AdditionalLightDistanceAttenuation");
PerCameraBuffer._AdditionalLightSpotDir = Shader.PropertyToID("_AdditionalLightSpotDir");
PerCameraBuffer._AdditionalLightSpotAttenuation = Shader.PropertyToID("_AdditionalLightSpotAttenuation");
ShadowConstantBuffer._WorldToShadow = Shader.PropertyToID("_WorldToShadow");
ShadowConstantBuffer._ShadowData = Shader.PropertyToID("_ShadowData");
ShadowConstantBuffer._DirShadowSplitSpheres = Shader.PropertyToID("_DirShadowSplitSpheres");
ShadowConstantBuffer._DirShadowSplitSphereRadii = Shader.PropertyToID("_DirShadowSplitSphereRadii");
ShadowConstantBuffer._ShadowOffset0 = Shader.PropertyToID("_ShadowOffset0");
ShadowConstantBuffer._ShadowOffset1 = Shader.PropertyToID("_ShadowOffset1");
ShadowConstantBuffer._ShadowOffset2 = Shader.PropertyToID("_ShadowOffset2");
ShadowConstantBuffer._ShadowOffset3 = Shader.PropertyToID("_ShadowOffset3");
ShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_ShadowmapSize");
m_ShadowMapRTID = Shader.PropertyToID("_ShadowMap");

// If we have a main light we don't shade it in the per-object light loop. We also remove it from the per-object cull list
int mainLightPresent = (lightData.mainLightIndex >= 0) ? 1 : 0;
int additionalPixelLightsCount = visibleLightsCount - mainLightPresent;
int vertexLightCount = (m_Asset.SupportsVertexLight) ? Math.Min(visibleLights.Count, kMaxPerObjectLights) - additionalPixelLightsCount : 0;
int vertexLightCount = (m_Asset.SupportsVertexLight) ? Math.Min(visibleLights.Count, kMaxPerObjectLights) - additionalPixelLightsCount - mainLightPresent : 0;
vertexLightCount = Math.Min(vertexLightCount, kMaxVertexLights);
lightData.pixelAdditionalLightsCount = additionalPixelLightsCount;

private void InitializeLightConstants(List<VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightDistanceAttenuation, out Vector4 lightSpotDir,
out Vector4 lightSpotAttenuation)
{
float directContributionNotBaked = 1.0f;
lightPos = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
lightColor = Color.black;
lightDistanceAttenuation = new Vector4(0.0f, 1.0f, 0.0f, directContributionNotBaked);
lightSpotDir = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
lightSpotAttenuation = new Vector4(0.0f, 1.0f, 0.0f, 0.0f);
lightPos = kDefaultLightPosition;
lightColor = kDefaultLightColor;
lightDistanceAttenuation = kDefaultLightSpotAttenuation;
lightSpotDir = kDefaultLightSpotDirection;
lightSpotAttenuation = kDefaultLightAttenuation;
// When no lights are visible, main light will be set to -1.
// In this case we initialize it to default values and return

float oneOverFadeRangeSqr = 1.0f / fadeRangeSqr;
float lightRangeSqrOverFadeRangeSqr = -lightRangeSqr / fadeRangeSqr;
float quadAtten = 25.0f / lightRangeSqr;
lightDistanceAttenuation = new Vector4(quadAtten, oneOverFadeRangeSqr, lightRangeSqrOverFadeRangeSqr, directContributionNotBaked);
lightDistanceAttenuation = new Vector4(quadAtten, oneOverFadeRangeSqr, lightRangeSqrOverFadeRangeSqr, 1.0f);
}
if (lightData.lightType == LightType.Spot)

if (lightData.shadowMapSampleType != LightShadows.None)
SetupShadowReceiverConstants(cmd, lights[lightData.mainLightIndex]);
if (lightData.totalAdditionalLightsCount > 0)
SetupAdditionalListConstants(cmd, lights, ref lightData);
SetupAdditionalListConstants(cmd, lights, ref lightData);
}
private void SetupMainLightConstants(CommandBuffer cmd, List<VisibleLight> lights, int lightIndex)

{
int additionalLightIndex = 0;
// 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.Count; ++i)
perObjectLightIndexMap[i] = -1;
for (int i = 0; i < lights.Count && additionalLightIndex < kMaxVisibleLights; ++i)
if (lightData.totalAdditionalLightsCount > 0)
if (i != lightData.mainLightIndex)
// 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.Count; ++i)
perObjectLightIndexMap[i] = -1;
for (int i = 0; i < lights.Count && additionalLightIndex < kMaxVisibleLights; ++i)
// 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]];
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_LightDistanceAttenuations[additionalLightIndex],
out m_LightSpotDirections[additionalLightIndex],
out m_LightSpotAttenuations[additionalLightIndex]);
additionalLightIndex++;
// 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_LightDistanceAttenuations[additionalLightIndex],
out m_LightSpotDirections[additionalLightIndex],
out m_LightSpotAttenuations[additionalLightIndex]);
additionalLightIndex++;
}
m_CullResults.SetLightIndexMap(perObjectLightIndexMap);
cmd.SetGlobalVector(PerCameraBuffer._AdditionalLightCount, new Vector4(lightData.pixelAdditionalLightsCount,
lightData.totalAdditionalLightsCount, 0.0f, 0.0f));
m_CullResults.SetLightIndexMap(perObjectLightIndexMap);
else
{
cmd.SetGlobalVector(PerCameraBuffer._AdditionalLightCount, Vector4.zero);
cmd.SetGlobalVector(PerCameraBuffer._AdditionalLightCount, new Vector4(lightData.pixelAdditionalLightsCount,
lightData.totalAdditionalLightsCount, 0.0f, 0.0f));
// Clear to default all light cosntant data
for (int i = 0; i < kMaxVisibleLights; ++i)
InitializeLightConstants(lights, -1, out m_LightPositions[additionalLightIndex],
out m_LightColors[additionalLightIndex],
out m_LightDistanceAttenuations[additionalLightIndex],
out m_LightSpotDirections[additionalLightIndex],
out m_LightSpotAttenuations[additionalLightIndex]);
}
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightPosition, m_LightPositions);
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightColor, m_LightColors);
cmd.SetGlobalVectorArray(PerCameraBuffer._AdditionalLightDistanceAttenuation, m_LightDistanceAttenuations);

// Scale bias by cascade's world space depth range.
// Directional shadow lights have orthogonal projection.
// proj.m22 = -2 / (far - near) since the projection's depth range is [-1.0, 1.0]
// Therefore we scale it by 0.5. We keep the negative sign and only flip it in case z is
// reversed.
// In order to be correct we should multiply bias by 0.5 but this introducing aliasing along cascades more visible.
bias = light.shadowBias * proj.m22 * 0.5f * sign;
bias = light.shadowBias * proj.m22 * sign;
// Currently only square POT cascades resolutions are used.
// We scale normalBias

private void SetupShadowReceiverConstants(CommandBuffer cmd, VisibleLight shadowLight)
{
Light light = shadowLight.light;
float shadowResolution = m_ShadowSlices[0].shadowResolution;
int cascadeCount = m_ShadowCasterCascadesCount;
for (int i = 0; i < kMaxCascades; ++i)

noOpShadowMatrix.m33 = (SystemInfo.usesReversedZBuffer) ? 1.0f : 0.0f;
m_ShadowMatrices[kMaxCascades] = noOpShadowMatrix;
float invShadowResolution = 0.5f / shadowResolution;
cmd.SetGlobalMatrixArray("_WorldToShadow", m_ShadowMatrices);
cmd.SetGlobalVector("_ShadowData", new Vector4(light.shadowStrength, 0.0f, 0.0f, 0.0f));
cmd.SetGlobalVectorArray("_DirShadowSplitSpheres", m_DirectionalShadowSplitDistances);
cmd.SetGlobalVector("_DirShadowSplitSphereRadii", m_DirectionalShadowSplitRadii);
cmd.SetGlobalVector("_ShadowOffset0", new Vector4(-invShadowResolution, -invShadowResolution, 0.0f, 0.0f));
cmd.SetGlobalVector("_ShadowOffset1", new Vector4(invShadowResolution, -invShadowResolution, 0.0f, 0.0f));
cmd.SetGlobalVector("_ShadowOffset2", new Vector4(-invShadowResolution, invShadowResolution, 0.0f, 0.0f));
cmd.SetGlobalVector("_ShadowOffset3", new Vector4(invShadowResolution, invShadowResolution, 0.0f, 0.0f));
float invShadowResolution = 1.0f / m_Asset.ShadowAtlasResolution;
float invHalfShadowResolution = 0.5f * invShadowResolution;
cmd.SetGlobalMatrixArray(ShadowConstantBuffer._WorldToShadow, m_ShadowMatrices);
cmd.SetGlobalVector(ShadowConstantBuffer._ShadowData, new Vector4(light.shadowStrength, 0.0f, 0.0f, 0.0f));
cmd.SetGlobalVectorArray(ShadowConstantBuffer._DirShadowSplitSpheres, m_DirectionalShadowSplitDistances);
cmd.SetGlobalVector(ShadowConstantBuffer._DirShadowSplitSphereRadii, m_DirectionalShadowSplitRadii);
cmd.SetGlobalVector(ShadowConstantBuffer._ShadowOffset0, new Vector4(-invHalfShadowResolution, -invHalfShadowResolution, 0.0f, 0.0f));
cmd.SetGlobalVector(ShadowConstantBuffer._ShadowOffset1, new Vector4( invHalfShadowResolution, -invHalfShadowResolution, 0.0f, 0.0f));
cmd.SetGlobalVector(ShadowConstantBuffer._ShadowOffset2, new Vector4(-invHalfShadowResolution, invHalfShadowResolution, 0.0f, 0.0f));
cmd.SetGlobalVector(ShadowConstantBuffer._ShadowOffset3, new Vector4( invHalfShadowResolution, invHalfShadowResolution, 0.0f, 0.0f));
cmd.SetGlobalVector(ShadowConstantBuffer._ShadowmapSize, new Vector4(invShadowResolution, invShadowResolution, m_Asset.ShadowAtlasResolution, m_Asset.ShadowAtlasResolution));
}
private void SetShaderKeywords(CommandBuffer cmd, ref LightData lightData, List<VisibleLight> visibleLights)

11
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Input.hlsl


#define MAX_VISIBLE_LIGHTS 16
struct InputData
{
float3 positionWS;
half3 normalWS;
half3 viewDirectionWS;
float4 shadowCoord;
half fogCoord;
half3 vertexLighting;
half3 bakedGI;
};
///////////////////////////////////////////////////////////////////////////////
// Constant Buffers //
///////////////////////////////////////////////////////////////////////////////

4
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/InputSurface.hlsl


half3 specular;
half metallic;
half smoothness;
half3 normal;
half3 normalTS;
half3 emission;
half occlusion;
half alpha;

#endif
outSurfaceData.smoothness = specGloss.a;
outSurfaceData.normal = Normal(uv);
outSurfaceData.normalTS = Normal(uv);
outSurfaceData.occlusion = Occlusion(uv);
outSurfaceData.emission = Emission(uv);
outSurfaceData.alpha = Alpha(albedoAlpha.a);

118
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Lighting.hlsl


half3 direction;
half3 color;
half attenuation;
half realtimeAttenuation;
half subtractiveModeAttenuation;
};
///////////////////////////////////////////////////////////////////////////////

return atten * atten;
}
half4 GetLightDirectionAndRealtimeAttenuation(LightInput lightInput, float3 positionWS)
half4 GetLightDirectionAndAttenuation(LightInput lightInput, float3 positionWS)
{
half4 directionAndAttenuation;
float3 posToLightVec = lightInput.position.xyz - positionWS * lightInput.position.w;

return directionAndAttenuation;
}
half4 GetMainLightDirectionAndRealtimeAttenuation(LightInput lightInput, float3 positionWS)
half4 GetMainLightDirectionAndAttenuation(LightInput lightInput, float3 positionWS)
{
half4 directionAndAttenuation;

directionAndAttenuation = GetLightDirectionAndRealtimeAttenuation(lightInput, positionWS);
directionAndAttenuation = GetLightDirectionAndAttenuation(lightInput, positionWS);
// Cookies and shadows are only computed for main light
// Cookies are only computed for main light
directionAndAttenuation.w *= RealtimeShadowAttenuation(positionWS);
return directionAndAttenuation;
}

lightInput.spotDirection = _MainLightSpotDir;
lightInput.spotAttenuation = _MainLightSpotAttenuation;
half4 directionAndRealtimeAttenuation = GetMainLightDirectionAndRealtimeAttenuation(lightInput, positionWS);
half4 directionAndRealtimeAttenuation = GetMainLightDirectionAndAttenuation(lightInput, positionWS);
light.realtimeAttenuation = directionAndRealtimeAttenuation.w;
light.attenuation = MixRealtimeAndBakedOcclusion(light.realtimeAttenuation, lightInput.distanceAttenuation.w);
light.attenuation = directionAndRealtimeAttenuation.w;
light.subtractiveModeAttenuation = lightInput.distanceAttenuation.w;
light.color = lightInput.color;
return light;

lightInput.spotDirection = _AdditionalLightSpotDir[lightIndex];
lightInput.spotAttenuation = _AdditionalLightSpotAttenuation[lightIndex];
half4 directionAndRealtimeAttenuation = GetLightDirectionAndRealtimeAttenuation(lightInput, positionWS);
half4 directionAndRealtimeAttenuation = GetLightDirectionAndAttenuation(lightInput, positionWS);
light.realtimeAttenuation = directionAndRealtimeAttenuation.w;
light.attenuation = MixRealtimeAndBakedOcclusion(light.realtimeAttenuation, lightInput.distanceAttenuation.w);
light.attenuation = directionAndRealtimeAttenuation.w;
light.subtractiveModeAttenuation = lightInput.distanceAttenuation.w;
light.color = lightInput.color;
return light;

half3 SubtractDirectMainLightFromLightmap(Light mainLight, half3 normalWS, half3 bakedGI)
{
#if defined(_MAIN_LIGHT_DIRECTIONAL) && defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON) && defined(_SHADOWS_ENABLED)
// Let's try to make realtime shadows work on a surface, which already contains
// baked lighting and shadowing from the main sun light.
// Summary:

// 1) Gives good estimate of illumination as if light would've been shadowed during the bake.
// Preserves bounce and other baked lights
// No shadows on the geometry facing away from the light
half shadowStrength = _ShadowData.x;
half shadowStrength = GetShadowStrength();
half3 estimatedLightContributionMaskedByInverseOfShadow = lambert * (1.0 - mainLight.realtimeAttenuation);
half3 estimatedLightContributionMaskedByInverseOfShadow = lambert * (1.0 - mainLight.attenuation);
half3 subtractedLightmap = bakedGI - estimatedLightContributionMaskedByInverseOfShadow;
// 2) Allows user to define overall ambient of the scene and control situation when realtime shadow becomes too dark.

// 3) Pick darkest color
return min(bakedGI, realtimeShadow);
#endif
return bakedGI;
}
half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS)

return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
}
void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI, half4 shadowMask)
{
#if defined(_MAIN_LIGHT_DIRECTIONAL) && defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON) && defined(_SHADOWS_ENABLED)
bakedGI = SubtractDirectMainLightFromLightmap(light, normalWS, bakedGI);
#endif
#if defined(LIGHTMAP_ON)
#if defined(_MIXED_LIGHTING_SHADOWMASK)
// TODO:
#elif defined(_MIXED_LIGHTING_SUBTRACTIVE)
// Subtractive Light mode has direct light contribution baked into lightmap for mixed lights.
// We need to remove direct realtime contribution from mixed lights
// subtractiveModeBakedOcclusion is set 0.0 if this light occlusion was baked in the lightmap, 1.0 otherwise.
light.attenuation *= light.subtractiveModeAttenuation;
#endif
#endif
}
///////////////////////////////////////////////////////////////////////////////
// Lighting Functions //
///////////////////////////////////////////////////////////////////////////////

{
Light light = GetLight(lightIter, positionWS);
half3 lightColor = light.color * light.realtimeAttenuation;
half3 lightColor = light.color * light.attenuation;
vertexLightColor += LightingLambert(lightColor, light.direction, normalWS);
}
#endif

// Fragment Functions //
// Used by ShaderGraph and others builtin renderers //
///////////////////////////////////////////////////////////////////////////////
half4 LightweightFragmentPBR(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half3 bakedGI, half3 vertexLighting, half3 albedo, half metallic, half3 specular,
half4 LightweightFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
Light mainLight = GetMainLight(positionWS);
bakedGI = SubtractDirectMainLightFromLightmap(mainLight, normalWS, bakedGI);
half3 color = GlobalIllumination(brdfData, bakedGI, occlusion, normalWS, viewDirectionWS);
color += LightingPhysicallyBased(brdfData, mainLight, normalWS, viewDirectionWS);
Light mainLight = GetMainLight(inputData.positionWS);
mainLight.attenuation *= RealtimeShadowAttenuation(inputData.positionWS, inputData.shadowCoord);
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
half3 color = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, inputData.normalWS, inputData.viewDirectionWS);
color += LightingPhysicallyBased(brdfData, mainLight, inputData.normalWS, inputData.viewDirectionWS);
Light light = GetLight(i, positionWS);
color += LightingPhysicallyBased(brdfData, light, normalWS, viewDirectionWS);
Light light = GetLight(i, inputData.positionWS);
color += LightingPhysicallyBased(brdfData, light, inputData.normalWS, inputData.viewDirectionWS);
color += vertexLighting * brdfData.diffuse;
color += inputData.vertexLighting * brdfData.diffuse;
half4 LightweightFragmentLambert(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half fogFactor, half3 bakedGI, half3 diffuse, half3 emission, half alpha)
half4 LightweightFragmentBlinnPhong(InputData inputData, half3 diffuse, half4 specularGloss, half shininess, half3 emission, half alpha)
Light mainLight = GetMainLight(positionWS);
half3 indirectDiffuse = SubtractDirectMainLightFromLightmap(mainLight, normalWS, bakedGI);
half3 lambert = LightingLambert(mainLight.color, mainLight.direction, normalWS);
half3 diffuseColor = lambert * mainLight.attenuation + indirectDiffuse;
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = GetPixelLightCount();
for (int i = 0; i < pixelLightCount; ++i)
{
Light light = GetLight(i, positionWS);
half3 attenuatedLightColor = light.color * light.attenuation;
diffuseColor += LightingLambert(attenuatedLightColor, light.direction, normalWS);
}
#endif
half3 finalColor = diffuseColor * diffuse + emission;
ApplyFog(finalColor, fogFactor);
return half4(finalColor, alpha);
}
half4 LightweightFragmentBlinnPhong(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half fogFactor, half3 bakedGI, half3 diffuse, half4 specularGloss, half shininess, half3 emission, half alpha)
{
Light mainLight = GetMainLight(positionWS);
half3 indirectDiffuse = SubtractDirectMainLightFromLightmap(mainLight, normalWS, bakedGI);
Light mainLight = GetMainLight(inputData.positionWS);
mainLight.attenuation *= RealtimeShadowAttenuation(inputData.positionWS, inputData.shadowCoord);
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
half3 diffuseColor = indirectDiffuse + LightingLambert(attenuatedLightColor, mainLight.direction, normalWS);
half3 specularColor = LightingSpecular(attenuatedLightColor, mainLight.direction, normalWS, viewDirectionWS, specularGloss, shininess);
half3 diffuseColor = inputData.bakedGI + LightingLambert(attenuatedLightColor, mainLight.direction, inputData.normalWS);
half3 specularColor = LightingSpecular(attenuatedLightColor, mainLight.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, shininess);
Light light = GetLight(i, positionWS);
Light light = GetLight(i, inputData.positionWS);
diffuseColor += LightingLambert(attenuatedLightColor, light.direction, normalWS);
specularColor += LightingSpecular(attenuatedLightColor, light.direction, normalWS, viewDirectionWS, specularGloss, shininess);
diffuseColor += LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
specularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, shininess);
finalColor += inputData.vertexLighting * diffuse;
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
#endif
ApplyFog(finalColor, fogFactor);
ApplyFog(finalColor, inputData.fogCoord);
return half4(finalColor, alpha);
}
#endif

82
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassLit.hlsl


float3 posWS : TEXCOORD2;
half3 normal : TEXCOORD3;
#if _NORMALMAP
#ifdef _NORMALMAP
half3 tangent : TEXCOORD4;
half3 binormal : TEXCOORD5;
#endif

#ifdef _SHADOWS_ENABLED
float4 shadowCoord : TEXCOORD8;
#endif
void InitializeInputData(LightweightVertexOutput IN, half3 normalTS, out InputData inputData)
{
inputData.positionWS = IN.posWS.xyz;
#ifdef _NORMALMAP
inputData.normalWS = TangentToWorldNormal(normalTS, IN.tangent, IN.binormal, IN.normal);
#else
inputData.normalWS = normalize(IN.normal);
#endif
#ifdef SHADER_API_MOBILE
// viewDirection should be normalized here, but we avoid doing it as it's close enough and we save some ALU.
inputData.viewDirectionWS = IN.viewDir;
#else
inputData.viewDirectionWS = normalize(IN.viewDir);
#endif
#ifdef _SHADOWS_ENABLED
inputData.shadowCoord = IN.shadowCoord;
#else
inputData.shadowCoord = float4(0, 0, 0, 0);
#endif
inputData.fogCoord = IN.fogFactorAndVertexLight.x;
inputData.vertexLighting = IN.fogFactorAndVertexLight.yzw;
inputData.bakedGI = SampleGI(IN.lightmapUVOrVertexSH, inputData.normalWS);
}
///////////////////////////////////////////////////////////////////////////////
// Vertex and Fragment functions //
///////////////////////////////////////////////////////////////////////////////

half fogFactor = ComputeFogFactor(o.clipPos.z);
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
#if defined(_SHADOWS_ENABLED) && !defined(_SHADOWS_CASCADE)
o.shadowCoord = ComputeShadowCoord(o.posWS.xyz);
#endif
return o;
}

SurfaceData surfaceData;
InitializeStandardLitSurfaceData(IN.uv, surfaceData);
#if _NORMALMAP
half3 normalWS = TangentToWorldNormal(surfaceData.normal, IN.tangent, IN.binormal, IN.normal);
#else
half3 normalWS = normalize(IN.normal);
#endif
InputData inputData;
InitializeInputData(IN, surfaceData.normalTS, inputData);
half3 indirectDiffuse = SampleGI(IN.lightmapUVOrVertexSH, normalWS);
float fogFactor = IN.fogFactorAndVertexLight.x;
half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha);
// viewDirection should be normalized here, but we avoid doing it as it's close enough and we save some ALU.
half4 color = LightweightFragmentPBR(IN.posWS.xyz, normalWS, IN.viewDir, indirectDiffuse, IN.fogFactorAndVertexLight.yzw, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha);
ApplyFog(color.rgb, fogFactor);
ApplyFog(color.rgb, inputData.fogCoord);
return color;
}

UNITY_SETUP_INSTANCE_ID(IN);
float2 uv = IN.uv;
half4 diffuseAlpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
half3 diffuse = diffuseAlpha.rgb * _Color.rgb;

AlphaDiscard(alpha, _Cutoff);
#if _NORMALMAP
half3 normalTangent = Normal(uv);
half3 normalWS = TangentToWorldNormal(normalTangent, IN.tangent, IN.binormal, IN.normal);
#ifdef _NORMALMAP
half3 normalTS = Normal(uv);
half3 normalWS = normalize(IN.normal);
half3 normalTS = half3(0, 0, 1);
half4 specularGloss = SpecularGloss(uv, diffuseAlpha.a);
half shininess = _Shininess * 128.0h;
half3 viewDirectionWS = SafeNormalize(IN.viewDir.xyz);
float3 positionWS = IN.posWS.xyz;
half3 diffuseGI = SampleGI(IN.lightmapUVOrVertexSH, normalWS);
#if _VERTEX_LIGHTS
diffuseGI += IN.fogFactorAndVertexLight.yzw;
#endif
half shininess = _Shininess * 128.0h;
half fogFactor = IN.fogFactorAndVertexLight.x;
InputData inputData;
InitializeInputData(IN, normalTS, inputData);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
half4 specularGloss = SpecularGloss(uv, diffuseAlpha.a);
return LightweightFragmentBlinnPhong(positionWS, normalWS, viewDirectionWS, fogFactor, diffuseGI, diffuse, specularGloss, shininess, emission, alpha);
#else
return LightweightFragmentLambert(positionWS, normalWS, viewDirectionWS, fogFactor, diffuseGI, diffuse, emission, alpha);
#endif
return LightweightFragmentBlinnPhong(inputData, diffuse, specularGloss, shininess, emission, alpha);
};
#endif

22
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Particles.hlsl


#endif
#if defined(_NORMALMAP)
float3 normal = normalize(UnpackNormalScale(readTexture(_BumpMap, sampler_BumpMap, IN), _BumpScale));
half3 normalTS = normalize(UnpackNormalScale(readTexture(_BumpMap, sampler_BumpMap, IN), _BumpScale));
float3 normal = float3(0, 0, 1);
half3 normalTS = float3(0, 0, 1);
#endif
#if defined(_EMISSION)

surfaceData.albedo = albedo.rbg;
surfaceData.specular = half3(0, 0, 0);
surfaceData.normal = normal;
surfaceData.normalTS = normalTS;
surfaceData.emission = emission * _EmissionColor.rgb;
surfaceData.metallic = metallicGloss.r;
surfaceData.smoothness = metallicGloss.g;

#if defined(_ALPHATEST_ON)
clip(surfaceData.alpha - _Cutoff + 0.0001);
#endif
}
void InitializeInputData(VertexOutputLit IN, half3 normalTS, out InputData input)
{
input.positionWS = IN.posWS.xyz;
#if _NORMALMAP
input.normalWS = TangentToWorldNormal(normalTS, IN.tangent, IN.binormal, IN.normal);
#else
input.normalWS = normalize(IN.normal);
#endif
input.viewDirectionWS = SafeNormalize(GetCameraPositionWS() - input.positionWS);
input.shadowCoord = float4(0, 0, 0, 0);
input.fogCoord = IN.posWS.w;
input.vertexLighting = half3(0, 0, 0);
input.bakedGI = half3(0, 0, 0);
}

80
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Shadows.hlsl


#define LIGHTWEIGHT_SHADOWS_INCLUDED
#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "CoreRP/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl"
#define MAX_SHADOW_CASCADES 4

// Last cascade is initialized with a no-op matrix. It always transforms
// shadow coord to half(0, 0, NEAR_PLANE). We use this trick to avoid
// branching since ComputeCascadeIndex can return cascade index = MAX_SHADOW_CASCADES
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES + 1];
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES];
float4 _DirShadowSplitSphereRadii;
half4 _ShadowOffset0;
half4 _ShadowOffset1;
half4 _ShadowOffset2;
half4 _ShadowOffset3;
half4 _ShadowData; // (x: shadowStrength)
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES + 1];
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES];
float4 _DirShadowSplitSphereRadii;
half4 _ShadowOffset0;
half4 _ShadowOffset1;
half4 _ShadowOffset2;
half4 _ShadowOffset3;
half4 _ShadowData; // (x: shadowStrength)
float4 _ShadowmapSize; // (xy: 1/width and 1/height, zw: width and height)
CBUFFER_END
inline half SampleShadowmap(float4 shadowCoord)

#endif
half attenuation;
#ifdef SHADER_API_MOBILE
// 4-tap hardware comparison
half4 attenuation4;
attenuation4.x = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, shadowCoord.xyz + _ShadowOffset0.xyz);

half attenuation = dot(attenuation4, 0.25);
attenuation = dot(attenuation4, 0.25);
#else
real fetchesWeights[9];
real2 fetchesUV[9];
SampleShadow_ComputeSamples_Tent_5x5(_ShadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV);
attenuation = fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[0].xy, shadowCoord.z));
attenuation += fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[1].xy, shadowCoord.z));
attenuation += fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[2].xy, shadowCoord.z));
attenuation += fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[3].xy, shadowCoord.z));
attenuation += fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[4].xy, shadowCoord.z));
attenuation += fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[5].xy, shadowCoord.z));
attenuation += fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[6].xy, shadowCoord.z));
attenuation += fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[7].xy, shadowCoord.z));
attenuation += fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, real3(fetchesUV[8].xy, shadowCoord.z));
#endif
half attenuation = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, shadowCoord.xyz);
attenuation = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, shadowCoord.xyz);
#endif
// Apply shadow strength

return (shadowCoord.x <= 0 || shadowCoord.x >= 1 || shadowCoord.y <= 0 || shadowCoord.y >= 1 || shadowCoord.z >= 1) ? 1.0 : attenuation;
}
inline half ComputeCascadeIndex(float3 wpos)
inline half ComputeCascadeIndex(float3 positionWS)
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;
float3 fromCenter0 = positionWS.xyz - _DirShadowSplitSpheres[0].xyz;
float3 fromCenter1 = positionWS.xyz - _DirShadowSplitSpheres[1].xyz;
float3 fromCenter2 = positionWS.xyz - _DirShadowSplitSpheres[2].xyz;
float3 fromCenter3 = positionWS.xyz - _DirShadowSplitSpheres[3].xyz;
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3));
half4 weights = half4(distances2 < _DirShadowSplitSphereRadii);

}
inline float4 ComputeShadowCoord(float3 positionWS, half cascadeIndex = 0)
float4 ComputeShadowCoord(float3 positionWS)
half cascadeIndex = ComputeCascadeIndex(positionWS);
return mul(_WorldToShadow[cascadeIndex], float4(positionWS, 1.0));
#endif

inline half RealtimeShadowAttenuation(float3 positionWS)
half GetShadowStrength()
{
return _ShadowData.x;
}
half RealtimeShadowAttenuation(float3 positionWS)
half cascadeIndex = ComputeCascadeIndex(positionWS);
float4 shadowCoord = ComputeShadowCoord(positionWS, cascadeIndex);
float4 shadowCoord = ComputeShadowCoord(positionWS);
half MixRealtimeAndBakedOcclusion(half realtimeAttenuation, half subtractiveModeBakedOcclusion, half4 shadowMaskModeBakedOcclusion = half4(0, 0, 0, 0))
half RealtimeShadowAttenuation(float3 positionWS, float4 shadowCoord)
#if defined(LIGHTMAP_ON)
#if defined(_MIXED_LIGHTING_SHADOWMASK)
// TODO:
#elif defined(_MIXED_LIGHTING_SUBTRACTIVE)
// Subtractive Light mode has direct light contribution baked into lightmap for mixed lights.
// We need to remove direct realtime contribution from mixed lights
// subtractiveModeBakedOcclusion is set 0.0 if this light occlusion was baked in the lightmap, 1.0 otherwise.
return realtimeAttenuation * subtractiveModeBakedOcclusion;
#if !defined(_SHADOWS_ENABLED)
return 1.0;
#ifdef _SHADOWS_CASCADE
shadowCoord = ComputeShadowCoord(positionWS);
return realtimeAttenuation;
return SampleShadowmap(shadowCoord);
}
#endif

1
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandard.shader


#pragma vertex LightweightVertexMeta
#pragma fragment LightweightFragmentMeta
#pragma shader_feature _SPECULAR_SETUP
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICSPECGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A

18
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardParticles.shader


SurfaceData surfaceData;
InitializeSurfaceData(IN, surfaceData);
float3 positionWS = IN.posWS.xyz;
half3 viewDirWS = SafeNormalize(GetCameraPositionWS() - positionWS);
half fogFactor = IN.posWS.w;
#if _NORMALMAP
half3 normalWS = TangentToWorldNormal(surfaceData.normal, IN.tangent, IN.binormal, IN.normal);
#else
half3 normalWS = normalize(IN.normal);
#endif
InputData inputData;
InitializeInputData(IN, surfaceData.normalTS, inputData);
half3 zero = half3(0.0, 0.0, 0.0);
half4 color = LightweightFragmentPBR(positionWS, normalWS, viewDirWS, /*indirectDiffuse*/ zero, /*vertex lighting*/ zero, surfaceData.albedo,
surfaceData.metallic, /* specularColor */ zero, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha);
ApplyFog(color.rgb, fogFactor);
half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo,
surfaceData.metallic, half3(0, 0, 0), surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha);
ApplyFog(color.rgb, inputData.fogCoord);
return color;
}

60
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardTerrain.shader


#endif
half4 fogFactorAndVertexLight : TEXCOORD6; // x: fogFactor, yzw: vertex light
float3 positionWS : TEXCOORD7;
#ifdef _SHADOWS_ENABLED
float4 shadowCoord : TEXCOORD8;
#endif
void InitializeInputData(VertexOutput IN, half3 normalTS, out InputData input)
{
input = (InputData)0;
input.positionWS = IN.positionWS;
#ifdef _TERRAIN_NORMAL_MAP
input.normalWS = TangentToWorldNormal(normalTS, IN.tangent, IN.binormal, IN.normal);
#else
input.normalWS = normalize(IN.normal);
#endif
input.viewDirectionWS = SafeNormalize(GetCameraPositionWS() - IN.positionWS);
#ifdef _SHADOWS_ENABLED
input.shadowCoord = IN.shadowCoord;
#endif
input.fogCoord = IN.fogFactorAndVertexLight.x;
#ifdef LIGHTMAP_ON
input.bakedGI = SampleLightmap(IN.uvControlAndLM.zw, input.normalWS);
#endif
}
void SplatmapMix(VertexOutput IN, half4 defaultAlpha, out half4 splat_control, out half weight, out half4 mixedDiffuse, inout half3 mixedNormal)
{

VertexOutput SplatmapVert(VertexInput v)
{
VertexOutput o;
VertexOutput o = (VertexOutput)0;
float3 positionWS = TransformObjectToWorld(v.vertex.xyz);
float4 clipPos = TransformWorldToHClip(positionWS);

o.fogFactorAndVertexLight.yzw = VertexLighting(positionWS, o.normal);
o.positionWS = positionWS;
o.clipPos = clipPos;
#if defined(_SHADOWS_ENABLED) && !defined(_SHADOWS_CASCADE)
o.shadowCoord = ComputeShadowCoord(o.positionWS.xyz);
#endif
return o;
}

half weight;
half4 mixedDiffuse;
half4 defaultSmoothness = half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3);
half3 normalTangent;
SplatmapMix(IN, defaultSmoothness, splat_control, weight, mixedDiffuse, normalTangent);
half3 normalTS;
SplatmapMix(IN, defaultSmoothness, splat_control, weight, mixedDiffuse, normalTS);
half3 albedo = mixedDiffuse.rgb;
half smoothness = mixedDiffuse.a;

#ifdef _TERRAIN_NORMAL_MAP
half3 normalWS = TangentToWorldNormal(normalTangent, IN.tangent, IN.binormal, IN.normal);
#else
half3 normalWS = normalize(IN.normal);
#endif
InputData inputData;
InitializeInputData(IN, normalTS, inputData);
half4 color = LightweightFragmentPBR(inputData, albedo, metallic, specular, smoothness, /* occlusion */ 1.0, /* emission */ half3(0, 0, 0), alpha);
half3 indirectDiffuse = half3(0, 0, 0);
#ifdef LIGHTMAP_ON
indirectDiffuse = SampleLightmap(IN.uvControlAndLM.zw, normalWS);
#endif
half3 viewDirectionWS = SafeNormalize(GetCameraPositionWS() - IN.positionWS);
half fogFactor = IN.fogFactorAndVertexLight.x;
half4 color = LightweightFragmentPBR(IN.positionWS, normalWS, viewDirectionWS, indirectDiffuse,
IN.fogFactorAndVertexLight.yzw, albedo, metallic, specular, smoothness, /* occlusion */ 1.0, /* emission */ half3(0, 0, 0), alpha);
ApplyFog(color.rgb, fogFactor);
ApplyFog(color.rgb, inputData.fogCoord);
return color;
}
ENDHLSL

5
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardUnlit.shader


}
SubShader
{
Tags { "RenderType" = "Opaque" "IgnoreProjectors" = "True" "RenderPipeline" = "LightweightPipe" }
Tags { "RenderType" = "Opaque" "IgnoreProjectors" = "True" "RenderPipeline" = "LightweightPipeline" }
LOD 100
Blend [_SrcBlend][_DstBlend]

#if _SAMPLE_GI
#if _NORMALMAP
half3 normalWS = TangentToWorldNormal(surfaceData.normal, IN.tangent, IN.binormal, IN.normal);
half3 normalWS = TangentToWorldNormal(surfaceData.normalTS, IN.tangent, IN.binormal, IN.normal);
#else
half3 normalWS = normalize(IN.normal);
#endif

ENDHLSL
}
}
FallBack "Hidden/InternalErrorShader"
CustomEditor "LightweightUnlitGUI"
}

4
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset


m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3}
m_Name: LightweightPipelineAsset
m_EditorClassIdentifier:
kAssetVersion: 1
kAssetVersion: 2
m_MaxPixelLights: 4
m_SupportsVertexLight: 0
m_RequireDepthTexture: 0

m_ShadowCascades: 2
m_Cascade2Split: 0.25
m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467}
m_DefaultShader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_ResourceAsset: {fileID: 11400000, guid: c8afc0a27fb8c0b4da18151c689a1082, type: 2}

3
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset.meta


fileFormatVersion: 2
guid: e6987eea1dd29074597d54ed91a54a26
timeCreated: 1489068733
licenseType: Pro
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:

65
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/LightingData.asset
文件差异内容过多而无法显示
查看文件

2
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/LightingData.asset.meta


fileFormatVersion: 2
guid: c1e3921e553ae4bdea5bd3521abb96e2
timeCreated: 1509632247
licenseType: Pro
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 25800000

999
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-0_comp_dir.png
文件差异内容过多而无法显示
查看文件

1001
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-0_comp_light.exr
文件差异内容过多而无法显示
查看文件

999
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-1_comp_dir.png
文件差异内容过多而无法显示
查看文件

1001
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/Lightmap-1_comp_light.exr
文件差异内容过多而无法显示
查看文件

1001
Tests/GraphicsTests/RenderPipeline/LightweightPipeline/Scenes/040_UpgradeScene/ReflectionProbe-0.exr
文件差异内容过多而无法显示
查看文件

244
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl


// ------------------------------------------------------------------
// PCF Filtering Tent Functions
// ------------------------------------------------------------------
// Assuming a isoceles right angled triangle of height "triangleHeight" (as drawn below).
// This function return the area of the triangle above the first texel.
//
// |\ <-- 45 degree slop isosceles right angled triangle
// | \
// ---- <-- length of this side is "triangleHeight"
// _ _ _ _ <-- texels
real SampleShadow_GetTriangleTexelArea(real triangleHeight)
{
return triangleHeight - 0.5;
}
// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
// This function return the area of the triangle above each of those texels.
// | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center
// / \ <-- 45 degree slop isosceles triangle (ie tent projected in 2D)
// / \
// _ _ _ _ <-- texels
// X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw)
void SampleShadow_GetTexelAreas_Tent_3x3(real offset, out real4 computedArea, out real4 computedAreaUncut)
{
// Compute the exterior areas
real offset01SquaredHalved = (offset + 0.5) * (offset + 0.5) * 0.5;
computedAreaUncut.x = computedArea.x = offset01SquaredHalved - offset;
computedAreaUncut.w = computedArea.w = offset01SquaredHalved;
// Compute the middle areas
// For Y : We find the area in Y of as if the left section of the isoceles triangle would
// intersect the axis between Y and Z (ie where offset = 0).
computedAreaUncut.y = SampleShadow_GetTriangleTexelArea(1.5 - offset);
// This area is superior to the one we are looking for if (offset < 0) thus we need to
// subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5).
real clampedOffsetLeft = min(offset,0);
real areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft;
computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle;
// We do the same for the Z but with the right part of the isoceles triangle
computedAreaUncut.z = SampleShadow_GetTriangleTexelArea(1.5 + offset);
real clampedOffsetRight = max(offset,0);
real areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight;
computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle;
}
// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
// This function return the weight of each texels area relative to the full triangle area.
void SampleShadow_GetTexelWeights_Tent_3x3(real offset, out real4 computedWeight)
{
real4 dummy;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedWeight, dummy);
computedWeight *= 0.44444;//0.44 == 1/(the triangle area)
}
// Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels.
// This function return the weight of each texels area relative to the full triangle area.
// / \
// _ _ _ _ _ _ <-- texels
// 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[])
void SampleShadow_GetTexelWeights_Tent_5x5(real offset, out real3 texelsWeightsA, out real3 texelsWeightsB)
{
// See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
real4 computedArea_From3texelTriangle;
real4 computedAreaUncut_From3texelTriangle;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
// Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
// the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel.
// 0.16 is 1/(the triangle area)
texelsWeightsA.x = 0.16 * (computedArea_From3texelTriangle.x);
texelsWeightsA.y = 0.16 * (computedAreaUncut_From3texelTriangle.y);
texelsWeightsA.z = 0.16 * (computedArea_From3texelTriangle.y + 1);
texelsWeightsB.x = 0.16 * (computedArea_From3texelTriangle.z + 1);
texelsWeightsB.y = 0.16 * (computedAreaUncut_From3texelTriangle.z);
texelsWeightsB.z = 0.16 * (computedArea_From3texelTriangle.w);
}
// Assuming a isoceles triangle of 3.5 texel height and 7 texels wide lying on 8 texels.
// This function return the weight of each texels area relative to the full triangle area.
// / \
// _ _ _ _ _ _ _ _ <-- texels
// 0 1 2 3 4 5 6 7 <-- computed area indices (in texelsWeights[])
void SampleShadow_GetTexelWeights_Tent_7x7(real offset, out real4 texelsWeightsA, out real4 texelsWeightsB)
{
// See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
real4 computedArea_From3texelTriangle;
real4 computedAreaUncut_From3texelTriangle;
SampleShadow_GetTexelAreas_Tent_3x3(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
// Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
// the 7 texel wide triangle can be seen as the 3 texel wide one but shifted up by two unit/texel.
// 0.081632 is 1/(the triangle area)
texelsWeightsA.x = 0.081632 * (computedArea_From3texelTriangle.x);
texelsWeightsA.y = 0.081632 * (computedAreaUncut_From3texelTriangle.y);
texelsWeightsA.z = 0.081632 * (computedAreaUncut_From3texelTriangle.y + 1);
texelsWeightsA.w = 0.081632 * (computedArea_From3texelTriangle.y + 2);
texelsWeightsB.x = 0.081632 * (computedArea_From3texelTriangle.z + 2);
texelsWeightsB.y = 0.081632 * (computedAreaUncut_From3texelTriangle.z + 1);
texelsWeightsB.z = 0.081632 * (computedAreaUncut_From3texelTriangle.z);
texelsWeightsB.w = 0.081632 * (computedArea_From3texelTriangle.w);
}
// 3x3 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_3x3(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[4], out real2 fetchesUV[4])
{
// tent base is 3x3 base thus covering from 9 to 12 texels, thus we need 4 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based
real4 texelsWeightsU, texelsWeightsV;
SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU);
SampleShadow_GetTexelWeights_Tent_3x3(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real2 fetchesWeightsU = texelsWeightsU.xz + texelsWeightsU.yw;
real2 fetchesWeightsV = texelsWeightsV.xz + texelsWeightsV.yw;
// move the PCF bilinear fetches to respect texels weights
real2 fetchesOffsetsU = texelsWeightsU.yw / fetchesWeightsU.xy + real2(-1.5,0.5);
real2 fetchesOffsetsV = texelsWeightsV.yw / fetchesWeightsV.xy + real2(-1.5,0.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[3] = fetchesWeightsU.y * fetchesWeightsV.y;
}
// 5x5 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_5x5(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[9], out real2 fetchesUV[9])
{
// tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
real3 texelsWeightsU_A, texelsWeightsU_B;
real3 texelsWeightsV_A, texelsWeightsV_B;
SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
SampleShadow_GetTexelWeights_Tent_5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real3 fetchesWeightsU = real3(texelsWeightsU_A.xz, texelsWeightsU_B.y) + real3(texelsWeightsU_A.y, texelsWeightsU_B.xz);
real3 fetchesWeightsV = real3(texelsWeightsV_A.xz, texelsWeightsV_B.y) + real3(texelsWeightsV_A.y, texelsWeightsV_B.xz);
// move the PCF bilinear fetches to respect texels weights
real3 fetchesOffsetsU = real3(texelsWeightsU_A.y, texelsWeightsU_B.xz) / fetchesWeightsU.xyz + real3(-2.5,-0.5,1.5);
real3 fetchesOffsetsV = real3(texelsWeightsV_A.y, texelsWeightsV_B.xz) / fetchesWeightsV.xyz + real3(-2.5,-0.5,1.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xxx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yyy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
fetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y;
fetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y;
fetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z;
fetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z;
fetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z;
}
// 7x7 Tent filter (45 degree sloped triangles in U and V)
void SampleShadow_ComputeSamples_Tent_7x7(real4 shadowMapTexture_TexelSize, real2 coord, out real fetchesWeights[16], out real2 fetchesUV[16])
{
// tent base is 7x7 base thus covering from 49 to 64 texels, thus we need 16 bilinear PCF fetches
real2 tentCenterInTexelSpace = coord.xy * shadowMapTexture_TexelSize.zw;
real2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
real2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
real4 texelsWeightsU_A, texelsWeightsU_B;
real4 texelsWeightsV_A, texelsWeightsV_B;
SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
SampleShadow_GetTexelWeights_Tent_7x7(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
real4 fetchesWeightsU = real4(texelsWeightsU_A.xz, texelsWeightsU_B.xz) + real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw);
real4 fetchesWeightsV = real4(texelsWeightsV_A.xz, texelsWeightsV_B.xz) + real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw);
// move the PCF bilinear fetches to respect texels weights
real4 fetchesOffsetsU = real4(texelsWeightsU_A.yw, texelsWeightsU_B.yw) / fetchesWeightsU.xyzw + real4(-3.5,-1.5,0.5,2.5);
real4 fetchesOffsetsV = real4(texelsWeightsV_A.yw, texelsWeightsV_B.yw) / fetchesWeightsV.xyzw + real4(-3.5,-1.5,0.5,2.5);
fetchesOffsetsU *= shadowMapTexture_TexelSize.xxxx;
fetchesOffsetsV *= shadowMapTexture_TexelSize.yyyy;
real2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTexture_TexelSize.xy;
fetchesUV[0] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.x);
fetchesUV[1] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.x);
fetchesUV[2] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.x);
fetchesUV[3] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.x);
fetchesUV[4] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.y);
fetchesUV[5] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.y);
fetchesUV[6] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.y);
fetchesUV[7] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.y);
fetchesUV[8] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.z);
fetchesUV[9] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.z);
fetchesUV[10] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.z);
fetchesUV[11] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.z);
fetchesUV[12] = bilinearFetchOrigin + real2(fetchesOffsetsU.x, fetchesOffsetsV.w);
fetchesUV[13] = bilinearFetchOrigin + real2(fetchesOffsetsU.y, fetchesOffsetsV.w);
fetchesUV[14] = bilinearFetchOrigin + real2(fetchesOffsetsU.z, fetchesOffsetsV.w);
fetchesUV[15] = bilinearFetchOrigin + real2(fetchesOffsetsU.w, fetchesOffsetsV.w);
fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x;
fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x;
fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x;
fetchesWeights[3] = fetchesWeightsU.w * fetchesWeightsV.x;
fetchesWeights[4] = fetchesWeightsU.x * fetchesWeightsV.y;
fetchesWeights[5] = fetchesWeightsU.y * fetchesWeightsV.y;
fetchesWeights[6] = fetchesWeightsU.z * fetchesWeightsV.y;
fetchesWeights[7] = fetchesWeightsU.w * fetchesWeightsV.y;
fetchesWeights[8] = fetchesWeightsU.x * fetchesWeightsV.z;
fetchesWeights[9] = fetchesWeightsU.y * fetchesWeightsV.z;
fetchesWeights[10] = fetchesWeightsU.z * fetchesWeightsV.z;
fetchesWeights[11] = fetchesWeightsU.w * fetchesWeightsV.z;
fetchesWeights[12] = fetchesWeightsU.x * fetchesWeightsV.w;
fetchesWeights[13] = fetchesWeightsU.y * fetchesWeightsV.w;
fetchesWeights[14] = fetchesWeightsU.z * fetchesWeightsV.w;
fetchesWeights[15] = fetchesWeightsU.w * fetchesWeightsV.w;
}

9
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl.meta


fileFormatVersion: 2
guid: 6ff912bb23fcd5b468dd2e5c37addac3
timeCreated: 1491321444
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

/ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightUnlit.shader.meta → /ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardUnlit.shader.meta

/ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightUnlit.shader → /ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardUnlit.shader

正在加载...
取消
保存