John Parsaie
7 年前
当前提交
b65915e1
共有 16 个文件被更改,包括 1796 次插入 和 435 次删除
-
850ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/ShaderGUI/LightweightSubsurfaceGUI.cs
-
2ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassLit.hlsl
-
23ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/Lighting.hlsl
-
7ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/LightweightPassLit.hlsl
-
4ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/LightweightSubsurface.shader
-
8ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Foliage.meta
-
8ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair.meta
-
189ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/InputSurface.hlsl
-
9ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Subsurface/InputSurface.hlsl.meta
-
714ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl
-
9ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl.meta
-
224ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader
-
9ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader.meta
-
166ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl
-
9ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl.meta
|
|||
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); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 967a9e9c7bcf0994891946c26e958db9 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 40c9ed26ae111bc45a26d5ace3b4017a |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#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 |
|
|||
fileFormatVersion: 2 |
|||
guid: 8bf4837f95f847b4d9ad817e9f99ea31 |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
nonModifiableTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#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 |
|
|||
fileFormatVersion: 2 |
|||
guid: eff950401d43e459f839ebd0dc057331 |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
nonModifiableTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
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" |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c535d86c2e6be4263bdb0d55c8b71903 |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
nonModifiableTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#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 |
|
|||
fileFormatVersion: 2 |
|||
guid: 846283d417dbc4ddb8b85110d4a44088 |
|||
ShaderImporter: |
|||
externalObjects: {} |
|||
defaultTextures: [] |
|||
nonModifiableTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue