浏览代码

Refactor transmittance from light space.

/projects-TheLastStand
John Parsaie 6 年前
当前提交
b65915e1
共有 16 个文件被更改,包括 1796 次插入435 次删除
  1. 850
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/ShaderGUI/LightweightSubsurfaceGUI.cs
  2. 2
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassLit.hlsl
  3. 23
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/Lighting.hlsl
  4. 7
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/LightweightPassLit.hlsl
  5. 4
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/LightweightSubsurface.shader
  6. 8
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Foliage.meta
  7. 8
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair.meta
  8. 189
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/InputSurface.hlsl
  9. 9
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/InputSurface.hlsl.meta
  10. 714
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl
  11. 9
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl.meta
  12. 224
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader
  13. 9
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader.meta
  14. 166
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl
  15. 9
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl.meta

850
ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/ShaderGUI/LightweightSubsurfaceGUI.cs


using System;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.LightweightPipeline;
namespace UnityEditor
{
internal class LightweightSubsurfaceGUI : LightweightShaderGUI
{
public enum WorkflowMode
{
Specular = 0,
Metallic
}
public enum SmoothnessMapChannel
{
SpecularMetallicAlpha,
AlbedoAlpha,
}
private static class Styles
{
public static GUIContent twoSidedText = new GUIContent("Two Sided", "Render front and back faces");
public static GUIContent alphaClipText = new GUIContent("Alpha Clip", "Enable Alpha Clip");
public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
public static GUIContent clipThresholdText = new GUIContent("Clip Threshold", "Threshold for alpha clip");
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 occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
public static GUIContent emissionText = new GUIContent("Color", "Emission (RGB)");
public static GUIContent bumpScaleNotSupported = new GUIContent("Bump scale is not supported on mobile platforms");
public static GUIContent fixNow = new GUIContent("Fix now");
//Subsurface
public static GUIContent subsurfaceAreaText = new GUIContent("Subsurface Scattering", "");
public static GUIContent diffusionProfileText = new GUIContent("Diffusion profile", "A profile determines the shape of the SSS/transmission filter.");
public static GUIContent curvatureText = new GUIContent("Curvature", "");
public static GUIContent thicknessText = new GUIContent("Thickness", "");
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 surfaceType = "Surface Type";
public static string blendingMode = "Blending Mode";
public static string advancedText = "Advanced Options";
public static readonly string[] workflowNames = Enum.GetNames(typeof(WorkflowMode));
public static readonly string[] surfaceNames = Enum.GetNames(typeof(SurfaceType));
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"};
}
private MaterialProperty workflowMode;
private MaterialProperty surfaceType;
private MaterialProperty blendMode;
private MaterialProperty culling;
private MaterialProperty alphaClip;
private MaterialProperty albedoColor;
private MaterialProperty albedoMap;
private MaterialProperty alphaThreshold;
private MaterialProperty smoothness;
private MaterialProperty smoothnessScale;
private MaterialProperty smoothnessMapChannel;
private MaterialProperty metallic;
private MaterialProperty specColor;
private MaterialProperty metallicGlossMap;
private MaterialProperty specGlossMap;
private MaterialProperty highlights;
private MaterialProperty reflections;
private MaterialProperty bumpScale;
private MaterialProperty bumpMap;
private MaterialProperty occlusionStrength;
private MaterialProperty occlusionMap;
private MaterialProperty emissionColorForRendering;
private MaterialProperty emissionMap;
//Subsurface
private MaterialProperty diffusionProfileID;
private MaterialProperty curvature;
private MaterialProperty thickness;
public override void FindProperties(MaterialProperty[] properties)
{
workflowMode = FindProperty("_WorkflowMode", properties);
surfaceType = FindProperty("_Surface", properties);
blendMode = FindProperty("_Blend", properties);
culling = FindProperty("_Cull", properties);
alphaClip = FindProperty("_AlphaClip", properties);
albedoColor = FindProperty("_Color", properties);
albedoMap = FindProperty("_MainTex", properties);
alphaThreshold = FindProperty("_Cutoff", properties);
smoothness = FindProperty("_Glossiness", properties);
smoothnessScale = FindProperty("_GlossMapScale", properties, false);
smoothnessMapChannel = FindProperty("_SmoothnessTextureChannel", properties, false);
metallic = FindProperty("_Metallic", properties);
specColor = FindProperty("_SpecColor", properties);
metallicGlossMap = FindProperty("_MetallicGlossMap", properties);
specGlossMap = FindProperty("_SpecGlossMap", properties);
highlights = FindProperty("_SpecularHighlights", properties);
reflections = FindProperty("_GlossyReflections", properties);
bumpScale = FindProperty("_BumpScale", properties);
bumpMap = FindProperty("_BumpMap", properties);
occlusionStrength = FindProperty("_OcclusionStrength", properties);
occlusionMap = FindProperty("_OcclusionMap", properties);
emissionColorForRendering = FindProperty("_EmissionColor", properties);
emissionMap = FindProperty("_EmissionMap", properties);
//Subsurface
diffusionProfileID = FindProperty("_DiffusionProfile", properties);
curvature = FindProperty("_Curvature", properties);
thickness = FindProperty("_Thickness", properties);
}
public override void MaterialChanged(Material material)
{
material.shaderKeywords = null;
SetupMaterialBlendMode(material);
SetMaterialKeywords(material);
}
public override 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.surfaceType, surfaceType, Styles.surfaceNames);
if ((SurfaceType)material.GetFloat("_Surface") == SurfaceType.Transparent)
DoPopup(Styles.blendingMode, blendMode, Styles.blendNames);
EditorGUI.BeginChangeCheck();
bool twoSidedEnabled = EditorGUILayout.Toggle(Styles.twoSidedText, culling.floatValue == 0);
if (EditorGUI.EndChangeCheck())
culling.floatValue = twoSidedEnabled ? 0 : 2;
EditorGUI.BeginChangeCheck();
bool alphaClipEnabled = EditorGUILayout.Toggle(Styles.alphaClipText, alphaClip.floatValue == 1);
if (EditorGUI.EndChangeCheck())
alphaClip.floatValue = alphaClipEnabled ? 1 : 0;
// 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);
EditorGUILayout.Space();
DoSubsurfaceArea();
}
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/"))
{
SetupMaterialBlendMode(material);
return;
}
SurfaceType surfaceType = SurfaceType.Opaque;
BlendMode blendMode = BlendMode.Alpha;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
surfaceType = SurfaceType.Opaque;
material.SetFloat("_AlphaClip", 1);
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
surfaceType = SurfaceType.Transparent;
blendMode = BlendMode.Alpha;
}
material.SetFloat("_Surface", (float)surfaceType);
material.SetFloat("_Blend", (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);
}
void DoAlbedoArea(Material material)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor);
if (material.GetFloat("_AlphaClip") == 1)
{
m_MaterialEditor.ShaderProperty(alphaThreshold, Styles.clipThresholdText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);
}
}
void DoNormalArea()
{
m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpScale : null);
if (bumpScale.floatValue != 1 && UnityEditorInternal.InternalEditorUtility.IsMobilePlatform(EditorUserBuildSettings.activeBuildTarget))
if (m_MaterialEditor.HelpBoxWithButton(Styles.bumpScaleNotSupported, Styles.fixNow))
bumpScale.floatValue = 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, 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;
}
void DoSubsurfaceArea()
{
GUILayout.Label(Styles.subsurfaceAreaText, EditorStyles.boldLabel);
var lwPipeine = RenderPipelineManager.currentPipeline as LightweightPipeline;
var diffusionProfileSettings = lwPipeine.DiffusionProfileSettings;
if(lwPipeine.IsInternalDiffusionProfile(diffusionProfileSettings))
{
EditorGUILayout.HelpBox("No diffusion profile Settings have been assigned to the render pipeline asset.", MessageType.Warning);
return;
}
// TODO: Optimize me
var profiles = diffusionProfileSettings.profiles;
var names = new GUIContent[profiles.Length + 1];
names[0] = new GUIContent("None");
var values = new int[names.Length];
values[0] = DiffusionProfileConstants.DIFFUSION_PROFILE_NEUTRAL_ID;
for (int i = 0; i < profiles.Length; i++)
{
names[i + 1] = new GUIContent(profiles[i].name);
values[i + 1] = i + 1;
}
using (var scope = new EditorGUI.ChangeCheckScope())
{
int profileID = (int)diffusionProfileID.floatValue;
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.PrefixLabel(Styles.diffusionProfileText);
using (new EditorGUILayout.HorizontalScope())
{
profileID = EditorGUILayout.IntPopup(profileID, names, values);
if (GUILayout.Button("Goto", EditorStyles.miniButton, GUILayout.Width(50f)))
Selection.activeObject = diffusionProfileSettings;
}
}
if (scope.changed)
diffusionProfileID.floatValue = profileID;
}
m_MaterialEditor.ShaderProperty(curvature, Styles.curvatureText);
m_MaterialEditor.ShaderProperty(thickness, Styles.thicknessText);
}
static SmoothnessMapChannel GetSmoothnessMapChannel(Material material)
{
int ch = (int)material.GetFloat("_SmoothnessTextureChannel");
if (ch == (int)SmoothnessMapChannel.AlbedoAlpha)
return SmoothnessMapChannel.AlbedoAlpha;
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");
CoreUtils.SetKeyword(material, "_SPECULAR_SETUP", isSpecularWorkFlow);
CoreUtils.SetKeyword(material, "_METALLICSPECGLOSSMAP", hasGlossMap);
CoreUtils.SetKeyword(material, "_SPECGLOSSMAP", hasGlossMap && isSpecularWorkFlow);
CoreUtils.SetKeyword(material, "_METALLICGLOSSMAP", hasGlossMap && !isSpecularWorkFlow);
CoreUtils.SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap"));
CoreUtils.SetKeyword(material, "_SPECULARHIGHLIGHTS_OFF", material.GetFloat("_SpecularHighlights") == 0.0f);
CoreUtils.SetKeyword(material, "_GLOSSYREFLECTIONS_OFF", material.GetFloat("_GlossyReflections") == 0.0f);
CoreUtils.SetKeyword(material, "_OCCLUSIONMAP", material.GetTexture("_OcclusionMap"));
CoreUtils.SetKeyword(material, "_PARALLAXMAP", material.GetTexture("_ParallaxMap"));
CoreUtils.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;
CoreUtils.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
if (material.HasProperty("_SmoothnessTextureChannel"))
{
CoreUtils.SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha);
}
}
}
}
using System;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.LightweightPipeline;
namespace UnityEditor
{
internal class LightweightSubsurfaceGUI : LightweightShaderGUI
{
public enum WorkflowMode
{
Specular = 0,
Metallic
}
public enum SmoothnessMapChannel
{
SpecularMetallicAlpha,
AlbedoAlpha,
}
private static class Styles
{
public static GUIContent twoSidedText = new GUIContent("Two Sided", "Render front and back faces");
public static GUIContent alphaClipText = new GUIContent("Alpha Clip", "Enable Alpha Clip");
public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
public static GUIContent clipThresholdText = new GUIContent("Clip Threshold", "Threshold for alpha clip");
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 occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
public static GUIContent emissionText = new GUIContent("Color", "Emission (RGB)");
public static GUIContent bumpScaleNotSupported = new GUIContent("Bump scale is not supported on mobile platforms");
public static GUIContent fixNow = new GUIContent("Fix now");
//Subsurface
public static GUIContent subsurfaceAreaText = new GUIContent("Subsurface Scattering", "");
public static GUIContent diffusionProfileText = new GUIContent("Diffusion profile", "A profile determines the shape of the SSS/transmission filter.");
public static GUIContent curvatureText = new GUIContent("Curvature", "");
public static GUIContent thicknessMapText = new GUIContent("Thickness Map", "");
public static GUIContent thicknessText = new GUIContent("Thickness", "");
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 surfaceType = "Surface Type";
public static string blendingMode = "Blending Mode";
public static string advancedText = "Advanced Options";
public static readonly string[] workflowNames = Enum.GetNames(typeof(WorkflowMode));
public static readonly string[] surfaceNames = Enum.GetNames(typeof(SurfaceType));
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"};
}
private MaterialProperty workflowMode;
private MaterialProperty surfaceType;
private MaterialProperty blendMode;
private MaterialProperty culling;
private MaterialProperty alphaClip;
private MaterialProperty albedoColor;
private MaterialProperty albedoMap;
private MaterialProperty alphaThreshold;
private MaterialProperty smoothness;
private MaterialProperty smoothnessScale;
private MaterialProperty smoothnessMapChannel;
private MaterialProperty metallic;
private MaterialProperty specColor;
private MaterialProperty metallicGlossMap;
private MaterialProperty specGlossMap;
private MaterialProperty highlights;
private MaterialProperty reflections;
private MaterialProperty bumpScale;
private MaterialProperty bumpMap;
private MaterialProperty occlusionStrength;
private MaterialProperty occlusionMap;
private MaterialProperty emissionColorForRendering;
private MaterialProperty emissionMap;
//Subsurface
private MaterialProperty diffusionProfileID;
private MaterialProperty curvature;
private MaterialProperty thicknessMap;
private MaterialProperty thickness;
public override void FindProperties(MaterialProperty[] properties)
{
workflowMode = FindProperty("_WorkflowMode", properties);
surfaceType = FindProperty("_Surface", properties);
blendMode = FindProperty("_Blend", properties);
culling = FindProperty("_Cull", properties);
alphaClip = FindProperty("_AlphaClip", properties);
albedoColor = FindProperty("_Color", properties);
albedoMap = FindProperty("_MainTex", properties);
alphaThreshold = FindProperty("_Cutoff", properties);
smoothness = FindProperty("_Glossiness", properties);
smoothnessScale = FindProperty("_GlossMapScale", properties, false);
smoothnessMapChannel = FindProperty("_SmoothnessTextureChannel", properties, false);
metallic = FindProperty("_Metallic", properties);
specColor = FindProperty("_SpecColor", properties);
metallicGlossMap = FindProperty("_MetallicGlossMap", properties);
specGlossMap = FindProperty("_SpecGlossMap", properties);
highlights = FindProperty("_SpecularHighlights", properties);
reflections = FindProperty("_GlossyReflections", properties);
bumpScale = FindProperty("_BumpScale", properties);
bumpMap = FindProperty("_BumpMap", properties);
occlusionStrength = FindProperty("_OcclusionStrength", properties);
occlusionMap = FindProperty("_OcclusionMap", properties);
emissionColorForRendering = FindProperty("_EmissionColor", properties);
emissionMap = FindProperty("_EmissionMap", properties);
//Subsurface
diffusionProfileID = FindProperty("_DiffusionProfile", properties);
curvature = FindProperty("_Curvature", properties);
thicknessMap = FindProperty("_ThicknessMap", properties);
thickness = FindProperty("_Thickness", properties);
}
public override void MaterialChanged(Material material)
{
material.shaderKeywords = null;
SetupMaterialBlendMode(material);
SetMaterialKeywords(material);
}
public override 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.surfaceType, surfaceType, Styles.surfaceNames);
if ((SurfaceType)material.GetFloat("_Surface") == SurfaceType.Transparent)
DoPopup(Styles.blendingMode, blendMode, Styles.blendNames);
EditorGUI.BeginChangeCheck();
bool twoSidedEnabled = EditorGUILayout.Toggle(Styles.twoSidedText, culling.floatValue == 0);
if (EditorGUI.EndChangeCheck())
culling.floatValue = twoSidedEnabled ? 0 : 2;
EditorGUI.BeginChangeCheck();
bool alphaClipEnabled = EditorGUILayout.Toggle(Styles.alphaClipText, alphaClip.floatValue == 1);
if (EditorGUI.EndChangeCheck())
alphaClip.floatValue = alphaClipEnabled ? 1 : 0;
// 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);
EditorGUILayout.Space();
DoSubsurfaceArea();
}
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/"))
{
SetupMaterialBlendMode(material);
return;
}
SurfaceType surfaceType = SurfaceType.Opaque;
BlendMode blendMode = BlendMode.Alpha;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
surfaceType = SurfaceType.Opaque;
material.SetFloat("_AlphaClip", 1);
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
surfaceType = SurfaceType.Transparent;
blendMode = BlendMode.Alpha;
}
material.SetFloat("_Surface", (float)surfaceType);
material.SetFloat("_Blend", (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);
}
void DoAlbedoArea(Material material)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor);
if (material.GetFloat("_AlphaClip") == 1)
{
m_MaterialEditor.ShaderProperty(alphaThreshold, Styles.clipThresholdText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);
}
}
void DoNormalArea()
{
m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpScale : null);
if (bumpScale.floatValue != 1 && UnityEditorInternal.InternalEditorUtility.IsMobilePlatform(EditorUserBuildSettings.activeBuildTarget))
if (m_MaterialEditor.HelpBoxWithButton(Styles.bumpScaleNotSupported, Styles.fixNow))
bumpScale.floatValue = 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, 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;
}
void DoSubsurfaceArea()
{
GUILayout.Label(Styles.subsurfaceAreaText, EditorStyles.boldLabel);
var lwPipeine = RenderPipelineManager.currentPipeline as LightweightPipeline;
var diffusionProfileSettings = lwPipeine.DiffusionProfileSettings;
if(lwPipeine.IsInternalDiffusionProfile(diffusionProfileSettings))
{
EditorGUILayout.HelpBox("No diffusion profile Settings have been assigned to the render pipeline asset.", MessageType.Warning);
return;
}
// TODO: Optimize me
var profiles = diffusionProfileSettings.profiles;
var names = new GUIContent[profiles.Length + 1];
names[0] = new GUIContent("None");
var values = new int[names.Length];
values[0] = DiffusionProfileConstants.DIFFUSION_PROFILE_NEUTRAL_ID;
for (int i = 0; i < profiles.Length; i++)
{
names[i + 1] = new GUIContent(profiles[i].name);
values[i + 1] = i + 1;
}
using (var scope = new EditorGUI.ChangeCheckScope())
{
int profileID = (int)diffusionProfileID.floatValue;
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.PrefixLabel(Styles.diffusionProfileText);
using (new EditorGUILayout.HorizontalScope())
{
profileID = EditorGUILayout.IntPopup(profileID, names, values);
if (GUILayout.Button("Goto", EditorStyles.miniButton, GUILayout.Width(50f)))
Selection.activeObject = diffusionProfileSettings;
}
}
if (scope.changed)
diffusionProfileID.floatValue = profileID;
}
m_MaterialEditor.ShaderProperty(curvature, Styles.curvatureText);
m_MaterialEditor.TexturePropertySingleLine(Styles.thicknessMapText, thicknessMap, thickness);
}
static SmoothnessMapChannel GetSmoothnessMapChannel(Material material)
{
int ch = (int)material.GetFloat("_SmoothnessTextureChannel");
if (ch == (int)SmoothnessMapChannel.AlbedoAlpha)
return SmoothnessMapChannel.AlbedoAlpha;
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");
CoreUtils.SetKeyword(material, "_SPECULAR_SETUP", isSpecularWorkFlow);
CoreUtils.SetKeyword(material, "_METALLICSPECGLOSSMAP", hasGlossMap);
CoreUtils.SetKeyword(material, "_SPECGLOSSMAP", hasGlossMap && isSpecularWorkFlow);
CoreUtils.SetKeyword(material, "_METALLICGLOSSMAP", hasGlossMap && !isSpecularWorkFlow);
CoreUtils.SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap"));
CoreUtils.SetKeyword(material, "_SPECULARHIGHLIGHTS_OFF", material.GetFloat("_SpecularHighlights") == 0.0f);
CoreUtils.SetKeyword(material, "_GLOSSYREFLECTIONS_OFF", material.GetFloat("_GlossyReflections") == 0.0f);
CoreUtils.SetKeyword(material, "_OCCLUSIONMAP", material.GetTexture("_OcclusionMap"));
CoreUtils.SetKeyword(material, "_PARALLAXMAP", material.GetTexture("_ParallaxMap"));
CoreUtils.SetKeyword(material, "_DETAIL_MULX2", material.GetTexture("_DetailAlbedoMap") || material.GetTexture("_DetailNormalMap"));
CoreUtils.SetKeyword(material, "_THICKNESSMAP", material.GetTexture("_ThicknessMap"));
// 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;
CoreUtils.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
if (material.HasProperty("_SmoothnessTextureChannel"))
{
CoreUtils.SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha);
}
}
}
}

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


