├── Editor └── CustomStandardShaderGUI.cs ├── LICENSE ├── README.md ├── StandardShader ├── CustomStandard.shader ├── CustomUnityStandardCore.cginc ├── CustomUnityStandardInput.cginc └── CustomUnityStandardMeta.cginc └── TerrainShaders ├── CustomStandard-AddPass.shader ├── CustomStandard-FirstPass.shader └── CustomTerrainSplatmapCommon.cginc /Editor/CustomStandardShaderGUI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityEditor 5 | { 6 | internal class StandardShaderGUI : ShaderGUI 7 | { 8 | private enum WorkflowMode 9 | { 10 | Specular, 11 | Metallic, 12 | Dielectric 13 | } 14 | 15 | public enum BlendMode 16 | { 17 | Opaque, 18 | Cutout, 19 | Fade, // Old school alpha-blending mode, fresnel does not affect amount of transparency 20 | Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply 21 | } 22 | 23 | private static class Styles 24 | { 25 | public static GUIStyle optionsButton = "PaneOptions"; 26 | public static GUIContent uvSetLabel = new GUIContent("UV Set"); 27 | public static GUIContent[] uvSetOptions = new GUIContent[] { new GUIContent("UV channel 0"), new GUIContent("UV channel 1") }; 28 | 29 | public static string emptyTootip = ""; 30 | public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)"); 31 | public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff"); 32 | public static GUIContent specularMapText = new GUIContent("Specular", "Specular (RGB) and Smoothness (A)"); 33 | public static GUIContent metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)"); 34 | public static GUIContent smoothnessText = new GUIContent("Smoothness", ""); 35 | public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map"); 36 | public static GUIContent heightMapText = new GUIContent("Height Map", "Height Map (G)"); 37 | public static GUIContent occlusionText = new GUIContent("Occlusion", "Occlusion (G)"); 38 | public static GUIContent emissionText = new GUIContent("Emission", "Emission (RGB)"); 39 | public static GUIContent detailMaskText = new GUIContent("Detail Mask", "Mask for Secondary Maps (A)"); 40 | public static GUIContent detailAlbedoText = new GUIContent("Detail Albedo x2", "Albedo (RGB) multiplied by 2"); 41 | public static GUIContent detailNormalMapText = new GUIContent("Normal Map", "Normal Map"); 42 | 43 | public static string whiteSpaceString = " "; 44 | public static string primaryMapsText = "Main Maps"; 45 | public static string secondaryMapsText = "Secondary Maps"; 46 | public static string renderingMode = "Rendering Mode"; 47 | public static GUIContent emissiveWarning = new GUIContent ("Emissive value is animated but the material has not been configured to support emissive. Please make sure the material itself has some amount of emissive."); 48 | public static GUIContent emissiveColorWarning = new GUIContent ("Ensure emissive color is non-black for emission to have effect."); 49 | public static readonly string[] blendNames = Enum.GetNames (typeof (BlendMode)); 50 | } 51 | 52 | MaterialProperty blendMode = null; 53 | MaterialProperty albedoMap = null; 54 | MaterialProperty albedoColor = null; 55 | MaterialProperty alphaCutoff = null; 56 | MaterialProperty specularMap = null; 57 | MaterialProperty specularColor = null; 58 | MaterialProperty metallicMap = null; 59 | MaterialProperty metallic = null; 60 | MaterialProperty smoothness = null; 61 | MaterialProperty bumpScale = null; 62 | MaterialProperty bumpMap = null; 63 | MaterialProperty occlusionStrength = null; 64 | MaterialProperty occlusionMap = null; 65 | MaterialProperty heigtMapScale = null; 66 | MaterialProperty heightMap = null; 67 | MaterialProperty emissionColorForRendering = null; 68 | MaterialProperty emissionMap = null; 69 | MaterialProperty detailMask = null; 70 | MaterialProperty detailAlbedoMap = null; 71 | MaterialProperty detailNormalMapScale = null; 72 | MaterialProperty detailNormalMap = null; 73 | MaterialProperty uvSetSecondary = null; 74 | 75 | MaterialEditor m_MaterialEditor; 76 | WorkflowMode m_WorkflowMode = WorkflowMode.Specular; 77 | ColorPickerHDRConfig m_ColorPickerHDRConfig = new ColorPickerHDRConfig(0f, 99f, 1/99f, 3f); 78 | 79 | bool m_FirstTimeApply = true; 80 | 81 | public void FindProperties (MaterialProperty[] props) 82 | { 83 | blendMode = FindProperty ("_Mode", props); 84 | albedoMap = FindProperty ("_MainTex", props); 85 | albedoColor = FindProperty ("_Color", props); 86 | alphaCutoff = FindProperty ("_Cutoff", props); 87 | specularMap = FindProperty ("_SpecGlossMap", props, false); 88 | specularColor = FindProperty ("_SpecColor", props, false); 89 | metallicMap = FindProperty ("_MetallicGlossMap", props, false); 90 | metallic = FindProperty ("_Metallic", props, false); 91 | if (specularMap != null && specularColor != null) 92 | m_WorkflowMode = WorkflowMode.Specular; 93 | else if (metallicMap != null && metallic != null) 94 | m_WorkflowMode = WorkflowMode.Metallic; 95 | else 96 | m_WorkflowMode = WorkflowMode.Dielectric; 97 | smoothness = FindProperty ("_Glossiness", props); 98 | bumpScale = FindProperty ("_BumpScale", props); 99 | bumpMap = FindProperty ("_BumpMap", props); 100 | heigtMapScale = FindProperty ("_Parallax", props); 101 | heightMap = FindProperty("_ParallaxMap", props); 102 | occlusionStrength = FindProperty ("_OcclusionStrength", props); 103 | occlusionMap = FindProperty ("_OcclusionMap", props); 104 | emissionColorForRendering = FindProperty ("_EmissionColor", props); 105 | emissionMap = FindProperty ("_EmissionMap", props); 106 | detailMask = FindProperty ("_DetailMask", props); 107 | detailAlbedoMap = FindProperty ("_DetailAlbedoMap", props); 108 | detailNormalMapScale = FindProperty ("_DetailNormalMapScale", props); 109 | detailNormalMap = FindProperty ("_DetailNormalMap", props); 110 | uvSetSecondary = FindProperty ("_UVSec", props); 111 | } 112 | 113 | public override void OnGUI (MaterialEditor materialEditor, MaterialProperty[] props) 114 | { 115 | FindProperties (props); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly 116 | m_MaterialEditor = materialEditor; 117 | Material material = materialEditor.target as Material; 118 | 119 | ShaderPropertiesGUI (material); 120 | 121 | // Make sure that needed keywords are set up if we're switching some existing 122 | // material to a standard shader. 123 | if (m_FirstTimeApply) 124 | { 125 | SetMaterialKeywords (material, m_WorkflowMode); 126 | m_FirstTimeApply = false; 127 | } 128 | } 129 | 130 | public void ShaderPropertiesGUI (Material material) 131 | { 132 | // Use default labelWidth 133 | EditorGUIUtility.labelWidth = 0f; 134 | 135 | // Detect any changes to the material 136 | EditorGUI.BeginChangeCheck(); 137 | { 138 | BlendModePopup(); 139 | 140 | // Primary properties 141 | GUILayout.Label (Styles.primaryMapsText, EditorStyles.boldLabel); 142 | DoAlbedoArea(material); 143 | DoSpecularMetallicArea(); 144 | m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpScale : null); 145 | m_MaterialEditor.TexturePropertySingleLine(Styles.heightMapText, heightMap, heightMap.textureValue != null ? heigtMapScale : null); 146 | m_MaterialEditor.TexturePropertySingleLine(Styles.occlusionText, occlusionMap, occlusionMap.textureValue != null ? occlusionStrength : null); 147 | DoEmissionArea(material); 148 | m_MaterialEditor.TexturePropertySingleLine(Styles.detailMaskText, detailMask); 149 | EditorGUI.BeginChangeCheck(); 150 | m_MaterialEditor.TextureScaleOffsetProperty(albedoMap); 151 | if (EditorGUI.EndChangeCheck()) 152 | emissionMap.textureScaleAndOffset = albedoMap.textureScaleAndOffset; // Apply the main texture scale and offset to the emission texture as well, for Enlighten's sake 153 | 154 | EditorGUILayout.Space(); 155 | 156 | // Secondary properties 157 | GUILayout.Label(Styles.secondaryMapsText, EditorStyles.boldLabel); 158 | m_MaterialEditor.TexturePropertySingleLine(Styles.detailAlbedoText, detailAlbedoMap); 159 | m_MaterialEditor.TexturePropertySingleLine(Styles.detailNormalMapText, detailNormalMap, detailNormalMapScale); 160 | m_MaterialEditor.TextureScaleOffsetProperty(detailAlbedoMap); 161 | m_MaterialEditor.ShaderProperty(uvSetSecondary, Styles.uvSetLabel.text); 162 | } 163 | if (EditorGUI.EndChangeCheck()) 164 | { 165 | foreach (var obj in blendMode.targets) 166 | MaterialChanged((Material)obj, m_WorkflowMode); 167 | } 168 | } 169 | 170 | internal void DetermineWorkflow(MaterialProperty[] props) 171 | { 172 | if (FindProperty("_SpecGlossMap", props, false) != null && FindProperty("_SpecColor", props, false) != null) 173 | m_WorkflowMode = WorkflowMode.Specular; 174 | else if (FindProperty("_MetallicGlossMap", props, false) != null && FindProperty("_Metallic", props, false) != null) 175 | m_WorkflowMode = WorkflowMode.Metallic; 176 | else 177 | m_WorkflowMode = WorkflowMode.Dielectric; 178 | } 179 | 180 | public override void AssignNewShaderToMaterial (Material material, Shader oldShader, Shader newShader) 181 | { 182 | // _Emission property is lost after assigning Standard shader to the material 183 | // thus transfer it before assigning the new shader 184 | if (material.HasProperty("_Emission")) 185 | { 186 | material.SetColor("_EmissionColor", material.GetColor("_Emission")); 187 | } 188 | 189 | base.AssignNewShaderToMaterial(material, oldShader, newShader); 190 | 191 | if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/")) 192 | return; 193 | 194 | BlendMode blendMode = BlendMode.Opaque; 195 | if (oldShader.name.Contains("/Transparent/Cutout/")) 196 | { 197 | blendMode = BlendMode.Cutout; 198 | } 199 | else if (oldShader.name.Contains("/Transparent/")) 200 | { 201 | // NOTE: legacy shaders did not provide physically based transparency 202 | // therefore Fade mode 203 | blendMode = BlendMode.Fade; 204 | } 205 | material.SetFloat("_Mode", (float)blendMode); 206 | 207 | DetermineWorkflow( MaterialEditor.GetMaterialProperties (new Material[] { material }) ); 208 | MaterialChanged(material, m_WorkflowMode); 209 | } 210 | 211 | void BlendModePopup() 212 | { 213 | EditorGUI.showMixedValue = blendMode.hasMixedValue; 214 | var mode = (BlendMode)blendMode.floatValue; 215 | 216 | EditorGUI.BeginChangeCheck(); 217 | mode = (BlendMode)EditorGUILayout.Popup(Styles.renderingMode, (int)mode, Styles.blendNames); 218 | if (EditorGUI.EndChangeCheck()) 219 | { 220 | m_MaterialEditor.RegisterPropertyChangeUndo("Rendering Mode"); 221 | blendMode.floatValue = (float)mode; 222 | } 223 | 224 | EditorGUI.showMixedValue = false; 225 | } 226 | 227 | void DoAlbedoArea(Material material) 228 | { 229 | m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor); 230 | if (((BlendMode)material.GetFloat("_Mode") == BlendMode.Cutout)) 231 | { 232 | m_MaterialEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel+1); 233 | } 234 | } 235 | 236 | void DoEmissionArea(Material material) 237 | { 238 | float brightness = emissionColorForRendering.colorValue.maxColorComponent; 239 | bool showHelpBox = !HasValidEmissiveKeyword(material); 240 | bool showEmissionColorAndGIControls = brightness > 0.0f; 241 | 242 | bool hadEmissionTexture = emissionMap.textureValue != null; 243 | 244 | // Texture and HDR color controls 245 | m_MaterialEditor.TexturePropertyWithHDRColor(Styles.emissionText, emissionMap, emissionColorForRendering, m_ColorPickerHDRConfig, false); 246 | 247 | // If texture was assigned and color was black set color to white 248 | if (emissionMap.textureValue != null && !hadEmissionTexture && brightness <= 0f) 249 | emissionColorForRendering.colorValue = Color.white; 250 | 251 | // Dynamic Lightmapping mode 252 | if (showEmissionColorAndGIControls) 253 | { 254 | bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled(emissionColorForRendering.colorValue); 255 | EditorGUI.BeginDisabledGroup(!shouldEmissionBeEnabled); 256 | 257 | m_MaterialEditor.LightmapEmissionProperty (MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1); 258 | 259 | EditorGUI.EndDisabledGroup(); 260 | } 261 | 262 | if (showHelpBox) 263 | { 264 | EditorGUILayout.HelpBox(Styles.emissiveWarning.text, MessageType.Warning); 265 | } 266 | } 267 | 268 | void DoSpecularMetallicArea() 269 | { 270 | if (m_WorkflowMode == WorkflowMode.Specular) 271 | { 272 | if (specularMap.textureValue == null) 273 | m_MaterialEditor.TexturePropertyTwoLines(Styles.specularMapText, specularMap, specularColor, Styles.smoothnessText, smoothness); 274 | else 275 | m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specularMap); 276 | 277 | } 278 | else if (m_WorkflowMode == WorkflowMode.Metallic) 279 | { 280 | if (metallicMap.textureValue == null) 281 | m_MaterialEditor.TexturePropertyTwoLines(Styles.metallicMapText, metallicMap, metallic, Styles.smoothnessText, smoothness); 282 | else 283 | m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicMap); 284 | } 285 | } 286 | 287 | public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode) 288 | { 289 | switch (blendMode) 290 | { 291 | case BlendMode.Opaque: 292 | material.SetOverrideTag("RenderType", ""); 293 | material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); 294 | material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); 295 | material.SetInt("_ZWrite", 1); 296 | material.DisableKeyword("_ALPHATEST_ON"); 297 | material.DisableKeyword("_ALPHABLEND_ON"); 298 | material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); 299 | material.renderQueue = -1; 300 | break; 301 | case BlendMode.Cutout: 302 | material.SetOverrideTag("RenderType", "TransparentCutout"); 303 | material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); 304 | material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); 305 | material.SetInt("_ZWrite", 1); 306 | material.EnableKeyword("_ALPHATEST_ON"); 307 | material.DisableKeyword("_ALPHABLEND_ON"); 308 | material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); 309 | material.renderQueue = 2450; 310 | break; 311 | case BlendMode.Fade: 312 | material.SetOverrideTag("RenderType", "Transparent"); 313 | material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); 314 | material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); 315 | material.SetInt("_ZWrite", 0); 316 | material.DisableKeyword("_ALPHATEST_ON"); 317 | material.EnableKeyword("_ALPHABLEND_ON"); 318 | material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); 319 | material.renderQueue = 3000; 320 | break; 321 | case BlendMode.Transparent: 322 | material.SetOverrideTag("RenderType", "Transparent"); 323 | material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); 324 | material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); 325 | material.SetInt("_ZWrite", 0); 326 | material.DisableKeyword("_ALPHATEST_ON"); 327 | material.DisableKeyword("_ALPHABLEND_ON"); 328 | material.EnableKeyword("_ALPHAPREMULTIPLY_ON"); 329 | material.renderQueue = 3000; 330 | break; 331 | } 332 | } 333 | 334 | static bool ShouldEmissionBeEnabled (Color color) 335 | { 336 | return color.maxColorComponent > (0.1f / 255.0f); 337 | } 338 | 339 | static void SetMaterialKeywords(Material material, WorkflowMode workflowMode) 340 | { 341 | // Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation 342 | // (MaterialProperty value might come from renderer material property block) 343 | SetKeyword (material, "_NORMALMAP", material.GetTexture ("_BumpMap") || material.GetTexture ("_DetailNormalMap")); 344 | if (workflowMode == WorkflowMode.Specular) 345 | SetKeyword (material, "_SPECGLOSSMAP", material.GetTexture ("_SpecGlossMap")); 346 | else if (workflowMode == WorkflowMode.Metallic) 347 | SetKeyword (material, "_METALLICGLOSSMAP", material.GetTexture ("_MetallicGlossMap")); 348 | SetKeyword (material, "_PARALLAXMAP", material.GetTexture ("_ParallaxMap")); 349 | SetKeyword (material, "_DETAIL_MULX2", material.GetTexture ("_DetailAlbedoMap") || material.GetTexture ("_DetailNormalMap")); 350 | 351 | bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled (material.GetColor("_EmissionColor")); 352 | SetKeyword (material, "_EMISSION", shouldEmissionBeEnabled); 353 | 354 | // Setup lightmap emissive flags 355 | MaterialGlobalIlluminationFlags flags = material.globalIlluminationFlags; 356 | if ((flags & (MaterialGlobalIlluminationFlags.BakedEmissive | MaterialGlobalIlluminationFlags.RealtimeEmissive)) != 0) 357 | { 358 | flags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack; 359 | if (!shouldEmissionBeEnabled) 360 | flags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack; 361 | 362 | material.globalIlluminationFlags = flags; 363 | } 364 | } 365 | 366 | bool HasValidEmissiveKeyword (Material material) 367 | { 368 | // Material animation might be out of sync with the material keyword. 369 | // So if the emission support is disabled on the material, but the property blocks have a value that requires it, then we need to show a warning. 370 | // (note: (Renderer MaterialPropertyBlock applies its values to emissionColorForRendering)) 371 | bool hasEmissionKeyword = material.IsKeywordEnabled ("_EMISSION"); 372 | if (!hasEmissionKeyword && ShouldEmissionBeEnabled (emissionColorForRendering.colorValue)) 373 | return false; 374 | else 375 | return true; 376 | } 377 | 378 | static void MaterialChanged(Material material, WorkflowMode workflowMode) 379 | { 380 | SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode")); 381 | 382 | SetMaterialKeywords(material, workflowMode); 383 | } 384 | 385 | static void SetKeyword(Material m, string keyword, bool state) 386 | { 387 | if (state) 388 | m.EnableKeyword (keyword); 389 | else 390 | m.DisableKeyword (keyword); 391 | } 392 | } 393 | 394 | } // namespace UnityEditor 395 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Unity EULA can be found here: 2 | https://unity3d.com/legal/eula -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnityCustomShaders 2 | My custom set of Standard Unity (v5+) shaders as used in my current game 3 | in development: https://twitter.com/hauntedoutbreak 4 | 5 | - The modification of the Standard shader allow to use the alpha channel of 6 | the material albedo texture as occlusion data (grayscale) when using "Opaque" 7 | rendering mode, the modified shader is called "CustomStandard". 8 | 9 | - The modifications of the Standard terrain shaders allow to use a custom 10 | splatmap mix in order to hide ground texture tiling, the modified shader is 11 | called "Nature/Terrain/CustomStandard". 12 | -------------------------------------------------------------------------------- /StandardShader/CustomStandard.shader: -------------------------------------------------------------------------------- 1 | Shader "Standard" 2 | { 3 | Properties 4 | { 5 | _Color("Color", Color) = (1,1,1,1) 6 | _MainTex("Albedo", 2D) = "white" {} 7 | 8 | _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 9 | 10 | _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5 11 | [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 12 | _MetallicGlossMap("Metallic", 2D) = "white" {} 13 | 14 | _BumpScale("Scale", Float) = 1.0 15 | _BumpMap("Normal Map", 2D) = "bump" {} 16 | 17 | _Parallax ("Height Scale", Range (0.005, 0.08)) = 0.02 18 | _ParallaxMap ("Height Map", 2D) = "black" {} 19 | 20 | _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0 21 | _OcclusionMap("Occlusion", 2D) = "white" {} 22 | 23 | _EmissionColor("Color", Color) = (0,0,0) 24 | _EmissionMap("Emission", 2D) = "white" {} 25 | 26 | _DetailMask("Detail Mask", 2D) = "white" {} 27 | 28 | _DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {} 29 | _DetailNormalMapScale("Scale", Float) = 1.0 30 | _DetailNormalMap("Normal Map", 2D) = "bump" {} 31 | 32 | [Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0 33 | 34 | 35 | // Blending state 36 | [HideInInspector] _Mode ("__mode", Float) = 0.0 37 | [HideInInspector] _SrcBlend ("__src", Float) = 1.0 38 | [HideInInspector] _DstBlend ("__dst", Float) = 0.0 39 | [HideInInspector] _ZWrite ("__zw", Float) = 1.0 40 | } 41 | 42 | CGINCLUDE 43 | #define UNITY_SETUP_BRDF_INPUT MetallicSetup 44 | ENDCG 45 | 46 | SubShader 47 | { 48 | Tags { "RenderType"="Opaque" "PerformanceChecks"="False" } 49 | LOD 300 50 | 51 | 52 | // ------------------------------------------------------------------ 53 | // Base forward pass (directional light, emission, lightmaps, ...) 54 | Pass 55 | { 56 | Name "FORWARD" 57 | Tags { "LightMode" = "ForwardBase" } 58 | 59 | Blend [_SrcBlend] [_DstBlend] 60 | ZWrite [_ZWrite] 61 | 62 | CGPROGRAM 63 | #pragma target 3.0 64 | // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT 65 | #pragma exclude_renderers gles 66 | 67 | // ------------------------------------- 68 | 69 | #pragma shader_feature _NORMALMAP 70 | #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON 71 | #pragma shader_feature _EMISSION 72 | #pragma shader_feature _METALLICGLOSSMAP 73 | #pragma shader_feature ___ _DETAIL_MULX2 74 | #pragma shader_feature _PARALLAXMAP 75 | 76 | #pragma multi_compile_fwdbase 77 | #pragma multi_compile_fog 78 | 79 | #pragma vertex vertBase 80 | #pragma fragment fragBase 81 | #include "UnityStandardCoreForward.cginc" 82 | 83 | ENDCG 84 | } 85 | // ------------------------------------------------------------------ 86 | // Additive forward pass (one light per pass) 87 | Pass 88 | { 89 | Name "FORWARD_DELTA" 90 | Tags { "LightMode" = "ForwardAdd" } 91 | Blend [_SrcBlend] One 92 | Fog { Color (0,0,0,0) } // in additive pass fog should be black 93 | ZWrite Off 94 | ZTest LEqual 95 | 96 | CGPROGRAM 97 | #pragma target 3.0 98 | // GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT 99 | #pragma exclude_renderers gles 100 | 101 | // ------------------------------------- 102 | 103 | 104 | #pragma shader_feature _NORMALMAP 105 | #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON 106 | #pragma shader_feature _METALLICGLOSSMAP 107 | #pragma shader_feature ___ _DETAIL_MULX2 108 | #pragma shader_feature _PARALLAXMAP 109 | 110 | #pragma multi_compile_fwdadd_fullshadows 111 | #pragma multi_compile_fog 112 | 113 | #pragma vertex vertAdd 114 | #pragma fragment fragAdd 115 | #include "UnityStandardCoreForward.cginc" 116 | 117 | ENDCG 118 | } 119 | // ------------------------------------------------------------------ 120 | // Shadow rendering pass 121 | Pass { 122 | Name "ShadowCaster" 123 | Tags { "LightMode" = "ShadowCaster" } 124 | 125 | ZWrite On ZTest LEqual 126 | 127 | CGPROGRAM 128 | #pragma target 3.0 129 | // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT 130 | #pragma exclude_renderers gles 131 | 132 | // ------------------------------------- 133 | 134 | 135 | #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON 136 | #pragma multi_compile_shadowcaster 137 | 138 | #pragma vertex vertShadowCaster 139 | #pragma fragment fragShadowCaster 140 | 141 | #include "UnityStandardShadow.cginc" 142 | 143 | ENDCG 144 | } 145 | // ------------------------------------------------------------------ 146 | // Deferred pass 147 | Pass 148 | { 149 | Name "DEFERRED" 150 | Tags { "LightMode" = "Deferred" } 151 | 152 | CGPROGRAM 153 | #pragma target 3.0 154 | // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT 155 | #pragma exclude_renderers nomrt gles 156 | 157 | 158 | // ------------------------------------- 159 | 160 | #pragma shader_feature _NORMALMAP 161 | #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON 162 | #pragma shader_feature _EMISSION 163 | #pragma shader_feature _METALLICGLOSSMAP 164 | #pragma shader_feature ___ _DETAIL_MULX2 165 | #pragma shader_feature _PARALLAXMAP 166 | 167 | #pragma multi_compile ___ UNITY_HDR_ON 168 | #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON 169 | #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE 170 | #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON 171 | 172 | #pragma vertex vertDeferred 173 | #pragma fragment fragDeferred 174 | 175 | #include "UnityStandardCore.cginc" 176 | 177 | ENDCG 178 | } 179 | 180 | // ------------------------------------------------------------------ 181 | // Extracts information for lightmapping, GI (emission, albedo, ...) 182 | // This pass it not used during regular rendering. 183 | Pass 184 | { 185 | Name "META" 186 | Tags { "LightMode"="Meta" } 187 | 188 | Cull Off 189 | 190 | CGPROGRAM 191 | #pragma vertex vert_meta 192 | #pragma fragment frag_meta 193 | 194 | #pragma shader_feature _EMISSION 195 | #pragma shader_feature _METALLICGLOSSMAP 196 | #pragma shader_feature ___ _DETAIL_MULX2 197 | 198 | #include "UnityStandardMeta.cginc" 199 | ENDCG 200 | } 201 | } 202 | 203 | SubShader 204 | { 205 | Tags { "RenderType"="Opaque" "PerformanceChecks"="False" } 206 | LOD 150 207 | 208 | // ------------------------------------------------------------------ 209 | // Base forward pass (directional light, emission, lightmaps, ...) 210 | Pass 211 | { 212 | Name "FORWARD" 213 | Tags { "LightMode" = "ForwardBase" } 214 | 215 | Blend [_SrcBlend] [_DstBlend] 216 | ZWrite [_ZWrite] 217 | 218 | CGPROGRAM 219 | #pragma target 2.0 220 | 221 | #pragma shader_feature _NORMALMAP 222 | #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON 223 | #pragma shader_feature _EMISSION 224 | #pragma shader_feature _METALLICGLOSSMAP 225 | #pragma shader_feature ___ _DETAIL_MULX2 226 | // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP 227 | 228 | #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE 229 | 230 | #pragma multi_compile_fwdbase 231 | #pragma multi_compile_fog 232 | 233 | #pragma vertex vertBase 234 | #pragma fragment fragBase 235 | #include "UnityStandardCoreForward.cginc" 236 | 237 | ENDCG 238 | } 239 | // ------------------------------------------------------------------ 240 | // Additive forward pass (one light per pass) 241 | Pass 242 | { 243 | Name "FORWARD_DELTA" 244 | Tags { "LightMode" = "ForwardAdd" } 245 | Blend [_SrcBlend] One 246 | Fog { Color (0,0,0,0) } // in additive pass fog should be black 247 | ZWrite Off 248 | ZTest LEqual 249 | 250 | CGPROGRAM 251 | #pragma target 2.0 252 | 253 | #pragma shader_feature _NORMALMAP 254 | #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON 255 | #pragma shader_feature _METALLICGLOSSMAP 256 | #pragma shader_feature ___ _DETAIL_MULX2 257 | // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP 258 | #pragma skip_variants SHADOWS_SOFT 259 | 260 | #pragma multi_compile_fwdadd_fullshadows 261 | #pragma multi_compile_fog 262 | 263 | #pragma vertex vertAdd 264 | #pragma fragment fragAdd 265 | #include "UnityStandardCoreForward.cginc" 266 | 267 | ENDCG 268 | } 269 | // ------------------------------------------------------------------ 270 | // Shadow rendering pass 271 | Pass { 272 | Name "ShadowCaster" 273 | Tags { "LightMode" = "ShadowCaster" } 274 | 275 | ZWrite On ZTest LEqual 276 | 277 | CGPROGRAM 278 | #pragma target 2.0 279 | 280 | #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON 281 | #pragma skip_variants SHADOWS_SOFT 282 | #pragma multi_compile_shadowcaster 283 | 284 | #pragma vertex vertShadowCaster 285 | #pragma fragment fragShadowCaster 286 | 287 | #include "UnityStandardShadow.cginc" 288 | 289 | ENDCG 290 | } 291 | 292 | // ------------------------------------------------------------------ 293 | // Extracts information for lightmapping, GI (emission, albedo, ...) 294 | // This pass it not used during regular rendering. 295 | Pass 296 | { 297 | Name "META" 298 | Tags { "LightMode"="Meta" } 299 | 300 | Cull Off 301 | 302 | CGPROGRAM 303 | #pragma vertex vert_meta 304 | #pragma fragment frag_meta 305 | 306 | #pragma shader_feature _EMISSION 307 | #pragma shader_feature _METALLICGLOSSMAP 308 | #pragma shader_feature ___ _DETAIL_MULX2 309 | 310 | #include "UnityStandardMeta.cginc" 311 | ENDCG 312 | } 313 | } 314 | 315 | 316 | FallBack "VertexLit" 317 | CustomEditor "StandardShaderGUI" 318 | } 319 | -------------------------------------------------------------------------------- /StandardShader/CustomUnityStandardCore.cginc: -------------------------------------------------------------------------------- 1 | #ifndef UNITY_STANDARD_CORE_INCLUDED 2 | #define UNITY_STANDARD_CORE_INCLUDED 3 | 4 | #include "UnityCG.cginc" 5 | #include "UnityShaderVariables.cginc" 6 | #include "UnityStandardConfig.cginc" 7 | #include "UnityStandardInput.cginc" 8 | #include "UnityPBSLighting.cginc" 9 | #include "UnityStandardUtils.cginc" 10 | #include "UnityStandardBRDF.cginc" 11 | 12 | #include "AutoLight.cginc" 13 | 14 | 15 | //------------------------------------------------------------------------------------- 16 | // counterpart for NormalizePerPixelNormal 17 | // skips normalization per-vertex and expects normalization to happen per-pixel 18 | half3 NormalizePerVertexNormal (half3 n) 19 | { 20 | #if (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE 21 | return normalize(n); 22 | #else 23 | return n; // will normalize per-pixel instead 24 | #endif 25 | } 26 | 27 | half3 NormalizePerPixelNormal (half3 n) 28 | { 29 | #if (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE 30 | return n; 31 | #else 32 | return normalize(n); 33 | #endif 34 | } 35 | 36 | //------------------------------------------------------------------------------------- 37 | UnityLight MainLight (half3 normalWorld) 38 | { 39 | UnityLight l; 40 | #ifdef LIGHTMAP_OFF 41 | 42 | l.color = _LightColor0.rgb; 43 | l.dir = _WorldSpaceLightPos0.xyz; 44 | l.ndotl = LambertTerm (normalWorld, l.dir); 45 | #else 46 | // no light specified by the engine 47 | // analytical light might be extracted from Lightmap data later on in the shader depending on the Lightmap type 48 | l.color = half3(0.f, 0.f, 0.f); 49 | l.ndotl = 0.f; 50 | l.dir = half3(0.f, 0.f, 0.f); 51 | #endif 52 | 53 | return l; 54 | } 55 | 56 | UnityLight AdditiveLight (half3 normalWorld, half3 lightDir, half atten) 57 | { 58 | UnityLight l; 59 | 60 | l.color = _LightColor0.rgb; 61 | l.dir = lightDir; 62 | #ifndef USING_DIRECTIONAL_LIGHT 63 | l.dir = NormalizePerPixelNormal(l.dir); 64 | #endif 65 | l.ndotl = LambertTerm (normalWorld, l.dir); 66 | 67 | // shadow the light 68 | l.color *= atten; 69 | return l; 70 | } 71 | 72 | UnityLight DummyLight (half3 normalWorld) 73 | { 74 | UnityLight l; 75 | l.color = 0; 76 | l.dir = half3 (0,1,0); 77 | l.ndotl = LambertTerm (normalWorld, l.dir); 78 | return l; 79 | } 80 | 81 | UnityIndirect ZeroIndirect () 82 | { 83 | UnityIndirect ind; 84 | ind.diffuse = 0; 85 | ind.specular = 0; 86 | return ind; 87 | } 88 | 89 | //------------------------------------------------------------------------------------- 90 | // Common fragment setup 91 | 92 | // deprecated 93 | half3 WorldNormal(half4 tan2world[3]) 94 | { 95 | return normalize(tan2world[2].xyz); 96 | } 97 | 98 | // deprecated 99 | #ifdef _TANGENT_TO_WORLD 100 | half3x3 ExtractTangentToWorldPerPixel(half4 tan2world[3]) 101 | { 102 | half3 t = tan2world[0].xyz; 103 | half3 b = tan2world[1].xyz; 104 | half3 n = tan2world[2].xyz; 105 | 106 | #if UNITY_TANGENT_ORTHONORMALIZE 107 | n = NormalizePerPixelNormal(n); 108 | 109 | // ortho-normalize Tangent 110 | t = normalize (t - n * dot(t, n)); 111 | 112 | // recalculate Binormal 113 | half3 newB = cross(n, t); 114 | b = newB * sign (dot (newB, b)); 115 | #endif 116 | 117 | return half3x3(t, b, n); 118 | } 119 | #else 120 | half3x3 ExtractTangentToWorldPerPixel(half4 tan2world[3]) 121 | { 122 | return half3x3(0,0,0,0,0,0,0,0,0); 123 | } 124 | #endif 125 | 126 | half3 PerPixelWorldNormal(float4 i_tex, half4 tangentToWorld[3]) 127 | { 128 | #ifdef _NORMALMAP 129 | half3 tangent = tangentToWorld[0].xyz; 130 | half3 binormal = tangentToWorld[1].xyz; 131 | half3 normal = tangentToWorld[2].xyz; 132 | 133 | #if UNITY_TANGENT_ORTHONORMALIZE 134 | normal = NormalizePerPixelNormal(normal); 135 | 136 | // ortho-normalize Tangent 137 | tangent = normalize (tangent - normal * dot(tangent, normal)); 138 | 139 | // recalculate Binormal 140 | half3 newB = cross(normal, tangent); 141 | binormal = newB * sign (dot (newB, binormal)); 142 | #endif 143 | 144 | half3 normalTangent = NormalInTangentSpace(i_tex); 145 | half3 normalWorld = NormalizePerPixelNormal(tangent * normalTangent.x + binormal * normalTangent.y + normal * normalTangent.z); // @TODO: see if we can squeeze this normalize on SM2.0 as well 146 | #else 147 | half3 normalWorld = normalize(tangentToWorld[2].xyz); 148 | #endif 149 | return normalWorld; 150 | } 151 | 152 | #ifdef _PARALLAXMAP 153 | #define IN_VIEWDIR4PARALLAX(i) NormalizePerPixelNormal(half3(i.tangentToWorldAndParallax[0].w,i.tangentToWorldAndParallax[1].w,i.tangentToWorldAndParallax[2].w)) 154 | #define IN_VIEWDIR4PARALLAX_FWDADD(i) NormalizePerPixelNormal(i.viewDirForParallax.xyz) 155 | #else 156 | #define IN_VIEWDIR4PARALLAX(i) half3(0,0,0) 157 | #define IN_VIEWDIR4PARALLAX_FWDADD(i) half3(0,0,0) 158 | #endif 159 | 160 | #if UNITY_SPECCUBE_BOX_PROJECTION 161 | #define IN_WORLDPOS(i) i.posWorld 162 | #else 163 | #define IN_WORLDPOS(i) half3(0,0,0) 164 | #endif 165 | 166 | #define IN_LIGHTDIR_FWDADD(i) half3(i.tangentToWorldAndLightDir[0].w, i.tangentToWorldAndLightDir[1].w, i.tangentToWorldAndLightDir[2].w) 167 | 168 | #define FRAGMENT_SETUP(x) FragmentCommonData x = \ 169 | FragmentSetup(i.tex, i.eyeVec, IN_VIEWDIR4PARALLAX(i), i.tangentToWorldAndParallax, IN_WORLDPOS(i)); 170 | 171 | #define FRAGMENT_SETUP_FWDADD(x) FragmentCommonData x = \ 172 | FragmentSetup(i.tex, i.eyeVec, IN_VIEWDIR4PARALLAX_FWDADD(i), i.tangentToWorldAndLightDir, half3(0,0,0)); 173 | 174 | struct FragmentCommonData 175 | { 176 | half3 diffColor, specColor; 177 | // Note: oneMinusRoughness & oneMinusReflectivity for optimization purposes, mostly for DX9 SM2.0 level. 178 | // Most of the math is being done on these (1-x) values, and that saves a few precious ALU slots. 179 | half oneMinusReflectivity, oneMinusRoughness; 180 | half3 normalWorld, eyeVec, posWorld; 181 | half alpha; 182 | 183 | #if UNITY_OPTIMIZE_TEXCUBELOD || UNITY_STANDARD_SIMPLE 184 | half3 reflUVW; 185 | #endif 186 | 187 | #if UNITY_STANDARD_SIMPLE 188 | half3 tangentSpaceNormal; 189 | #endif 190 | }; 191 | 192 | #ifndef UNITY_SETUP_BRDF_INPUT 193 | #define UNITY_SETUP_BRDF_INPUT SpecularSetup 194 | #endif 195 | 196 | inline FragmentCommonData SpecularSetup (float4 i_tex) 197 | { 198 | half4 specGloss = SpecularGloss(i_tex.xy); 199 | half3 specColor = specGloss.rgb; 200 | half oneMinusRoughness = specGloss.a; 201 | 202 | half oneMinusReflectivity; 203 | half3 diffColor = EnergyConservationBetweenDiffuseAndSpecular (Albedo(i_tex), specColor, /*out*/ oneMinusReflectivity); 204 | 205 | FragmentCommonData o = (FragmentCommonData)0; 206 | o.diffColor = diffColor; 207 | o.specColor = specColor; 208 | o.oneMinusReflectivity = oneMinusReflectivity; 209 | o.oneMinusRoughness = oneMinusRoughness; 210 | return o; 211 | } 212 | 213 | inline FragmentCommonData MetallicSetup (float4 i_tex) 214 | { 215 | half2 metallicGloss = MetallicGloss(i_tex.xy); 216 | half metallic = metallicGloss.x; 217 | half oneMinusRoughness = metallicGloss.y; // this is 1 minus the square root of real roughness m. 218 | 219 | half oneMinusReflectivity; 220 | half3 specColor; 221 | half3 diffColor = DiffuseAndSpecularFromMetallic (Albedo(i_tex), metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity); 222 | 223 | FragmentCommonData o = (FragmentCommonData)0; 224 | o.diffColor = diffColor; 225 | o.specColor = specColor; 226 | o.oneMinusReflectivity = oneMinusReflectivity; 227 | o.oneMinusRoughness = oneMinusRoughness; 228 | return o; 229 | } 230 | 231 | inline FragmentCommonData FragmentSetup (float4 i_tex, half3 i_eyeVec, half3 i_viewDirForParallax, half4 tangentToWorld[3], half3 i_posWorld) 232 | { 233 | i_tex = Parallax(i_tex, i_viewDirForParallax); 234 | 235 | half alpha = Alpha(i_tex.xy); 236 | #if defined(_ALPHATEST_ON) 237 | clip (alpha - _Cutoff); 238 | #endif 239 | 240 | FragmentCommonData o = UNITY_SETUP_BRDF_INPUT (i_tex); 241 | o.normalWorld = PerPixelWorldNormal(i_tex, tangentToWorld); 242 | o.eyeVec = NormalizePerPixelNormal(i_eyeVec); 243 | o.posWorld = i_posWorld; 244 | 245 | // NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha) 246 | o.diffColor = PreMultiplyAlpha (o.diffColor, alpha, o.oneMinusReflectivity, /*out*/ o.alpha); 247 | return o; 248 | } 249 | 250 | inline UnityGI FragmentGI (FragmentCommonData s, half occlusion, half4 i_ambientOrLightmapUV, half atten, UnityLight light, bool reflections) 251 | { 252 | UnityGIInput d; 253 | d.light = light; 254 | d.worldPos = s.posWorld; 255 | d.worldViewDir = -s.eyeVec; 256 | d.atten = atten; 257 | #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON) 258 | d.ambient = 0; 259 | d.lightmapUV = i_ambientOrLightmapUV; 260 | #else 261 | d.ambient = i_ambientOrLightmapUV.rgb; 262 | d.lightmapUV = 0; 263 | #endif 264 | d.boxMax[0] = unity_SpecCube0_BoxMax; 265 | d.boxMin[0] = unity_SpecCube0_BoxMin; 266 | d.probePosition[0] = unity_SpecCube0_ProbePosition; 267 | d.probeHDR[0] = unity_SpecCube0_HDR; 268 | 269 | d.boxMax[1] = unity_SpecCube1_BoxMax; 270 | d.boxMin[1] = unity_SpecCube1_BoxMin; 271 | d.probePosition[1] = unity_SpecCube1_ProbePosition; 272 | d.probeHDR[1] = unity_SpecCube1_HDR; 273 | 274 | if(reflections) 275 | { 276 | Unity_GlossyEnvironmentData g; 277 | g.roughness = 1 - s.oneMinusRoughness; 278 | #if UNITY_OPTIMIZE_TEXCUBELOD || UNITY_STANDARD_SIMPLE 279 | g.reflUVW = s.reflUVW; 280 | #else 281 | g.reflUVW = reflect(s.eyeVec, s.normalWorld); 282 | #endif 283 | 284 | return UnityGlobalIllumination (d, occlusion, s.normalWorld, g); 285 | } 286 | else 287 | { 288 | return UnityGlobalIllumination (d, occlusion, s.normalWorld); 289 | } 290 | } 291 | 292 | inline UnityGI FragmentGI (FragmentCommonData s, half occlusion, half4 i_ambientOrLightmapUV, half atten, UnityLight light) 293 | { 294 | return FragmentGI(s, occlusion, i_ambientOrLightmapUV, atten, light, true); 295 | } 296 | 297 | 298 | //------------------------------------------------------------------------------------- 299 | half4 OutputForward (half4 output, half alphaFromSurface) 300 | { 301 | #if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON) 302 | output.a = alphaFromSurface; 303 | #else 304 | UNITY_OPAQUE_ALPHA(output.a); 305 | #endif 306 | return output; 307 | } 308 | 309 | inline half4 VertexGIForward(VertexInput v, float3 posWorld, half3 normalWorld) 310 | { 311 | half4 ambientOrLightmapUV = 0; 312 | // Static lightmaps 313 | #ifndef LIGHTMAP_OFF 314 | ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; 315 | ambientOrLightmapUV.zw = 0; 316 | // Sample light probe for Dynamic objects only (no static or dynamic lightmaps) 317 | #elif UNITY_SHOULD_SAMPLE_SH 318 | #ifdef VERTEXLIGHT_ON 319 | // Approximated illumination from non-important point lights 320 | ambientOrLightmapUV.rgb = Shade4PointLights ( 321 | unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0, 322 | unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb, 323 | unity_4LightAtten0, posWorld, normalWorld); 324 | #endif 325 | 326 | ambientOrLightmapUV.rgb = ShadeSHPerVertex (normalWorld, ambientOrLightmapUV.rgb); 327 | #endif 328 | 329 | #ifdef DYNAMICLIGHTMAP_ON 330 | ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; 331 | #endif 332 | 333 | return ambientOrLightmapUV; 334 | } 335 | 336 | // ------------------------------------------------------------------ 337 | // Base forward pass (directional light, emission, lightmaps, ...) 338 | 339 | struct VertexOutputForwardBase 340 | { 341 | float4 pos : SV_POSITION; 342 | float4 tex : TEXCOORD0; 343 | half3 eyeVec : TEXCOORD1; 344 | half4 tangentToWorldAndParallax[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] 345 | half4 ambientOrLightmapUV : TEXCOORD5; // SH or Lightmap UV 346 | SHADOW_COORDS(6) 347 | UNITY_FOG_COORDS(7) 348 | 349 | // next ones would not fit into SM2.0 limits, but they are always for SM3.0+ 350 | #if UNITY_SPECCUBE_BOX_PROJECTION 351 | float3 posWorld : TEXCOORD8; 352 | #endif 353 | 354 | #if UNITY_OPTIMIZE_TEXCUBELOD 355 | #if UNITY_SPECCUBE_BOX_PROJECTION 356 | half3 reflUVW : TEXCOORD9; 357 | #else 358 | half3 reflUVW : TEXCOORD8; 359 | #endif 360 | #endif 361 | }; 362 | 363 | VertexOutputForwardBase vertForwardBase (VertexInput v) 364 | { 365 | VertexOutputForwardBase o; 366 | UNITY_INITIALIZE_OUTPUT(VertexOutputForwardBase, o); 367 | 368 | float4 posWorld = mul(_Object2World, v.vertex); 369 | #if UNITY_SPECCUBE_BOX_PROJECTION 370 | o.posWorld = posWorld.xyz; 371 | #endif 372 | o.pos = mul(UNITY_MATRIX_MVP, v.vertex); 373 | o.tex = TexCoords(v); 374 | o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); 375 | float3 normalWorld = UnityObjectToWorldNormal(v.normal); 376 | #ifdef _TANGENT_TO_WORLD 377 | float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); 378 | 379 | float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); 380 | o.tangentToWorldAndParallax[0].xyz = tangentToWorld[0]; 381 | o.tangentToWorldAndParallax[1].xyz = tangentToWorld[1]; 382 | o.tangentToWorldAndParallax[2].xyz = tangentToWorld[2]; 383 | #else 384 | o.tangentToWorldAndParallax[0].xyz = 0; 385 | o.tangentToWorldAndParallax[1].xyz = 0; 386 | o.tangentToWorldAndParallax[2].xyz = normalWorld; 387 | #endif 388 | //We need this for shadow receving 389 | TRANSFER_SHADOW(o); 390 | 391 | o.ambientOrLightmapUV = VertexGIForward(v, posWorld, normalWorld); 392 | 393 | #ifdef _PARALLAXMAP 394 | TANGENT_SPACE_ROTATION; 395 | half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex)); 396 | o.tangentToWorldAndParallax[0].w = viewDirForParallax.x; 397 | o.tangentToWorldAndParallax[1].w = viewDirForParallax.y; 398 | o.tangentToWorldAndParallax[2].w = viewDirForParallax.z; 399 | #endif 400 | 401 | #if UNITY_OPTIMIZE_TEXCUBELOD 402 | o.reflUVW = reflect(o.eyeVec, normalWorld); 403 | #endif 404 | 405 | UNITY_TRANSFER_FOG(o,o.pos); 406 | return o; 407 | } 408 | 409 | half4 fragForwardBaseInternal (VertexOutputForwardBase i) 410 | { 411 | FRAGMENT_SETUP(s) 412 | #if UNITY_OPTIMIZE_TEXCUBELOD 413 | s.reflUVW = i.reflUVW; 414 | #endif 415 | 416 | UnityLight mainLight = MainLight (s.normalWorld); 417 | half atten = SHADOW_ATTENUATION(i); 418 | 419 | 420 | half occlusion = Occlusion(i.tex.xy); 421 | UnityGI gi = FragmentGI (s, occlusion, i.ambientOrLightmapUV, atten, mainLight); 422 | 423 | half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect); 424 | c.rgb += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi); 425 | c.rgb += Emission(i.tex.xy); 426 | 427 | UNITY_APPLY_FOG(i.fogCoord, c.rgb); 428 | return OutputForward (c, s.alpha); 429 | } 430 | 431 | half4 fragForwardBase (VertexOutputForwardBase i) : SV_Target // backward compatibility (this used to be the fragment entry function) 432 | { 433 | return fragForwardBaseInternal(i); 434 | } 435 | 436 | // ------------------------------------------------------------------ 437 | // Additive forward pass (one light per pass) 438 | 439 | struct VertexOutputForwardAdd 440 | { 441 | float4 pos : SV_POSITION; 442 | float4 tex : TEXCOORD0; 443 | half3 eyeVec : TEXCOORD1; 444 | half4 tangentToWorldAndLightDir[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:lightDir] 445 | LIGHTING_COORDS(5,6) 446 | UNITY_FOG_COORDS(7) 447 | 448 | // next ones would not fit into SM2.0 limits, but they are always for SM3.0+ 449 | #if defined(_PARALLAXMAP) 450 | half3 viewDirForParallax : TEXCOORD8; 451 | #endif 452 | }; 453 | 454 | VertexOutputForwardAdd vertForwardAdd (VertexInput v) 455 | { 456 | VertexOutputForwardAdd o; 457 | UNITY_INITIALIZE_OUTPUT(VertexOutputForwardAdd, o); 458 | 459 | float4 posWorld = mul(_Object2World, v.vertex); 460 | o.pos = mul(UNITY_MATRIX_MVP, v.vertex); 461 | o.tex = TexCoords(v); 462 | o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); 463 | float3 normalWorld = UnityObjectToWorldNormal(v.normal); 464 | #ifdef _TANGENT_TO_WORLD 465 | float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); 466 | 467 | float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); 468 | o.tangentToWorldAndLightDir[0].xyz = tangentToWorld[0]; 469 | o.tangentToWorldAndLightDir[1].xyz = tangentToWorld[1]; 470 | o.tangentToWorldAndLightDir[2].xyz = tangentToWorld[2]; 471 | #else 472 | o.tangentToWorldAndLightDir[0].xyz = 0; 473 | o.tangentToWorldAndLightDir[1].xyz = 0; 474 | o.tangentToWorldAndLightDir[2].xyz = normalWorld; 475 | #endif 476 | //We need this for shadow receiving 477 | TRANSFER_VERTEX_TO_FRAGMENT(o); 478 | 479 | float3 lightDir = _WorldSpaceLightPos0.xyz - posWorld.xyz * _WorldSpaceLightPos0.w; 480 | #ifndef USING_DIRECTIONAL_LIGHT 481 | lightDir = NormalizePerVertexNormal(lightDir); 482 | #endif 483 | o.tangentToWorldAndLightDir[0].w = lightDir.x; 484 | o.tangentToWorldAndLightDir[1].w = lightDir.y; 485 | o.tangentToWorldAndLightDir[2].w = lightDir.z; 486 | 487 | #ifdef _PARALLAXMAP 488 | TANGENT_SPACE_ROTATION; 489 | o.viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex)); 490 | #endif 491 | 492 | UNITY_TRANSFER_FOG(o,o.pos); 493 | return o; 494 | } 495 | 496 | half4 fragForwardAddInternal (VertexOutputForwardAdd i) 497 | { 498 | FRAGMENT_SETUP_FWDADD(s) 499 | 500 | UnityLight light = AdditiveLight (s.normalWorld, IN_LIGHTDIR_FWDADD(i), LIGHT_ATTENUATION(i)); 501 | UnityIndirect noIndirect = ZeroIndirect (); 502 | 503 | half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, light, noIndirect); 504 | 505 | UNITY_APPLY_FOG_COLOR(i.fogCoord, c.rgb, half4(0,0,0,0)); // fog towards black in additive pass 506 | return OutputForward (c, s.alpha); 507 | } 508 | 509 | half4 fragForwardAdd (VertexOutputForwardAdd i) : SV_Target // backward compatibility (this used to be the fragment entry function) 510 | { 511 | return fragForwardAddInternal(i); 512 | } 513 | 514 | // ------------------------------------------------------------------ 515 | // Deferred pass 516 | 517 | struct VertexOutputDeferred 518 | { 519 | float4 pos : SV_POSITION; 520 | float4 tex : TEXCOORD0; 521 | half3 eyeVec : TEXCOORD1; 522 | half4 tangentToWorldAndParallax[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax] 523 | half4 ambientOrLightmapUV : TEXCOORD5; // SH or Lightmap UVs 524 | #if UNITY_SPECCUBE_BOX_PROJECTION 525 | float3 posWorld : TEXCOORD6; 526 | #endif 527 | #if UNITY_OPTIMIZE_TEXCUBELOD 528 | #if UNITY_SPECCUBE_BOX_PROJECTION 529 | half3 reflUVW : TEXCOORD7; 530 | #else 531 | half3 reflUVW : TEXCOORD6; 532 | #endif 533 | #endif 534 | 535 | }; 536 | 537 | 538 | VertexOutputDeferred vertDeferred (VertexInput v) 539 | { 540 | VertexOutputDeferred o; 541 | UNITY_INITIALIZE_OUTPUT(VertexOutputDeferred, o); 542 | 543 | float4 posWorld = mul(_Object2World, v.vertex); 544 | #if UNITY_SPECCUBE_BOX_PROJECTION 545 | o.posWorld = posWorld; 546 | #endif 547 | o.pos = mul(UNITY_MATRIX_MVP, v.vertex); 548 | o.tex = TexCoords(v); 549 | o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos); 550 | float3 normalWorld = UnityObjectToWorldNormal(v.normal); 551 | #ifdef _TANGENT_TO_WORLD 552 | float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); 553 | 554 | float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); 555 | o.tangentToWorldAndParallax[0].xyz = tangentToWorld[0]; 556 | o.tangentToWorldAndParallax[1].xyz = tangentToWorld[1]; 557 | o.tangentToWorldAndParallax[2].xyz = tangentToWorld[2]; 558 | #else 559 | o.tangentToWorldAndParallax[0].xyz = 0; 560 | o.tangentToWorldAndParallax[1].xyz = 0; 561 | o.tangentToWorldAndParallax[2].xyz = normalWorld; 562 | #endif 563 | 564 | o.ambientOrLightmapUV = 0; 565 | #ifndef LIGHTMAP_OFF 566 | o.ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; 567 | #elif UNITY_SHOULD_SAMPLE_SH 568 | o.ambientOrLightmapUV.rgb = ShadeSHPerVertex (normalWorld, o.ambientOrLightmapUV.rgb); 569 | #endif 570 | #ifdef DYNAMICLIGHTMAP_ON 571 | o.ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; 572 | #endif 573 | 574 | #ifdef _PARALLAXMAP 575 | TANGENT_SPACE_ROTATION; 576 | half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex)); 577 | o.tangentToWorldAndParallax[0].w = viewDirForParallax.x; 578 | o.tangentToWorldAndParallax[1].w = viewDirForParallax.y; 579 | o.tangentToWorldAndParallax[2].w = viewDirForParallax.z; 580 | #endif 581 | 582 | #if UNITY_OPTIMIZE_TEXCUBELOD 583 | o.reflUVW = reflect(o.eyeVec, normalWorld); 584 | #endif 585 | 586 | return o; 587 | } 588 | 589 | void fragDeferred ( 590 | VertexOutputDeferred i, 591 | out half4 outDiffuse : SV_Target0, // RT0: diffuse color (rgb), occlusion (a) 592 | out half4 outSpecSmoothness : SV_Target1, // RT1: spec color (rgb), smoothness (a) 593 | out half4 outNormal : SV_Target2, // RT2: normal (rgb), --unused, very low precision-- (a) 594 | out half4 outEmission : SV_Target3 // RT3: emission (rgb), --unused-- (a) 595 | ) 596 | { 597 | #if (SHADER_TARGET < 30) 598 | outDiffuse = 1; 599 | outSpecSmoothness = 1; 600 | outNormal = 0; 601 | outEmission = 0; 602 | return; 603 | #endif 604 | 605 | FRAGMENT_SETUP(s) 606 | #if UNITY_OPTIMIZE_TEXCUBELOD 607 | s.reflUVW = i.reflUVW; 608 | #endif 609 | 610 | // no analytic lights in this pass 611 | UnityLight dummyLight = DummyLight (s.normalWorld); 612 | half atten = 1; 613 | 614 | // only GI 615 | half occlusion = Occlusion(i.tex.xy); 616 | #if UNITY_ENABLE_REFLECTION_BUFFERS 617 | bool sampleReflectionsInDeferred = false; 618 | #else 619 | bool sampleReflectionsInDeferred = true; 620 | #endif 621 | 622 | UnityGI gi = FragmentGI (s, occlusion, i.ambientOrLightmapUV, atten, dummyLight, sampleReflectionsInDeferred); 623 | 624 | half3 color = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect).rgb; 625 | color += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi); 626 | 627 | #ifdef _EMISSION 628 | color += Emission (i.tex.xy); 629 | #endif 630 | 631 | #ifndef UNITY_HDR_ON 632 | color.rgb = exp2(-color.rgb); 633 | #endif 634 | 635 | outDiffuse = half4(s.diffColor, occlusion); 636 | outSpecSmoothness = half4(s.specColor, s.oneMinusRoughness); 637 | outNormal = half4(s.normalWorld*0.5+0.5,1); 638 | outEmission = half4(color, 1); 639 | } 640 | 641 | 642 | // 643 | // Old FragmentGI signature. Kept only for backward compatibility and will be removed soon 644 | // 645 | 646 | inline UnityGI FragmentGI( 647 | float3 posWorld, 648 | half occlusion, half4 i_ambientOrLightmapUV, half atten, half oneMinusRoughness, half3 normalWorld, half3 eyeVec, 649 | UnityLight light, 650 | bool reflections) 651 | { 652 | // we init only fields actually used 653 | FragmentCommonData s = (FragmentCommonData)0; 654 | s.oneMinusRoughness = oneMinusRoughness; 655 | s.normalWorld = normalWorld; 656 | s.eyeVec = eyeVec; 657 | s.posWorld = posWorld; 658 | #if UNITY_OPTIMIZE_TEXCUBELOD 659 | s.reflUVW = reflect(eyeVec, normalWorld); 660 | #endif 661 | return FragmentGI(s, occlusion, i_ambientOrLightmapUV, atten, light, reflections); 662 | } 663 | inline UnityGI FragmentGI ( 664 | float3 posWorld, 665 | half occlusion, half4 i_ambientOrLightmapUV, half atten, half oneMinusRoughness, half3 normalWorld, half3 eyeVec, 666 | UnityLight light) 667 | { 668 | return FragmentGI (posWorld, occlusion, i_ambientOrLightmapUV, atten, oneMinusRoughness, normalWorld, eyeVec, light, true); 669 | } 670 | 671 | #endif // UNITY_STANDARD_CORE_INCLUDED 672 | -------------------------------------------------------------------------------- /StandardShader/CustomUnityStandardInput.cginc: -------------------------------------------------------------------------------- 1 | #ifndef UNITY_STANDARD_INPUT_INCLUDED 2 | #define UNITY_STANDARD_INPUT_INCLUDED 3 | 4 | #include "UnityCG.cginc" 5 | #include "UnityShaderVariables.cginc" 6 | #include "UnityStandardConfig.cginc" 7 | #include "UnityPBSLighting.cginc" // TBD: remove 8 | #include "UnityStandardUtils.cginc" 9 | 10 | //--------------------------------------- 11 | // Directional lightmaps & Parallax require tangent space too 12 | #if (_NORMALMAP || !DIRLIGHTMAP_OFF || _PARALLAXMAP) 13 | #define _TANGENT_TO_WORLD 1 14 | #endif 15 | 16 | #if (_DETAIL_MULX2 || _DETAIL_MUL || _DETAIL_ADD || _DETAIL_LERP) 17 | #define _DETAIL 1 18 | #endif 19 | 20 | //--------------------------------------- 21 | half4 _Color; 22 | half _Cutoff; 23 | 24 | sampler2D _MainTex; 25 | float4 _MainTex_ST; 26 | 27 | sampler2D _DetailAlbedoMap; 28 | float4 _DetailAlbedoMap_ST; 29 | 30 | sampler2D _BumpMap; 31 | half _BumpScale; 32 | 33 | sampler2D _DetailMask; 34 | sampler2D _DetailNormalMap; 35 | half _DetailNormalMapScale; 36 | 37 | sampler2D _SpecGlossMap; 38 | sampler2D _MetallicGlossMap; 39 | half _Metallic; 40 | half _Glossiness; 41 | 42 | sampler2D _OcclusionMap; 43 | half _OcclusionStrength; 44 | 45 | sampler2D _ParallaxMap; 46 | half _Parallax; 47 | half _UVSec; 48 | 49 | half4 _EmissionColor; 50 | sampler2D _EmissionMap; 51 | 52 | //------------------------------------------------------------------------------------- 53 | // Input functions 54 | 55 | struct VertexInput 56 | { 57 | float4 vertex : POSITION; 58 | half3 normal : NORMAL; 59 | float2 uv0 : TEXCOORD0; 60 | float2 uv1 : TEXCOORD1; 61 | #if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META) 62 | float2 uv2 : TEXCOORD2; 63 | #endif 64 | #ifdef _TANGENT_TO_WORLD 65 | half4 tangent : TANGENT; 66 | #endif 67 | }; 68 | 69 | float4 TexCoords(VertexInput v) 70 | { 71 | float4 texcoord; 72 | texcoord.xy = TRANSFORM_TEX(v.uv0, _MainTex); // Always source from uv0 73 | texcoord.zw = TRANSFORM_TEX(((_UVSec == 0) ? v.uv0 : v.uv1), _DetailAlbedoMap); 74 | return texcoord; 75 | } 76 | 77 | half DetailMask(float2 uv) 78 | { 79 | return tex2D (_DetailMask, uv).a; 80 | } 81 | 82 | half3 Albedo(float4 texcoords) 83 | { 84 | half3 albedo = _Color.rgb * tex2D (_MainTex, texcoords.xy).rgb; 85 | #if _DETAIL 86 | #if (SHADER_TARGET < 30) 87 | // SM20: instruction count limitation 88 | // SM20: no detail mask 89 | half mask = 1; 90 | #else 91 | half mask = DetailMask(texcoords.xy); 92 | #endif 93 | half3 detailAlbedo = tex2D (_DetailAlbedoMap, texcoords.zw).rgb; 94 | #if _DETAIL_MULX2 95 | albedo *= LerpWhiteTo (detailAlbedo * unity_ColorSpaceDouble.rgb, mask); 96 | #elif _DETAIL_MUL 97 | albedo *= LerpWhiteTo (detailAlbedo, mask); 98 | #elif _DETAIL_ADD 99 | albedo += detailAlbedo * mask; 100 | #elif _DETAIL_LERP 101 | albedo = lerp (albedo, detailAlbedo, mask); 102 | #endif 103 | #endif 104 | return albedo; 105 | } 106 | 107 | half Alpha(float2 uv) 108 | { 109 | return tex2D(_MainTex, uv).a * _Color.a; 110 | } 111 | 112 | half Occlusion(float2 uv) 113 | { 114 | #if (SHADER_TARGET < 30) 115 | // SM20: instruction count limitation 116 | // SM20: simpler occlusion 117 | return tex2D(_OcclusionMap, uv).g; 118 | #else 119 | half occ = tex2D(_OcclusionMap, uv).g; 120 | return LerpOneTo (occ, _OcclusionStrength); 121 | #endif 122 | } 123 | 124 | half4 SpecularGloss(float2 uv) 125 | { 126 | half4 sg; 127 | #ifdef _SPECGLOSSMAP 128 | sg = tex2D(_SpecGlossMap, uv.xy); 129 | #else 130 | sg = half4(_SpecColor.rgb, _Glossiness); 131 | #endif 132 | return sg; 133 | } 134 | 135 | half2 MetallicGloss(float2 uv) 136 | { 137 | half2 mg; 138 | #ifdef _METALLICGLOSSMAP 139 | mg = tex2D(_MetallicGlossMap, uv.xy).ra; 140 | #else 141 | mg = half2(_Metallic, _Glossiness); 142 | #endif 143 | return mg; 144 | } 145 | 146 | half3 Emission(float2 uv) 147 | { 148 | #ifndef _EMISSION 149 | return 0; 150 | #else 151 | return tex2D(_EmissionMap, uv).rgb * _EmissionColor.rgb; 152 | #endif 153 | } 154 | 155 | #ifdef _NORMALMAP 156 | half3 NormalInTangentSpace(float4 texcoords) 157 | { 158 | half3 normalTangent = UnpackScaleNormal(tex2D (_BumpMap, texcoords.xy), _BumpScale); 159 | // SM20: instruction count limitation 160 | // SM20: no detail normalmaps 161 | #if _DETAIL && !defined(SHADER_API_MOBILE) && (SHADER_TARGET >= 30) 162 | half mask = DetailMask(texcoords.xy); 163 | half3 detailNormalTangent = UnpackScaleNormal(tex2D (_DetailNormalMap, texcoords.zw), _DetailNormalMapScale); 164 | #if _DETAIL_LERP 165 | normalTangent = lerp( 166 | normalTangent, 167 | detailNormalTangent, 168 | mask); 169 | #else 170 | normalTangent = lerp( 171 | normalTangent, 172 | BlendNormals(normalTangent, detailNormalTangent), 173 | mask); 174 | #endif 175 | #endif 176 | return normalTangent; 177 | } 178 | #endif 179 | 180 | float4 Parallax (float4 texcoords, half3 viewDir) 181 | { 182 | #if !defined(_PARALLAXMAP) || (SHADER_TARGET < 30) 183 | // SM20: instruction count limitation 184 | // SM20: no parallax 185 | return texcoords; 186 | #else 187 | half h = tex2D (_ParallaxMap, texcoords.xy).g; 188 | float2 offset = ParallaxOffset1Step (h, _Parallax, viewDir); 189 | return float4(texcoords.xy + offset, texcoords.zw + offset); 190 | #endif 191 | } 192 | 193 | #endif // UNITY_STANDARD_INPUT_INCLUDED 194 | -------------------------------------------------------------------------------- /StandardShader/CustomUnityStandardMeta.cginc: -------------------------------------------------------------------------------- 1 | #ifndef UNITY_STANDARD_META_INCLUDED 2 | #define UNITY_STANDARD_META_INCLUDED 3 | 4 | // Functionality for Standard shader "meta" pass 5 | // (extracts albedo/emission for lightmapper etc.) 6 | 7 | // define meta pass before including other files; they have conditions 8 | // on that in some places 9 | #define UNITY_PASS_META 1 10 | 11 | #include "UnityCG.cginc" 12 | #include "UnityStandardInput.cginc" 13 | #include "UnityMetaPass.cginc" 14 | #include "UnityStandardCore.cginc" 15 | 16 | struct v2f_meta 17 | { 18 | float4 uv : TEXCOORD0; 19 | float4 pos : SV_POSITION; 20 | }; 21 | 22 | v2f_meta vert_meta (VertexInput v) 23 | { 24 | v2f_meta o; 25 | o.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); 26 | o.uv = TexCoords(v); 27 | return o; 28 | } 29 | 30 | // Albedo for lightmapping should basically be diffuse color. 31 | // But rough metals (black diffuse) still scatter quite a lot of light around, so 32 | // we want to take some of that into account too. 33 | half3 UnityLightmappingAlbedo (half3 diffuse, half3 specular, half oneMinusRoughness) 34 | { 35 | half roughness = 1 - oneMinusRoughness; 36 | half3 res = diffuse; 37 | res += specular * roughness * roughness * 0.5; 38 | return res; 39 | } 40 | 41 | float4 frag_meta (v2f_meta i) : SV_Target 42 | { 43 | // we're interested in diffuse & specular colors, 44 | // and surface roughness to produce final albedo. 45 | FragmentCommonData data = UNITY_SETUP_BRDF_INPUT (i.uv); 46 | 47 | UnityMetaInput o; 48 | UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o); 49 | 50 | o.Albedo = UnityLightmappingAlbedo (data.diffColor, data.specColor, data.oneMinusRoughness); 51 | o.Emission = Emission(i.uv.xy); 52 | 53 | return UnityMetaFragment(o); 54 | } 55 | 56 | #endif // UNITY_STANDARD_META_INCLUDED 57 | -------------------------------------------------------------------------------- /TerrainShaders/CustomStandard-AddPass.shader: -------------------------------------------------------------------------------- 1 | Shader "Hidden/TerrainEngine/Splatmap/Standard-AddPass" { 2 | Properties { 3 | // set by terrain engine 4 | [HideInInspector] _Control ("Control (RGBA)", 2D) = "red" {} 5 | [HideInInspector] _Splat3 ("Layer 3 (A)", 2D) = "white" {} 6 | [HideInInspector] _Splat2 ("Layer 2 (B)", 2D) = "white" {} 7 | [HideInInspector] _Splat1 ("Layer 1 (G)", 2D) = "white" {} 8 | [HideInInspector] _Splat0 ("Layer 0 (R)", 2D) = "white" {} 9 | [HideInInspector] _Normal3 ("Normal 3 (A)", 2D) = "bump" {} 10 | [HideInInspector] _Normal2 ("Normal 2 (B)", 2D) = "bump" {} 11 | [HideInInspector] _Normal1 ("Normal 1 (G)", 2D) = "bump" {} 12 | [HideInInspector] _Normal0 ("Normal 0 (R)", 2D) = "bump" {} 13 | [HideInInspector] [Gamma] _Metallic0 ("Metallic 0", Range(0.0, 1.0)) = 0.0 14 | [HideInInspector] [Gamma] _Metallic1 ("Metallic 1", Range(0.0, 1.0)) = 0.0 15 | [HideInInspector] [Gamma] _Metallic2 ("Metallic 2", Range(0.0, 1.0)) = 0.0 16 | [HideInInspector] [Gamma] _Metallic3 ("Metallic 3", Range(0.0, 1.0)) = 0.0 17 | [HideInInspector] _Smoothness0 ("Smoothness 0", Range(0.0, 1.0)) = 1.0 18 | [HideInInspector] _Smoothness1 ("Smoothness 1", Range(0.0, 1.0)) = 1.0 19 | [HideInInspector] _Smoothness2 ("Smoothness 2", Range(0.0, 1.0)) = 1.0 20 | [HideInInspector] _Smoothness3 ("Smoothness 3", Range(0.0, 1.0)) = 1.0 21 | } 22 | 23 | SubShader { 24 | Tags { 25 | "Queue" = "Geometry-99" 26 | "IgnoreProjector"="True" 27 | "RenderType" = "Opaque" 28 | } 29 | 30 | CGPROGRAM 31 | #pragma surface surf Standard decal:add vertex:SplatmapVert finalcolor:SplatmapFinalColor finalgbuffer:SplatmapFinalGBuffer fullforwardshadows 32 | #pragma multi_compile_fog 33 | #pragma target 3.0 34 | // needs more than 8 texcoords 35 | #pragma exclude_renderers gles 36 | #include "UnityPBSLighting.cginc" 37 | 38 | #pragma multi_compile __ _TERRAIN_NORMAL_MAP 39 | 40 | #define TERRAIN_SPLAT_ADDPASS 41 | #define TERRAIN_STANDARD_SHADER 42 | #define TERRAIN_SURFACE_OUTPUT SurfaceOutputStandard 43 | #include "TerrainSplatmapCommon.cginc" 44 | 45 | half _Metallic0; 46 | half _Metallic1; 47 | half _Metallic2; 48 | half _Metallic3; 49 | 50 | half _Smoothness0; 51 | half _Smoothness1; 52 | half _Smoothness2; 53 | half _Smoothness3; 54 | 55 | void surf (Input IN, inout SurfaceOutputStandard o) { 56 | half4 splat_control; 57 | half weight; 58 | fixed4 mixedDiffuse; 59 | half4 defaultSmoothness = half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3); 60 | SplatmapMix(IN, defaultSmoothness, splat_control, weight, mixedDiffuse, o.Normal); 61 | o.Albedo = mixedDiffuse.rgb; 62 | o.Alpha = weight; 63 | o.Smoothness = mixedDiffuse.a; 64 | o.Metallic = dot(splat_control, half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3)); 65 | } 66 | ENDCG 67 | } 68 | 69 | Fallback "Hidden/TerrainEngine/Splatmap/Diffuse-AddPass" 70 | } 71 | -------------------------------------------------------------------------------- /TerrainShaders/CustomStandard-FirstPass.shader: -------------------------------------------------------------------------------- 1 | Shader "Nature/Terrain/Standard" { 2 | Properties { 3 | // set by terrain engine 4 | [HideInInspector] _Control ("Control (RGBA)", 2D) = "red" {} 5 | [HideInInspector] _Splat3 ("Layer 3 (A)", 2D) = "white" {} 6 | [HideInInspector] _Splat2 ("Layer 2 (B)", 2D) = "white" {} 7 | [HideInInspector] _Splat1 ("Layer 1 (G)", 2D) = "white" {} 8 | [HideInInspector] _Splat0 ("Layer 0 (R)", 2D) = "white" {} 9 | [HideInInspector] _Normal3 ("Normal 3 (A)", 2D) = "bump" {} 10 | [HideInInspector] _Normal2 ("Normal 2 (B)", 2D) = "bump" {} 11 | [HideInInspector] _Normal1 ("Normal 1 (G)", 2D) = "bump" {} 12 | [HideInInspector] _Normal0 ("Normal 0 (R)", 2D) = "bump" {} 13 | [HideInInspector] [Gamma] _Metallic0 ("Metallic 0", Range(0.0, 1.0)) = 0.0 14 | [HideInInspector] [Gamma] _Metallic1 ("Metallic 1", Range(0.0, 1.0)) = 0.0 15 | [HideInInspector] [Gamma] _Metallic2 ("Metallic 2", Range(0.0, 1.0)) = 0.0 16 | [HideInInspector] [Gamma] _Metallic3 ("Metallic 3", Range(0.0, 1.0)) = 0.0 17 | [HideInInspector] _Smoothness0 ("Smoothness 0", Range(0.0, 1.0)) = 1.0 18 | [HideInInspector] _Smoothness1 ("Smoothness 1", Range(0.0, 1.0)) = 1.0 19 | [HideInInspector] _Smoothness2 ("Smoothness 2", Range(0.0, 1.0)) = 1.0 20 | [HideInInspector] _Smoothness3 ("Smoothness 3", Range(0.0, 1.0)) = 1.0 21 | 22 | // used in fallback on old cards & base map 23 | [HideInInspector] _MainTex ("BaseMap (RGB)", 2D) = "white" {} 24 | [HideInInspector] _Color ("Main Color", Color) = (1,1,1,1) 25 | } 26 | 27 | SubShader { 28 | Tags { 29 | "Queue" = "Geometry-100" 30 | "RenderType" = "Opaque" 31 | } 32 | 33 | CGPROGRAM 34 | #pragma surface surf Standard vertex:SplatmapVert finalcolor:SplatmapFinalColor finalgbuffer:SplatmapFinalGBuffer fullforwardshadows 35 | #pragma multi_compile_fog 36 | #pragma target 3.0 37 | // needs more than 8 texcoords 38 | #pragma exclude_renderers gles 39 | #include "UnityPBSLighting.cginc" 40 | 41 | #pragma multi_compile __ _TERRAIN_NORMAL_MAP 42 | 43 | #define TERRAIN_STANDARD_SHADER 44 | #define TERRAIN_SURFACE_OUTPUT SurfaceOutputStandard 45 | #include "TerrainSplatmapCommon.cginc" 46 | 47 | half _Metallic0; 48 | half _Metallic1; 49 | half _Metallic2; 50 | half _Metallic3; 51 | 52 | half _Smoothness0; 53 | half _Smoothness1; 54 | half _Smoothness2; 55 | half _Smoothness3; 56 | 57 | void surf (Input IN, inout SurfaceOutputStandard o) { 58 | half4 splat_control; 59 | half weight; 60 | fixed4 mixedDiffuse; 61 | half4 defaultSmoothness = half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3); 62 | SplatmapMix(IN, defaultSmoothness, splat_control, weight, mixedDiffuse, o.Normal); 63 | o.Albedo = mixedDiffuse.rgb; 64 | o.Alpha = weight; 65 | o.Smoothness = mixedDiffuse.a; 66 | o.Metallic = dot(splat_control, half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3)); 67 | } 68 | ENDCG 69 | } 70 | 71 | Dependency "AddPassShader" = "Hidden/TerrainEngine/Splatmap/Standard-AddPass" 72 | Dependency "BaseMapShader" = "Hidden/TerrainEngine/Splatmap/Standard-Base" 73 | 74 | Fallback "Nature/Terrain/Diffuse" 75 | } 76 | -------------------------------------------------------------------------------- /TerrainShaders/CustomTerrainSplatmapCommon.cginc: -------------------------------------------------------------------------------- 1 | #ifndef TERRAIN_SPLATMAP_COMMON_CGINC_INCLUDED 2 | #define TERRAIN_SPLATMAP_COMMON_CGINC_INCLUDED 3 | 4 | struct Input 5 | { 6 | float2 uv_Splat0 : TEXCOORD0; 7 | float2 uv_Splat1 : TEXCOORD1; 8 | float2 uv_Splat2 : TEXCOORD2; 9 | float2 uv_Splat3 : TEXCOORD3; 10 | float2 tc_Control : TEXCOORD4; // Not prefixing '_Contorl' with 'uv' allows a tighter packing of interpolators, which is necessary to support directional lightmap. 11 | UNITY_FOG_COORDS(5) 12 | }; 13 | 14 | sampler2D _Control; 15 | float4 _Control_ST; 16 | sampler2D _Splat0,_Splat1,_Splat2,_Splat3; 17 | 18 | #ifdef _TERRAIN_NORMAL_MAP 19 | sampler2D _Normal0, _Normal1, _Normal2, _Normal3; 20 | #endif 21 | 22 | void SplatmapVert(inout appdata_full v, out Input data) 23 | { 24 | UNITY_INITIALIZE_OUTPUT(Input, data); 25 | data.tc_Control = TRANSFORM_TEX(v.texcoord, _Control); // Need to manually transform uv here, as we choose not to use 'uv' prefix for this texcoord. 26 | float4 pos = mul (UNITY_MATRIX_MVP, v.vertex); 27 | UNITY_TRANSFER_FOG(data, pos); 28 | 29 | #ifdef _TERRAIN_NORMAL_MAP 30 | v.tangent.xyz = cross(v.normal, float3(0,0,1)); 31 | v.tangent.w = -1; 32 | #endif 33 | } 34 | 35 | #ifdef TERRAIN_STANDARD_SHADER 36 | void SplatmapMix(Input IN, half4 defaultAlpha, out half4 splat_control, out half weight, out fixed4 mixedDiffuse, inout fixed3 mixedNormal) 37 | #else 38 | void SplatmapMix(Input IN, out half4 splat_control, out half weight, out fixed4 mixedDiffuse, inout fixed3 mixedNormal) 39 | #endif 40 | { 41 | splat_control = tex2D(_Control, IN.tc_Control); 42 | weight = dot(splat_control, half4(1,1,1,1)); 43 | 44 | #if !defined(SHADER_API_MOBILE) && defined(TERRAIN_SPLAT_ADDPASS) 45 | clip(weight - 0.0039 /*1/255*/); 46 | #endif 47 | 48 | // Normalize weights before lighting and restore weights in final modifier functions so that the overal 49 | // lighting result can be correctly weighted. 50 | splat_control /= (weight + 1e-3f); 51 | 52 | mixedDiffuse = 0.0f; 53 | #ifdef TERRAIN_STANDARD_SHADER 54 | mixedDiffuse += splat_control.r * tex2D(_Splat0, IN.uv_Splat0) * half4(1.0, 1.0, 1.0, defaultAlpha.r); 55 | mixedDiffuse += splat_control.g * tex2D(_Splat1, IN.uv_Splat1) * half4(1.0, 1.0, 1.0, defaultAlpha.g); 56 | mixedDiffuse += splat_control.b * tex2D(_Splat2, IN.uv_Splat2) * half4(1.0, 1.0, 1.0, defaultAlpha.b); 57 | mixedDiffuse += splat_control.a * tex2D(_Splat3, IN.uv_Splat3) * half4(1.0, 1.0, 1.0, defaultAlpha.a); 58 | #else 59 | mixedDiffuse += splat_control.r * tex2D(_Splat0, IN.uv_Splat0); 60 | mixedDiffuse += splat_control.g * tex2D(_Splat1, IN.uv_Splat1); 61 | mixedDiffuse += splat_control.b * tex2D(_Splat2, IN.uv_Splat2); 62 | mixedDiffuse += splat_control.a * tex2D(_Splat3, IN.uv_Splat3); 63 | #endif 64 | 65 | #ifdef _TERRAIN_NORMAL_MAP 66 | fixed4 nrm = 0.0f; 67 | nrm += splat_control.r * tex2D(_Normal0, IN.uv_Splat0); 68 | nrm += splat_control.g * tex2D(_Normal1, IN.uv_Splat1); 69 | nrm += splat_control.b * tex2D(_Normal2, IN.uv_Splat2); 70 | nrm += splat_control.a * tex2D(_Normal3, IN.uv_Splat3); 71 | mixedNormal = UnpackNormal(nrm); 72 | #endif 73 | } 74 | 75 | #ifndef TERRAIN_SURFACE_OUTPUT 76 | #define TERRAIN_SURFACE_OUTPUT SurfaceOutput 77 | #endif 78 | 79 | void SplatmapFinalColor(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 color) 80 | { 81 | color *= o.Alpha; 82 | #ifdef TERRAIN_SPLAT_ADDPASS 83 | UNITY_APPLY_FOG_COLOR(IN.fogCoord, color, fixed4(0,0,0,0)); 84 | #else 85 | UNITY_APPLY_FOG(IN.fogCoord, color); 86 | #endif 87 | } 88 | 89 | void SplatmapFinalPrepass(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 normalSpec) 90 | { 91 | normalSpec *= o.Alpha; 92 | } 93 | 94 | void SplatmapFinalGBuffer(Input IN, TERRAIN_SURFACE_OUTPUT o, inout half4 diffuse, inout half4 specSmoothness, inout half4 normal, inout half4 emission) 95 | { 96 | diffuse.rgb *= o.Alpha; 97 | specSmoothness *= o.Alpha; 98 | normal.rgb *= o.Alpha; 99 | emission *= o.Alpha; 100 | } 101 | 102 | #endif // TERRAIN_SPLATMAP_COMMON_CGINC_INCLUDED 103 | --------------------------------------------------------------------------------