123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- #if UNITY_EDITOR
- using UnityEngine;
- using UnityEngine.Rendering;
- using UnityEditor;
- using System.Collections.Generic;
- using System.IO;
- namespace VLB
- {
- public class ShaderGenerator : ScriptableObject
- {
- [SerializeField] TextAsset m_Base = null;
- TextAsset textAssetBase { get { return m_Base; } }
- [SerializeField] TextAsset m_Pass = null;
- TextAsset textAssetPass { get { return m_Pass; } }
- [SerializeField] TextAsset m_IncludesBuiltin = null;
- TextAsset textAssetIncludesBuiltin { get { return m_IncludesBuiltin; } }
- [SerializeField] TextAsset m_IncludesURP = null;
- TextAsset textAssetIncludesURP { get { return m_IncludesURP; } }
- [SerializeField] TextAsset m_IncludesHDRP = null;
- TextAsset textAssetIncludesHDRP { get { return m_IncludesHDRP; } }
- const string kShaderAssetName = "VLBGeneratedShader";
- static string GetOutputPath()
- {
- var path = Path.GetDirectoryName(AssetDatabase.GetAssetPath(Instance));
- if (string.IsNullOrEmpty(path)) path = "Plugins/VolumetricLightBeam/Shaders/";
- path = path.Replace("\\", "/");
- const string kAssetsFolder = "Assets/";
- if (path.IndexOf(kAssetsFolder) == 0) path = path.Remove(0, kAssetsFolder.Length);
- return path;
- }
- public class EnabledFeatures
- {
- public bool dithering;
- public bool depthBlend;
- public FeatureEnabledColorGradient colorGradient;
- public bool noise3D;
- public bool dynamicOcclusion;
- public bool meshSkewing;
- public bool shaderAccuracyHigh;
- }
- public static Shader Generate(RenderPipeline rp, RenderingMode rm, EnabledFeatures enabledFeatures)
- {
- // The instance might not be accessible yet, when called from Config.OnEnable for instance if the Config is enabled before the ShaderGenerator.
- // In this case we don't generate the shader right away, we store the parameters instead and we'll generate the shader in ShaderGenerator.OnEnable.
- if (Instance == null)
- {
- ms_GenerationParamOnEnable = new GenerationParam { renderPipeline = rp, renderingMode = rm, enabledFeatures = enabledFeatures };
- return null;
- }
- return new GenShader(rp, rm, enabledFeatures).Generate();
- }
- static string LoadText(TextAsset textAsset)
- {
- Debug.Assert(textAsset != null, "Fail to load a TextAsset, please try to reinstall the VolumetricLightBeam plugin");
- return textAsset.text;
- }
- TextAsset GetTextAssetIncludes(SRPHelper.RenderPipeline rp)
- {
- switch (rp)
- {
- case SRPHelper.RenderPipeline.BuiltIn:
- return textAssetIncludesBuiltin;
- case SRPHelper.RenderPipeline.LWRP:
- case SRPHelper.RenderPipeline.URP:
- return textAssetIncludesURP;
- case SRPHelper.RenderPipeline.HDRP:
- return textAssetIncludesHDRP;
- }
- return null;
- }
- static bool IsFogSupported(SRPHelper.RenderPipeline rp) { return rp != SRPHelper.RenderPipeline.HDRP; }
- enum ShaderLangage { CG, HLSL }
- static ShaderLangage GetShaderLangage(SRPHelper.RenderPipeline rp)
- {
- switch (rp)
- {
- case SRPHelper.RenderPipeline.BuiltIn:
- case SRPHelper.RenderPipeline.LWRP:
- return ShaderLangage.CG;
- case SRPHelper.RenderPipeline.URP:
- case SRPHelper.RenderPipeline.HDRP:
- return ShaderLangage.HLSL;
- }
- return ShaderLangage.CG;
- }
- static string GetShaderLangagePre (ShaderLangage lang) { return lang == ShaderLangage.CG ? "CGPROGRAM" : "HLSLPROGRAM"; }
- static string GetShaderLangagePost(ShaderLangage lang) { return lang == ShaderLangage.CG ? "ENDCG" : "ENDHLSL"; }
- public class GenPass
- {
- CullMode m_CullMode;
- public GenPass(CullMode cullMode)
- {
- m_CullMode = cullMode;
- }
- static void AppendMultiCompile(ref string str, bool genDefaultVariant, params string[] options)
- {
- #if UNITY_2019_1_OR_NEWER
- const string kPrefix = " #pragma multi_compile_local";
- #else
- const string kPrefix = " #pragma multi_compile";
- #endif
- str += kPrefix;
- if(genDefaultVariant) str += " __";
- foreach (string opt in options) str += " " + opt;
- str += System.Environment.NewLine;
- }
- public string Generate(SRPHelper.RenderPipeline rp, RenderingMode rm, EnabledFeatures enabledFeatures, int passID, int passCount)
- {
- var code = LoadText(Instance.textAssetPass);
- code = code.Replace("{VLB_GEN_CULLING}", m_CullMode.ToString());
- code = code.Replace("{VLB_GEN_PRAGMA_INSTANCING}", rm == RenderingMode.GPUInstancing ? "#pragma multi_compile_instancing" : "");
- code = code.Replace("{VLB_GEN_PRAGMA_FOG}", IsFogSupported(rp) ? "#pragma multi_compile_fog" : "");
- string multiCompileVariants = "";
- AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.AlphaAsBlack);
- if (enabledFeatures.noise3D) AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.Noise3D);
- if (enabledFeatures.depthBlend) AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.DepthBlend);
- switch(enabledFeatures.colorGradient)
- {
- case FeatureEnabledColorGradient.HighOnly: AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.ColorGradientMatrixHigh); break;
- case FeatureEnabledColorGradient.HighAndLow: AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.ColorGradientMatrixHigh, ShaderKeywords.ColorGradientMatrixLow); break;
- }
- if (enabledFeatures.dynamicOcclusion) AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.OcclusionClippingPlane, ShaderKeywords.OcclusionDepthTexture);
- if (enabledFeatures.meshSkewing) AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.MeshSkewing);
- if (enabledFeatures.shaderAccuracyHigh) AppendMultiCompile(ref multiCompileVariants, true, ShaderKeywords.ShaderAccuracyHigh);
- code = code.Replace("{VLB_GEN_PRAGMA_MULTI_COMPILE_VARIANTS}", multiCompileVariants);
- var lang = GetShaderLangage(rp);
- code = code.Replace("{VLB_GEN_PROGRAM_PRE}", GetShaderLangagePre(lang));
- code = code.Replace("{VLB_GEN_PROGRAM_POST}", GetShaderLangagePost(lang));
- var passPre = "";
- if (passCount > 1)
- {
- code = code.Replace("{VLB_GEN_INPUT_VS}", string.Format("{0}", passID));
- code = code.Replace("{VLB_GEN_INPUT_FS}", string.Format("{0}", passID));
- }
- else
- {
- code = code.Replace("{VLB_GEN_INPUT_VS}", string.Format("{0}", "v.texcoord.y"));
- code = code.Replace("{VLB_GEN_INPUT_FS}", string.Format("{0}", "i.cameraPosObjectSpace_outsideBeam.w"));
- passPre += " #define VLB_PASS_OUTSIDEBEAM_FROM_VS_TO_FS 1" + System.Environment.NewLine;
- }
- if (rp != SRPHelper.RenderPipeline.BuiltIn)
- {
- passPre += " #define VLB_SRP_API 1" + System.Environment.NewLine;
- if (rm == RenderingMode.SRPBatcher)
- {
- passPre += " #define VLB_SRP_BATCHER 1" + System.Environment.NewLine;
- if (rp == SRPHelper.RenderPipeline.URP)
- {
- // force enable constant buffers to fix SRP Batcher support on Android
- passPre += " #pragma enable_cbuffer" + System.Environment.NewLine;
- }
- }
- }
- if (enabledFeatures.dithering)
- {
- passPre += " #define VLB_DITHERING 1" + System.Environment.NewLine;
- }
- passPre += LoadText(Instance.GetTextAssetIncludes(rp));
- code = code.Replace("{VLB_GEN_PRE}", passPre);
- return code;
- }
- }
- class GenShader
- {
- SRPHelper.RenderPipeline m_RenderPipeline;
- RenderingMode m_RenderingMode;
- EnabledFeatures m_EnabledFeatures;
- List<GenPass> m_Passes = new List<GenPass>();
- public GenShader(RenderPipeline rp, RenderingMode rm, EnabledFeatures enabledFeatures)
- {
- m_RenderingMode = rm;
- m_EnabledFeatures = enabledFeatures;
- switch (rp)
- {
- case RenderPipeline.BuiltIn:
- AddPass(CullMode.Front);
- if (rm == RenderingMode.MultiPass) AddPass(CullMode.Back);
- m_RenderPipeline = SRPHelper.RenderPipeline.BuiltIn;
- break;
- case RenderPipeline.URP:
- AddPass(CullMode.Front);
- m_RenderPipeline = SRPHelper.RenderPipeline.URP;
- break;
- case RenderPipeline.HDRP:
- AddPass(CullMode.Front);
- m_RenderPipeline = SRPHelper.RenderPipeline.HDRP;
- break;
- }
- }
- GenShader AddPass(CullMode cullMode)
- {
- m_Passes.Add(new GenPass(cullMode));
- return this;
- }
- public Shader Generate()
- {
- var shaderName = string.Format("Hidden/VLB_{0}_{1}", m_RenderPipeline, m_RenderingMode);
- var code = LoadText(Instance.textAssetBase);
- code = code.Replace("{VLB_GEN_SHADERNAME}", shaderName);
- var passes = "";
- for (int i = 0; i < m_Passes.Count; ++i)
- passes += m_Passes[i].Generate(m_RenderPipeline, m_RenderingMode, m_EnabledFeatures, i, m_Passes.Count);
- code = code.Replace("{VLB_GEN_PASSES}", passes);
- code = code.Replace("{VLB_GEN_SPECIFIC_INCLUDE}", GetRenderPipelineInclude(m_RenderPipeline));
- var outputFolderPath = ShaderGenerator.GetOutputPath();
- var outputFilePath = Path.Combine(outputFolderPath, kShaderAssetName);
- var outputFullPath = System.IO.Path.Combine(Application.dataPath, outputFilePath + ".shader");
- File.WriteAllText(outputFullPath, code);
- AssetDatabase.Refresh();
- var shader = Shader.Find(shaderName);
- Debug.Assert(shader != null, string.Format("Failed to generate shader '{0}' at '{1}'", shaderName, outputFullPath));
- return shader;
- }
- string GetRenderPipelineInclude(SRPHelper.RenderPipeline rp)
- {
- switch(rp)
- {
- case SRPHelper.RenderPipeline.BuiltIn: return "ShaderSpecificBuiltin.cginc";
- case SRPHelper.RenderPipeline.HDRP: return "ShaderSpecificHDRP.hlsl";
- case SRPHelper.RenderPipeline.LWRP:
- case SRPHelper.RenderPipeline.URP: return "ShaderSpecificURP.cginc";
- }
- return null;
- }
- }
- static ShaderGenerator FindInstance()
- {
- var assetGUIDs = AssetDatabase.FindAssets("ShaderGenerator");
- foreach (var guid in assetGUIDs)
- {
- var path = AssetDatabase.GUIDToAssetPath(guid);
- var asset = AssetDatabase.LoadAssetAtPath<ShaderGenerator>(path);
- if (asset)
- return asset;
- }
- return null;
- }
- // Store data to generate the shader on OnEnable
- class GenerationParam
- {
- public RenderPipeline renderPipeline;
- public RenderingMode renderingMode;
- public EnabledFeatures enabledFeatures;
- }
- static GenerationParam ms_GenerationParamOnEnable = null;
- void OnEnable()
- {
- if(ms_GenerationParamOnEnable != null && Instance != null)
- {
- Generate(ms_GenerationParamOnEnable.renderPipeline, ms_GenerationParamOnEnable.renderingMode, ms_GenerationParamOnEnable.enabledFeatures);
- ms_GenerationParamOnEnable = null;
- }
- }
- // Singleton management
- static ShaderGenerator m_Instance = null;
- static ShaderGenerator Instance
- {
- get
- {
- if (m_Instance == null)
- m_Instance = FindInstance();
- return m_Instance;
- }
- }
- }
- }
- #endif
|