#elif defined(_DEBUG_METALNESS)
debug = surfaceData.metallic;
#elif defined(_DEBUG_NORMALS)
debug = (0.5 * inputData.normalWS + 0.5);
debug = ( inputData.normalWS );
#elif defined(_DEBUG_SMOOTHNESS)
debug = surfaceData.smoothness;
#elif defined(_DEBUG_OCCLUSION)

23
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/Lighting.hlsl


#include "LWRP/DiffusionProfile/DiffusionProfileSettings.cs.hlsl"
//Surface Constants
float _Thickness;
//Diffusion Profile Constants
int _DiffusionProfile;
float4 _ThicknessRemap[9];

float irradiance = max(0.3 + dot(-normalWS, light.direction), 0.0);
return transmittance * irradiance * light.color * albedo;
}
half3 Transmittance_DataDriven(half thickness, half3 albedo, half3 normalWS, Light light)
{
half T = _ThicknessRemap[_DiffusionProfile].x + _ThicknessRemap[_DiffusionProfile].y * _Thickness;
float3 transmittance = ComputeTransmittanceJimenez(_HalfRcpVariancesAndWeights[_DiffusionProfile][0].rgb,
_HalfRcpVariancesAndWeights[_DiffusionProfile][0].a,
_HalfRcpVariancesAndWeights[_DiffusionProfile][1].rgb,
_HalfRcpVariancesAndWeights[_DiffusionProfile][1].a,
_TransmissionTint[_DiffusionProfile].rgb,
T);
float irradiance = max(0.3 + dot(-normalWS, light.direction), 0.0);
return transmittance * irradiance * light.color * albedo;
}
///////////////////////////////////////////////////////////////////////////////

// Used by ShaderGraph and others builtin renderers //
///////////////////////////////////////////////////////////////////////////////
half4 LightweightFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
half smoothness, half3 occlusion, half3 emission, half alpha, half curvature)
half smoothness, half3 occlusion, half3 emission, half alpha, half curvature, half thickness)
{
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, curvature, brdfData);

half3 color = GlobalIllumination (brdfData, inputData.bakedGI, occlusion, inputData.normalWS, inputData.viewDirectionWS);
color += LightingPhysicallyBased (brdfData, mainLight, inputData.normalWS, inputData.viewDirectionWS);
color += Transmittance (inputData.positionWS, inputData.normalWS, albedo, mainLight);
//color += Transmittance (inputData.positionWS, inputData.normalWS, albedo, mainLight);
//color += Transmittance_DataDriven(thickness, albedo, inputData.normalWS, mainLight);
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = GetPixelLightCount();

7
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/LightweightPassLit.hlsl


#ifndef LIGHTWEIGHT_PASS_LIT_INCLUDED
#define LIGHTWEIGHT_PASS_LIT_INCLUDED
#include "LWRP/ShaderLibrary/InputSurface.hlsl"
#include "InputSurface.hlsl"
#include "Lighting.hlsl"
struct LightweightVertexInput

return o;
}
float _Curvature;
// Used for Standard shader
half4 LitPassFragment(LightweightVertexOutput IN) : SV_Target
{

(length(fwidth(inputData.positionWS))) * _Curvature );
Light light = GetMainLight(inputData.positionWS);
half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha, curvature);
half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha, surfaceData.curvature, surfaceData.thickness);
ApplyFog(color.rgb, inputData.fogCoord);
return half4(color.rgb * SSAO(IN.shadowCoord), color.a);

4
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/LightweightSubsurface.shader


//Subsurface
_DiffusionProfile("Diffusion Profile", Int) = 0
_Curvature("Curvature", Range(0.0, 1.0)) = 0.005
_Thickness("Thickness", Range(0.0, 50.0)) = 20.0
_ThicknessMap("Thickness Map", 2D) = "white" {}
_Thickness("Thickness", Range(0.0, 1.0)) = 20.0
[Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0

#pragma shader_feature _METALLICSPECGLOSSMAP
#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _OCCLUSIONMAP
#pragma shader_feature _THICKNESSMAP
#pragma shader_feature _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _GLOSSYREFLECTIONS_OFF

8
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Foliage.meta


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

8
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair.meta


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

189
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/InputSurface.hlsl


#ifndef LIGHTWEIGHT_SURFACE_INPUT_INCLUDED
#define LIGHTWEIGHT_SURFACE_INPUT_INCLUDED
#include "../../ShaderLibrary/Core.hlsl"
#include "CoreRP/ShaderLibrary/Packing.hlsl"
#include "CoreRP/ShaderLibrary/CommonMaterial.hlsl"
#ifdef _SPECULAR_SETUP
#define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv)
#else
#define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, uv)
#endif
CBUFFER_START(UnityPerMaterial)
half4 _MainTex_ST;
half4 _Color;
half _Cutoff;
half _Glossiness;
half _GlossMapScale;
half _SmoothnessTextureChannel;
half _Metallic;
half4 _SpecColor;
half _BumpScale;
half _OcclusionStrength;
half4 _EmissionColor;
half _Shininess;
float _Thickness;
float _Curvature;
CBUFFER_END
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
TEXTURE2D(_MetallicGlossMap); SAMPLER(sampler_MetallicGlossMap);
TEXTURE2D(_SpecGlossMap); SAMPLER(sampler_SpecGlossMap);
TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap);
TEXTURE2D(_EmissionMap); SAMPLER(sampler_EmissionMap);
TEXTURE2D(_ThicknessMap); SAMPLER(sampler_ThicknessMap);
// Must match Lightweigth ShaderGraph master node
struct SurfaceData
{
half3 albedo;
half3 specular;
half metallic;
half smoothness;
half3 normalTS;
half3 emission;
half3 occlusion; //TLS: Colored AO.
half alpha;
half thickness;
half curvature;
};
///////////////////////////////////////////////////////////////////////////////
// Material Property Helpers //
///////////////////////////////////////////////////////////////////////////////
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 UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv), _BumpScale);
#else
return half3(0.0h, 0.0h, 1.0h);
#endif
}
half4 SpecularGloss(half2 uv, half alpha)
{
half4 specularGloss = half4(0, 0, 0, 1);
#ifdef _SPECGLOSSMAP
specularGloss = SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv);
specularGloss.rgb = specularGloss.rgb;
#elif defined(_SPECULAR_COLOR)
specularGloss = _SpecColor;
#endif
#ifdef _GLOSSINESS_FROM_BASE_ALPHA
specularGloss.a = alpha;
#endif
return specularGloss;
}
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 _SPECULAR_SETUP
specGloss.rgb = _SpecColor.rgb;
#else
specGloss.rgb = _Metallic.rrr;
#endif
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
specGloss.a = albedoAlpha * _GlossMapScale;
#else
specGloss.a = _Glossiness;
#endif
#endif
return specGloss;
}
half Occlusion(float2 uv)
{
#ifdef _OCCLUSIONMAP
#if (SHADER_TARGET < 30)
// SM20: instruction count limitation
// SM20: simpler occlusion
return SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g;
#else
half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g;
return LerpWhiteTo(occ, _OcclusionStrength);
#endif
#else
return 1.0;
#endif
}
half3 Emission(float2 uv)
{
#ifndef _EMISSION
return 0;
#else
return SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv).rgb * _EmissionColor.rgb;
#endif
}
half Thickness(float2 uv)
{
float T = _Thickness;
#ifdef _THICKNESSMAP
T *= SAMPLE_TEXTURE2D(_ThicknessMap, sampler_ThicknessMap, uv).r;
#endif
return T;
}
half Curvature(float2 uv)
{
return _Curvature;
}
inline void InitializeStandardLitSurfaceData(float2 uv, out SurfaceData outSurfaceData)
{
half4 albedoAlpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
half4 specGloss = MetallicSpecGloss(uv, albedoAlpha.a);
outSurfaceData.albedo = albedoAlpha.rgb * _Color.rgb;
#if _SPECULAR_SETUP
outSurfaceData.metallic = 1.0h;
outSurfaceData.specular = specGloss.rgb;
#else
outSurfaceData.metallic = specGloss.r;
outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h);
#endif
outSurfaceData.smoothness = specGloss.a;
outSurfaceData.normalTS = Normal(uv);
outSurfaceData.occlusion = Occlusion(uv);
outSurfaceData.emission = Emission(uv);
outSurfaceData.alpha = Alpha(albedoAlpha.a);
outSurfaceData.thickness = Thickness(uv);
outSurfaceData.curvature = Curvature(uv);
}
#endif

9
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/InputSurface.hlsl.meta


fileFormatVersion: 2
guid: 8bf4837f95f847b4d9ad817e9f99ea31
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

714
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl


#ifndef LIGHTWEIGHT_LIGHTING_INCLUDED
#define LIGHTWEIGHT_LIGHTING_INCLUDED
#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "CoreRP/ShaderLibrary/EntityLighting.hlsl"
#include "CoreRP/ShaderLibrary/ImageBasedLighting.hlsl"
#include "LWRP/ShaderLibrary/Core.hlsl"
#include "LWRP/ShaderLibrary/Shadows.hlsl"
#ifdef NO_ADDITIONAL_LIGHTS
#undef _ADDITIONAL_LIGHTS
#endif
// If lightmap is not defined than we evaluate GI (ambient + probes) from SH
// We might do it fully or partially in vertex to save shader ALU
#if !defined(LIGHTMAP_ON)
#ifdef SHADER_API_GLES
// Evaluates SH fully in vertex
#define EVALUATE_SH_VERTEX
#else
// Evaluates L2 SH in vertex and L0L1 in pixel
#define EVALUATE_SH_MIXED
#endif
#endif
#ifdef LIGHTMAP_ON
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw;
#define OUTPUT_SH(normalWS, OUT)
#else
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT)
#define OUTPUT_SH(normalWS, OUT) OUT.xyz = SampleSHVertex(normalWS)
#endif
///////////////////////////////////////////////////////////////////////////////
// Light Helpers //
///////////////////////////////////////////////////////////////////////////////
// Abstraction over Light input constants
struct LightInput
{
float4 position;
half3 color;
half4 distanceAttenuation;
half4 spotDirection;
half4 spotAttenuation;
};
// Abstraction over Light shading data.
struct Light
{
half3 direction;
half3 color;
half attenuation;
half subtractiveModeAttenuation;
};
///////////////////////////////////////////////////////////////////////////////
// Attenuation Functions /
///////////////////////////////////////////////////////////////////////////////
half CookieAttenuation(float3 worldPos)
{
#ifdef _MAIN_LIGHT_COOKIE
#ifdef _MAIN_LIGHT_DIRECTIONAL
float2 cookieUV = mul(_WorldToLight, float4(worldPos, 1.0)).xy;
return SAMPLE_TEXTURE2D(_MainLightCookie, sampler_MainLightCookie, cookieUV).a;
#elif defined(_MAIN_LIGHT_SPOT)
float4 projPos = mul(_WorldToLight, float4(worldPos, 1.0));
float2 cookieUV = projPos.xy / projPos.w + 0.5;
return SAMPLE_TEXTURE2D(_MainLightCookie, sampler_MainLightCookie, cookieUV).a;
#endif // POINT LIGHT cookie not supported
#endif
return 1;
}
// Matches Unity Vanila attenuation
// Attenuation smoothly decreases to light range.
half DistanceAttenuation(half distanceSqr, half3 distanceAttenuation)
{
// We use a shared distance attenuation for additional directional and puctual lights
// for directional lights attenuation will be 1
half quadFalloff = distanceAttenuation.x;
half denom = distanceSqr * quadFalloff + 1.0;
half lightAtten = 1.0 / denom;
// We need to smoothly fade attenuation to light range. We start fading linearly at 80% of light range
// Therefore:
// fadeDistance = (0.8 * 0.8 * lightRangeSq)
// smoothFactor = (lightRangeSqr - distanceSqr) / (lightRangeSqr - fadeDistance)
// We can rewrite that to fit a MAD by doing
// distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr)
// distanceSqr * distanceAttenuation.y + distanceAttenuation.z
half smoothFactor = saturate(distanceSqr * distanceAttenuation.y + distanceAttenuation.z);
return lightAtten * smoothFactor;
}
half SpotAttenuation(half3 spotDirection, half3 lightDirection, half4 spotAttenuation)
{
// 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)
// SdotL * spotAttenuation.x + spotAttenuation.y
// If we precompute the terms in a MAD instruction
half SdotL = dot(spotDirection, lightDirection);
half atten = saturate(SdotL * spotAttenuation.x + spotAttenuation.y);
return atten * atten;
}
half4 GetLightDirectionAndAttenuation(LightInput lightInput, float3 positionWS)
{
half4 directionAndAttenuation;
float3 posToLightVec = lightInput.position.xyz - positionWS * lightInput.position.w;
float distanceSqr = max(dot(posToLightVec, posToLightVec), FLT_MIN);
directionAndAttenuation.xyz = half3(posToLightVec * rsqrt(distanceSqr));
directionAndAttenuation.w = DistanceAttenuation(distanceSqr, lightInput.distanceAttenuation.xyz);
directionAndAttenuation.w *= SpotAttenuation(lightInput.spotDirection.xyz, directionAndAttenuation.xyz, lightInput.spotAttenuation);
return directionAndAttenuation;
}
half4 GetMainLightDirectionAndAttenuation(LightInput lightInput, float3 positionWS)
{
half4 directionAndAttenuation = lerp(half4(lightInput.position.xyz, 1.0), GetLightDirectionAndAttenuation(lightInput, positionWS), lightInput.position.w);
// Cookies are only computed for main light
directionAndAttenuation.w *= CookieAttenuation(positionWS);
return directionAndAttenuation;
}
///////////////////////////////////////////////////////////////////////////////
// Light Abstraction //
///////////////////////////////////////////////////////////////////////////////
Light GetMainLight(float3 positionWS)
{
LightInput lightInput;
lightInput.position = _MainLightPosition;
lightInput.color = _MainLightColor.rgb;
lightInput.distanceAttenuation = _MainLightDistanceAttenuation;
lightInput.spotDirection = _MainLightSpotDir;
lightInput.spotAttenuation = _MainLightSpotAttenuation;
half4 directionAndRealtimeAttenuation = GetMainLightDirectionAndAttenuation(lightInput, positionWS);
Light light;
light.direction = directionAndRealtimeAttenuation.xyz;
light.attenuation = directionAndRealtimeAttenuation.w;
light.subtractiveModeAttenuation = lightInput.distanceAttenuation.w;
light.color = lightInput.color;
return light;
}
Light GetLight(int i, float3 positionWS)
{
LightInput lightInput;
half4 indices = (i < 4) ? unity_4LightIndices0 : unity_4LightIndices1;
int index = (i < 4) ? i : i - 4;
int lightIndex = indices[index];
lightInput.position = _AdditionalLightPosition[lightIndex];
lightInput.color = _AdditionalLightColor[lightIndex].rgb;
lightInput.distanceAttenuation = _AdditionalLightDistanceAttenuation[lightIndex];
lightInput.spotDirection = _AdditionalLightSpotDir[lightIndex];
lightInput.spotAttenuation = _AdditionalLightSpotAttenuation[lightIndex];
half4 directionAndRealtimeAttenuation = GetLightDirectionAndAttenuation(lightInput, positionWS);
Light light;
light.direction = directionAndRealtimeAttenuation.xyz;
light.attenuation = directionAndRealtimeAttenuation.w;
light.subtractiveModeAttenuation = lightInput.distanceAttenuation.w;
light.color = lightInput.color;
return light;
}
half GetPixelLightCount()
{
return min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y);
}
///////////////////////////////////////////////////////////////////////////////
// BRDF Functions //
///////////////////////////////////////////////////////////////////////////////
#define kDieletricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
struct BRDFData
{
half3 diffuse;
half3 specular;
half perceptualRoughness;
half roughness;
half roughness2;
half grazingTerm;
};
half ReflectivitySpecular(half3 specular)
{
#if (SHADER_TARGET < 30)
// SM2.0: instruction count limitation
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
}
half OneMinusReflectivityMetallic(half metallic)
{
// 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;
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
}
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData)
{
#ifdef _SPECULAR_SETUP
half reflectivity = ReflectivitySpecular(specular);
half oneMinusReflectivity = 1.0 - reflectivity;
outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular);
outBRDFData.specular = specular;
#else
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
half reflectivity = 1.0 - oneMinusReflectivity;
outBRDFData.diffuse = albedo * oneMinusReflectivity;
outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic);
#endif
outBRDFData.grazingTerm = saturate(smoothness + reflectivity);
outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
outBRDFData.roughness = PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness);
outBRDFData.roughness2 = outBRDFData.roughness * outBRDFData.roughness;
#ifdef _ALPHAPREMULTIPLY_ON
outBRDFData.diffuse *= alpha;
alpha = alpha * oneMinusReflectivity + reflectivity;
#endif
}
half3 EnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half fresnelTerm)
{
half3 c = indirectDiffuse * brdfData.diffuse;
float surfaceReduction = 1.0 / (brdfData.roughness2 + 1.0);
c += surfaceReduction * indirectSpecular * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm);
return c;
}
// 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 DirectBDRF(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
half3 halfDir = SafeNormalize(lightDirectionWS + viewDirectionWS);
half NoH = saturate(dot(normalWS, halfDir));
half LoH = saturate(dot(lightDirectionWS, 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 * (brdfData.roughness2 - 1.h) + 1.00001h;
half LoH2 = LoH * LoH;
half specularTerm = brdfData.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 - HALF_MIN;
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
}
///////////////////////////////////////////////////////////////////////////////
// Global Illumination //
///////////////////////////////////////////////////////////////////////////////
// Samples SH L0, L1 and L2 terms
half3 SampleSH(half3 normalWS)
{
// LPPV is not supported in Ligthweight Pipeline
real4 SHCoefficients[7];
SHCoefficients[0] = unity_SHAr;
SHCoefficients[1] = unity_SHAg;
SHCoefficients[2] = unity_SHAb;
SHCoefficients[3] = unity_SHBr;
SHCoefficients[4] = unity_SHBg;
SHCoefficients[5] = unity_SHBb;
SHCoefficients[6] = unity_SHC;
return max(half3(0, 0, 0), SampleSH9(SHCoefficients, normalWS));
}
// SH Vertex Evaluation. Depending on target SH sampling might be
// done completely per vertex or mixed with L2 term per vertex and L0, L1
// per pixel. See SampleSHPixel
half3 SampleSHVertex(half3 normalWS)
{
#if defined(EVALUATE_SH_VERTEX)
return max(half3(0, 0, 0), SampleSH(normalWS));
#elif defined(EVALUATE_SH_MIXED)
// no max since this is only L2 contribution
return SHEvalLinearL2(normalWS, unity_SHBr, unity_SHBg, unity_SHBb, unity_SHC);
#endif
// Fully per-pixel. Nothing to compute.
return half3(0.0, 0.0, 0.0);
}
// SH Pixel Evaluation. Depending on target SH sampling might be done
// mixed or fully in pixel. See SampleSHVertex
half3 SampleSHPixel(half3 L2Term, half3 normalWS)
{
#ifdef EVALUATE_SH_MIXED
half3 L0L1Term = SHEvalLinearL0L1(normalWS, unity_SHAr, unity_SHAg, unity_SHAb);
return max(half3(0, 0, 0), L2Term + L0L1Term);
#endif
// Default: Evaluate SH fully per-pixel
return SampleSH(normalWS);
}
// Sample baked lightmap. Non-Direction and Directional if available.
// Realtime GI is not supported.
half3 SampleLightmap(float2 lightmapUV, half3 normalWS)
{
#ifdef UNITY_LIGHTMAP_FULL_HDR
bool encodedLightmap = false;
#else
bool encodedLightmap = true;
#endif
// The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale.
// However, lightweight pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and
// the compiler will optimize the transform away.
half4 transformCoords = half4(1, 1, 0, 0);
#ifdef DIRLIGHTMAP_COMBINED
return SampleDirectionalLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap),
TEXTURE2D_PARAM(unity_LightmapInd, samplerunity_Lightmap),
lightmapUV, transformCoords, normalWS, encodedLightmap, unity_Lightmap_HDR);
#else
return SampleSingleLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), lightmapUV, transformCoords, encodedLightmap, unity_Lightmap_HDR);
#endif
}
// We either sample GI from baked lightmap or from probes.
// If lightmap: sampleData.xy = lightmapUV
// If probe: sampleData.xyz = L2 SH terms
half3 SampleGI(float4 sampleData, half3 normalWS)
{
#ifdef LIGHTMAP_ON
return SampleLightmap(sampleData.xy, normalWS);
#endif
// If lightmap is not enabled we sample GI from SH
return SampleSHPixel(sampleData.xyz, normalWS);
}
half3 GlossyEnvironmentReflection(half3 reflectVector, half perceptualRoughness, half occlusion)
{
#if !defined(_GLOSSYREFLECTIONS_OFF)
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
half4 encodedIrradiance = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip);
#if !defined(UNITY_USE_NATIVE_HDR)
half3 irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
#else
half3 irradiance = encodedIrradiance.rbg;
#endif
return irradiance * occlusion;
#endif // GLOSSY_REFLECTIONS
return _GlossyEnvironmentColor.rgb * occlusion;
}
half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS)
{
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
half3 indirectDiffuse = bakedGI * occlusion;
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion);
return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
}
half3 SubtractDirectMainLightFromLightmap(Light mainLight, half3 normalWS, half3 bakedGI)
{
// 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) Calculate possible value in the shadow by subtracting estimated light contribution from the places occluded by realtime shadow:
// a) preserves other baked lights and light bounces
// b) eliminates shadows on the geometry facing away from the light
// 2) Clamp against user defined ShadowColor.
// 3) Pick original lightmap value, if it is the darkest one.
// 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 = GetShadowStrength();
half NdotL = saturate(dot(mainLight.direction, normalWS));
half3 lambert = mainLight.color * NdotL;
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.
half3 realtimeShadow = max(subtractedLightmap, _SubtractiveShadowColor.xyz);
realtimeShadow = lerp(bakedGI, realtimeShadow, shadowStrength);
// 3) Pick darkest color
return min(bakedGI, realtimeShadow);
}
void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI, half4 shadowMask)
{
#if defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON) && defined(_SHADOWS_ENABLED)
bakedGI = lerp(SubtractDirectMainLightFromLightmap(light, normalWS, bakedGI), bakedGI, _MainLightPosition.w);
#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 //
///////////////////////////////////////////////////////////////////////////////
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
{
half NdotL = saturate(dot(normal, lightDir));
return lightColor * NdotL;
}
half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specularGloss, half shininess)
{
half3 halfVec = SafeNormalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));
half3 specularReflection = specularGloss.rgb * pow(NdotH, shininess) * specularGloss.a;
return lightColor * specularReflection;
}
half3 LightingPhysicallyBased(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS)
{
half NdotL = saturate(dot(normalWS, lightDirectionWS));
half3 radiance = lightColor * (lightAttenuation * NdotL);
return DirectBDRF(brdfData, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
}
half3 LightingPhysicallyBased(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS)
{
return LightingPhysicallyBased(brdfData, light.color, light.direction, light.attenuation, normalWS, viewDirectionWS);
}
half3 VertexLighting(float3 positionWS, half3 normalWS)
{
half3 vertexLightColor = half3(0.0, 0.0, 0.0);
#if defined(_VERTEX_LIGHTS)
int vertexLightStart = _AdditionalLightCount.x;
int vertexLightEnd = min(_AdditionalLightCount.y, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = vertexLightStart; lightIter < vertexLightEnd; ++lightIter)
{
Light light = GetLight(lightIter, positionWS);
half3 lightColor = light.color * light.attenuation;
vertexLightColor += LightingLambert(lightColor, light.direction, normalWS);
}
#endif
return vertexLightColor;
}
#define ALPHA_R -5.0
#define ALPHA_TT ALPHA_R / 2.0
#define ALPHA_TRT -3.0 * ALPHA_R / 2.0
#define BETA_R 5.0
#define BETA_TT BETA_R / 2.0
#define BETA_TRT 2.0 * BETA_R
#define IOR 1.55
float Fresnel(float ior, float x)
{
float num = 1.0 - ior;
float den = 1.0 + ior;
float F0 = (num * num) / (den * den);
return F0 + (1.0 - F0) * pow(1.0 - x, 5);
}
//M Term is a simple gaussian distribution
float M(float B, float Theta)
{
float term0 = 1.0 / (B * sqrt(2.0 * PI));
float term1 = -( (Theta * Theta) / (2.0 * B * B) );
return term0 * exp(term1);
}
//NR Term
float NR(float CosPhi, float CosHalfPhi)
{
float Distribution = 0.25 * CosHalfPhi;
float Attenuation = Fresnel(IOR, CosHalfPhi);
return Distribution * Attenuation;
}
//NTT Term
float3 NTT(float CosPhi, float CosHalfPhi, float CosThetaD, float3 VolumeAlbedo)
{
//Assumes Eta of 1.55 for human hair.
float EtaPrime = (1.19 / CosThetaD) + 0.36 * CosThetaD;
float a = 1.0 / EtaPrime;
float h = (1.0 + (a * (0.6 - (0.8 * CosPhi)))) * CosHalfPhi;
//Attenuation Term
float F = Fresnel(EtaPrime, CosThetaD * sqrt(1.0 - h*h));
float Fp = Fresnel(IOR, CosHalfPhi);
float Texp = (sqrt(1.0 - (h*h*a*a)) / (2.0 * CosThetaD));
float3 T = pow(VolumeAlbedo, Texp);
float3 A = pow(1 - F, 2) * Fp * T;
//Distribution Term
float D = exp((-3.65 * CosPhi) - 3.98);
return A * D;
}
//NTRT Term
float3 NTRT(float CosPhi, float CosHalfPhi, float CosThetaD, float3 VolumeAlbedo)
{
//Assumes Eta of 1.55 for human hair.
float EtaPrime = (1.19 / CosThetaD) + 0.36 * CosThetaD;
float h = sqrt(3) / 2.0;
float F = Fresnel(EtaPrime, CosThetaD * sqrt(1.0 - h*h));
float Fp = Fresnel(IOR, CosHalfPhi);
float3 T = pow(VolumeAlbedo, 0.8 / CosThetaD);
float3 A = pow(1 - F, 2) * Fp * T;
float D = exp((17.0 * CosPhi) - 16.78);
return A * D;
}
half3 Hair(BRDFData brdfData,
half3 Light, half3 View, half3 Normal, half3 Tangent)
{
//Calculate Binormal to complete the onormal basis.
half3 Binormal = cross(Tangent, Normal);
//Calculate cosines.
float TdotL = dot(Tangent, Light);
float TdotV = dot(Tangent, View);
float BdotL = dot(Binormal, Light);
float BdotV = dot(Binormal, View);
float LdotV = dot(Light, View);
//Azimuth projection.
float3 ProjLight = Light - TdotL * Tangent;
float3 ProjView = View - TdotV * Tangent;
float ThetaH = (TdotL + TdotV) / 2.0;
float CosPhi = dot(ProjView, ProjLight) * pow(dot(ProjView, ProjView) * dot(ProjLight, ProjLight), -0.5);
float CosHalfPhi = sqrt(0.5 + 0.5 * CosPhi);
float CosThetaD = cos( (acos(TdotV) - acos(TdotL)) / 2.0 );
//R Path
float mr = M(radians(BETA_R), ThetaH - radians(ALPHA_R));
float nr = NR(CosPhi, CosHalfPhi);
//TT Path
float mtt = M(radians(BETA_TT), ThetaH - radians(ALPHA_TT));
float3 ntt = NTT(CosPhi, CosHalfPhi, CosThetaD, brdfData.diffuse);
//TRT Path
float mtrt = M(radians(BETA_TRT), ThetaH - radians(ALPHA_TRT));
float3 ntrt = NTRT(CosPhi, CosHalfPhi, CosThetaD, brdfData.diffuse);
return brdfData.diffuse + (((mr * nr * 1) + (mtt * ntt * 1) + (mtrt * ntrt * 1)) / (CosThetaD * CosThetaD));
}
half3 HairGlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS,
half3 tangent)
{
half3 reflectVector = normalWS;// reflect(-viewDirectionWS, normalWS);
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
half3 indirectDiffuse = bakedGI * occlusion;
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion);
float TdotL = dot(tangent, normalWS);
float TdotV = dot(tangent, viewDirectionWS);
float ThetaH = (TdotL + TdotV) / 1.0;
float mr = M(radians(BETA_R), ThetaH - radians(ALPHA_R));
return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
}
///////////////////////////////////////////////////////////////////////////////
// Fragment Functions //
// Used by ShaderGraph and others builtin renderers //
///////////////////////////////////////////////////////////////////////////////
half4 LightweightFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
half smoothness, half occlusion, half3 emission, half alpha, half3 tangent)
{
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
Light mainLight = GetMainLight(inputData.positionWS);
mainLight.attenuation *= RealtimeShadowAttenuation(inputData.shadowCoord);
float3 V = inputData.viewDirectionWS;
float3 T = tangent;
float3 normalFake = normalize(V - T * dot(T, V));
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
half3 color = HairGlobalIllumination(brdfData, inputData.bakedGI, occlusion, normalFake, inputData.viewDirectionWS, tangent);
//Hair Shading.
half NdotL = saturate(dot(inputData.normalWS, mainLight.direction));
half3 radiance = mainLight.color * (mainLight.attenuation * NdotL);
color += Hair(brdfData, mainLight.direction, inputData.viewDirectionWS, inputData.normalWS, tangent) * radiance;
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = GetPixelLightCount();
for (int i = 0; i < pixelLightCount; ++i)
{
Light light = GetLight(i, inputData.positionWS);
half NdotL = saturate(dot(inputData.normalWS, light.direction));
radiance = light.color * (light.attenuation * NdotL);
color += Hair(brdfData, light.direction, inputData.viewDirectionWS, inputData.normalWS, tangent) * radiance;
}
#endif
color += inputData.vertexLighting * brdfData.diffuse;
color += emission;
return half4(color, alpha);
}
half4 LightweightFragmentBlinnPhong(InputData inputData, half3 diffuse, half4 specularGloss, half shininess, half3 emission, half alpha)
{
Light mainLight = GetMainLight(inputData.positionWS);
mainLight.attenuation *= RealtimeShadowAttenuation(inputData.shadowCoord);
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
half3 attenuatedLightColor = mainLight.color * mainLight.attenuation;
half3 diffuseColor = inputData.bakedGI + LightingLambert(attenuatedLightColor, mainLight.direction, inputData.normalWS);
half3 specularColor = LightingSpecular(attenuatedLightColor, mainLight.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, shininess);
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = GetPixelLightCount();
for (int i = 0; i < pixelLightCount; ++i)
{
Light light = GetLight(i, inputData.positionWS);
half3 attenuatedLightColor = light.color * light.attenuation;
diffuseColor += LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
specularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, shininess);
}
#endif
half3 finalColor = diffuseColor * diffuse + emission;
finalColor += inputData.vertexLighting * diffuse;
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
finalColor += specularColor;
#endif
ApplyFog(finalColor, inputData.fogCoord);
return half4(finalColor, alpha);
}
#endif

9
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl.meta


fileFormatVersion: 2
guid: eff950401d43e459f839ebd0dc057331
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

224
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader


Shader "LightweightPipeline/Hair"
{
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" {}
[ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0
[ToggleOff] _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] _Surface("__surface", Float) = 0.0
[HideInInspector] _Blend("__blend", Float) = 0.0
[HideInInspector] _AlphaClip("__clip", Float) = 0.0
[HideInInspector] _SrcBlend("__src", Float) = 1.0
[HideInInspector] _DstBlend("__dst", Float) = 0.0
[HideInInspector] _ZWrite("__zw", Float) = 1.0
[HideInInspector] _Cull("__cull", Float) = 2.0
}
SubShader
{
// Lightweight Pipeline tag is required. If Lightweight pipeline is not set in the graphics settings
// this Subshader will fail. One can add a subshader below or fallback to Standard built-in to make this
// material work with both Lightweight Pipeline and Builtin Unity Pipeline
Tags{"RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline"}
LOD 300
// ------------------------------------------------------------------
// Forward pass. Shades all light in a single pass. GI + emission + Fog
Pass
{
// Lightmode matches the ShaderPassName set in LightweightPipeline.cs. SRPDefaultUnlit and passes with
// no LightMode tag are also rendered by Lightweight Pipeline
Tags{"LightMode" = "LightweightForward"}
Blend[_SrcBlend][_DstBlend]
ZWrite[_ZWrite]
Cull[_Cull]
HLSLPROGRAM
// Required to compile gles 2.0 with standard SRP library
// All shaders must be compiled with HLSLcc and currently only gles is not using HLSLcc by default
#pragma prefer_hlslcc gles
#pragma target 3.0
// -------------------------------------
// Material Keywords
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ALPHATEST_ON
#pragma shader_feature _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICSPECGLOSSMAP
#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _OCCLUSIONMAP
#pragma shader_feature _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _GLOSSYREFLECTIONS_OFF
#pragma shader_feature _SPECULAR_SETUP
// -------------------------------------
// Lightweight Pipeline keywords
#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
#pragma multi_compile _ FOG_LINEAR FOG_EXP2
// -------------------------------------
// Unity defined keywords
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma vertex LitPassVertex
#pragma fragment LitPassFragment
#include "LightweightPassLit.hlsl"
ENDHLSL
}
Pass
{
Tags{"LightMode" = "ShadowCaster"}
ZWrite On
ZTest LEqual
Cull[_Cull]
HLSLPROGRAM
// Required to compile gles 2.0 with standard srp library
#pragma prefer_hlslcc gles
#pragma target 2.0
// -------------------------------------
// Material Keywords
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ALPHATEST_ON
#pragma shader_feature _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICSPECGLOSSMAP
#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _OCCLUSIONMAP
#pragma shader_feature _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _GLOSSYREFLECTIONS_OFF
#pragma shader_feature _SPECULAR_SETUP
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma vertex ShadowPassVertex
#pragma fragment LitPassFragmentNull
#include "LWRP/ShaderLibrary/LightweightPassShadow.hlsl"
ENDHLSL
}
Pass
{
Tags{"LightMode" = "DepthOnly"}
ZWrite On
Cull[_Cull]
ColorMask 0
HLSLPROGRAM
// Required to compile gles 2.0 with standard srp library
#pragma prefer_hlslcc gles
#pragma target 2.0
// -------------------------------------
// Material Keywords
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ALPHATEST_ON
#pragma shader_feature _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICSPECGLOSSMAP
#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _OCCLUSIONMAP
#pragma shader_feature _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _GLOSSYREFLECTIONS_OFF
#pragma shader_feature _SPECULAR_SETUP
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma vertex LitPassVertex
#pragma fragment LitPassFragmentNull
#include "LWRP/ShaderLibrary/LightweightPassLit.hlsl"
ENDHLSL
}
// This pass it not used during regular rendering, only for lightmap baking.
Pass
{
Tags{"LightMode" = "Meta"}
Cull Off
HLSLPROGRAM
// Required to compile gles 2.0 with standard srp library
#pragma prefer_hlslcc gles
#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
#pragma shader_feature EDITOR_VISUALIZATION
#pragma shader_feature _SPECGLOSSMAP
#include "LWRP/ShaderLibrary/LightweightPassMeta.hlsl"
ENDHLSL
}
}
FallBack "Hidden/InternalErrorShader"
CustomEditor "LightweightStandardGUI"
}

9
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader.meta


fileFormatVersion: 2
guid: c535d86c2e6be4263bdb0d55c8b71903
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

166
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl


#ifndef LIGHTWEIGHT_PASS_LIT_INCLUDED
#define LIGHTWEIGHT_PASS_LIT_INCLUDED
#include "LWRP/ShaderLibrary/InputSurface.hlsl"
#include "Lighting.hlsl"
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 lightmapUVOrVertexSH : TEXCOORD1; // holds either lightmapUV or vertex SH. depending on LIGHTMAP_ON
float3 posWS : TEXCOORD2;
half3 normal : TEXCOORD3;
//Force TBN output for hair.
half3 tangent : TEXCOORD4;
half3 binormal : TEXCOORD5;
half3 viewDir : TEXCOORD6;
half4 fogFactorAndVertexLight : TEXCOORD7; // x: fogFactor, yzw: vertex light
float4 shadowCoord : TEXCOORD8;
float4 clipPos : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
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
inputData.shadowCoord = IN.shadowCoord;
inputData.fogCoord = IN.fogFactorAndVertexLight.x;
inputData.vertexLighting = IN.fogFactorAndVertexLight.yzw;
inputData.bakedGI = SampleGI(IN.lightmapUVOrVertexSH, inputData.normalWS);
}
///////////////////////////////////////////////////////////////////////////////
// Vertex and Fragment functions //
///////////////////////////////////////////////////////////////////////////////
// Vertex: Used for Standard and StandardSimpleLighting shaders
LightweightVertexOutput LitPassVertex(LightweightVertexInput v)
{
LightweightVertexOutput o = (LightweightVertexOutput)0;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.posWS = TransformObjectToWorld(v.vertex.xyz);
o.clipPos = TransformWorldToHClip(o.posWS);
o.viewDir = SafeNormalize(GetCameraPositionWS() - o.posWS);
// initializes o.normal and if _NORMALMAP also o.tangent and o.binormal
//OUTPUT_NORMAL(v, o);
//Force TBN output for hair.
OutputTangentToWorld(v.tangent, v.normal, o.tangent, o.binormal, o.normal);
// We either sample GI from lightmap or SH. lightmap UV and vertex SH coefficients
// are packed in lightmapUVOrVertexSH to save interpolator.
// The following funcions initialize
OUTPUT_LIGHTMAP_UV(v.lightmapUV, unity_LightmapST, o.lightmapUVOrVertexSH);
OUTPUT_SH(o.normal, o.lightmapUVOrVertexSH);
half3 vertexLight = VertexLighting(o.posWS, o.normal);
half fogFactor = ComputeFogFactor(o.clipPos.z);
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
o.shadowCoord = ComputeShadowCoord(o.clipPos);
return o;
}
// Used for Standard shader
half4 LitPassFragment(LightweightVertexOutput IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
SurfaceData surfaceData;
InitializeStandardLitSurfaceData(IN.uv, surfaceData);
InputData inputData;
InitializeInputData(IN, surfaceData.normalTS, inputData);
half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha, -IN.binormal);
ApplyFog(color.rgb, inputData.fogCoord);
return half4(color.rgb, 1);
}
// Used for Standard shader
half4 LitPassFragmentNull(LightweightVertexOutput IN) : SV_Target
{
LitPassFragment(IN);
return 0;
}
// Used for StandardSimpleLighting shader
half4 LitPassFragmentSimple(LightweightVertexOutput IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
float2 uv = IN.uv;
half4 diffuseAlpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
half3 diffuse = diffuseAlpha.rgb * _Color.rgb;
half alpha = diffuseAlpha.a * _Color.a;
AlphaDiscard(alpha, _Cutoff);
#ifdef _ALPHAPREMULTIPLY_ON
diffuse *= alpha;
#endif
#ifdef _NORMALMAP
half3 normalTS = Normal(uv);
#else
half3 normalTS = half3(0, 0, 1);
#endif
half3 emission = Emission(uv);
half4 specularGloss = SpecularGloss(uv, diffuseAlpha.a);
half shininess = _Shininess * 128.0h;
InputData inputData;
InitializeInputData(IN, normalTS, inputData);
return LightweightFragmentBlinnPhong(inputData, diffuse, specularGloss, shininess, emission, alpha);
};
// Used for StandardSimpleLighting shader
half4 LitPassFragmentSimpleNull(LightweightVertexOutput IN) : SV_Target
{
half4 result = LitPassFragmentSimple(IN);
return result.a;
}
#endif

9
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl.meta


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