Esempio n. 1
0
        public void Compile(Material m, string shaderName = null)
        {
            int hash = 0;

            MicroSplatKeywords keywords = MicroSplatUtilities.FindOrCreateKeywords(m);

            for (int i = 0; i < keywords.keywords.Count; ++i)
            {
                hash += 31 + keywords.keywords [i].GetHashCode();
            }
            var    path = AssetDatabase.GetAssetPath(m.shader);
            string nm   = m.shader.name;

            if (!string.IsNullOrEmpty(shaderName))
            {
                nm = shaderName;
            }
            string baseName = "Hidden/" + nm + "_Base" + hash.ToString();

            string terrainShader = Compile(keywords.keywords.ToArray(), nm, baseName);

            if (renderLoop != null)
            {
                keywords.EnableKeyword(renderLoop.GetRenderLoopKeyword());
            }

            GenerateAuxShaders(nm, path, keywords.keywords);

            MicroSplatUtilities.Checkout(path);
            System.IO.File.WriteAllText(path, terrainShader);

            if (!keywords.IsKeywordEnabled("_MICROMESH") && !keywords.IsKeywordEnabled("_MICROVERTEXMESH") && !keywords.IsKeywordEnabled("_MEGASPLAT") && !keywords.IsKeywordEnabled("_MICROTERRAINMESH"))
            {
                // generate fallback
                string[] oldKeywords = new string[keywords.keywords.Count];
                System.Array.Copy(keywords.keywords.ToArray(), oldKeywords, keywords.keywords.Count);
                keywords.DisableKeyword("_TESSDISTANCE");
                keywords.DisableKeyword("_PARALLAX");
                keywords.DisableKeyword("_DETAILNOISE");
                keywords.EnableKeyword("_MICROSPLATBASEMAP");

                string fallback = Compile(keywords.keywords.ToArray(), baseName);
                keywords.keywords = new List <string> (oldKeywords);
                string fallbackPath = path.Replace(".shader", "_Base.shader");
                MicroSplatUtilities.Checkout(fallbackPath);
                System.IO.File.WriteAllText(fallbackPath, fallback);
            }


            EditorUtility.SetDirty(m);
            AssetDatabase.Refresh();
#if __MICROSPLAT_MESH__
            MicroSplatMesh.ClearMaterialCache();
#endif
            MicroSplatObject.SyncAll();
        }
 void Undo_UndoRedoPerformed()
 {
     if (cachedMaterial != null && cachedKeywordCount > 0)
     {
         var keywordSO = MicroSplatUtilities.FindOrCreateKeywords(cachedMaterial);
         if (cachedKeywordCount != keywordSO.keywords.Count)
         {
             needsCompile = true;
         }
     }
 }
    public static Material NewShaderAndMaterial(string path, string name, string[] keywords = null)
    {
        string shaderPath     = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplat.shader");
        string shaderBasePath = shaderPath.Replace(".shader", "_Base.shader");
        string matPath        = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplat.mat");

        MicroSplatCompiler compiler = new MicroSplatCompiler();

        compiler.Init();

        if (keywords == null)
        {
            keywords = new string[0];
        }

        string baseName = "Hidden/MicroSplat/" + name + "_Base";

        string baseShader    = compiler.Compile(keywords, baseName);
        string regularShader = compiler.Compile(keywords, name, baseName);

        System.IO.File.WriteAllText(shaderPath, regularShader);
        System.IO.File.WriteAllText(shaderBasePath, baseShader);


        if (keywords.Contains("_MESHOVERLAYSPLATS"))
        {
            string meshOverlayShader = compiler.Compile(keywords, name, null, true);
            System.IO.File.WriteAllText(shaderPath.Replace(".shader", "_MeshOverlay.shader"), meshOverlayShader);
        }

        AssetDatabase.Refresh();
        Shader s = AssetDatabase.LoadAssetAtPath <Shader>(shaderPath);

        Material m = new Material(s);

        AssetDatabase.CreateAsset(m, matPath);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        var kwds = MicroSplatUtilities.FindOrCreateKeywords(m);

        kwds.keywords = new List <string>(keywords);
        EditorUtility.SetDirty(kwds);

        return(AssetDatabase.LoadAssetAtPath <Material>(matPath));
    }
Esempio n. 4
0
    public static Material NewShaderAndMaterial(string path, string name, string[] keywords = null)
    {
        string shaderPath     = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplat.shader");
        string shaderBasePath = shaderPath.Replace(".shader", "_Base.shader");
        string matPath        = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplat.mat");

        shaderPath     = shaderPath.Replace("//", "/");
        shaderBasePath = shaderBasePath.Replace("//", "/");
        matPath        = matPath.Replace("//", "/");

        MicroSplatCompiler compiler = new MicroSplatCompiler();

        compiler.Init();

        if (keywords == null)
        {
            keywords = new string[0];
        }

        var pipeline = MicroSplatUtilities.DetectPipeline();

        if (pipeline == MicroSplatUtilities.PipelineType.HDPipeline)
        {
            System.Array.Resize(ref keywords, keywords.Length + 1);
            keywords [keywords.Length - 1] = "_MSRENDERLOOP_UNITYHD";
        }
        else if (pipeline == MicroSplatUtilities.PipelineType.UniversalPipeline)
        {
            System.Array.Resize(ref keywords, keywords.Length + 1);
            keywords [keywords.Length - 1] = "_MSRENDERLOOP_UNITYLD";
        }


        string baseName = "Hidden/MicroSplat/" + name + "_Base";

        string baseShader    = compiler.Compile(keywords, baseName);
        string regularShader = compiler.Compile(keywords, name, baseName);

        System.IO.File.WriteAllText(shaderPath, regularShader);
        System.IO.File.WriteAllText(shaderBasePath, baseShader);


        if (keywords.Contains("_MESHOVERLAYSPLATS"))
        {
            string meshOverlayShader = compiler.Compile(keywords, name, null, true);
            System.IO.File.WriteAllText(shaderPath.Replace(".shader", "_MeshOverlay.shader"), meshOverlayShader);
        }

        AssetDatabase.Refresh();
        Shader s = AssetDatabase.LoadAssetAtPath <Shader> (shaderPath);

        if (s == null)
        {
            Debug.LogError("Shader not found at path " + shaderPath);
        }
        Material m = new Material(s);

        AssetDatabase.CreateAsset(m, matPath);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        var kwds = MicroSplatUtilities.FindOrCreateKeywords(m);

        kwds.keywords = new List <string> (keywords);
        EditorUtility.SetDirty(kwds);
        var propData = MicroSplatShaderGUI.FindOrCreatePropTex(m);

        if (propData != null)
        {
            EditorUtility.SetDirty(propData);
        }

        return(AssetDatabase.LoadAssetAtPath <Material> (matPath));
    }
Esempio n. 5
0
        public void Compile(Material m, string shaderName = null)
        {
            int hash = 0;

            MicroSplatKeywords keywords = MicroSplatUtilities.FindOrCreateKeywords(m);

            for (int i = 0; i < keywords.keywords.Count; ++i)
            {
                hash += 31 + keywords.keywords [i].GetHashCode();
            }
            var    path = AssetDatabase.GetAssetPath(m.shader);
            string nm   = m.shader.name;

            if (!string.IsNullOrEmpty(shaderName))
            {
                nm = shaderName;
            }
            string baseName = "Hidden/" + nm + "_Base" + hash.ToString();

            string terrainShader = Compile(keywords.keywords.ToArray(), nm, baseName);

            if (renderLoop != null)
            {
                keywords.EnableKeyword(renderLoop.GetRenderLoopKeyword());
            }
            string blendShader = null;

            // strip extra feature from terrain blending to make it cheaper
            if (keywords.IsKeywordEnabled("_TERRAINBLENDING"))
            {
                List <string> blendKeywords = new List <string> (keywords.keywords);
                if (keywords.IsKeywordEnabled("_TBDISABLE_DETAILNOISE") && blendKeywords.Contains("_DETAILNOISE"))
                {
                    blendKeywords.Remove("_DETAILNOISE");
                }
                if (keywords.IsKeywordEnabled("_TBDISABLE_DETAILNOISE") && blendKeywords.Contains("_ANTITILEARRAYDETAIL"))
                {
                    blendKeywords.Remove("_ANTITILEARRAYDETAIL");
                }
                if (keywords.IsKeywordEnabled("_TBDISABLE_DISTANCENOISE") && blendKeywords.Contains("_DISTANCENOISE"))
                {
                    blendKeywords.Remove("_DISTANCENOISE");
                }
                if (keywords.IsKeywordEnabled("_TBDISABLE_DISTANCENOISE") && blendKeywords.Contains("_ANTITILEARRAYDISTANCE"))
                {
                    blendKeywords.Remove("_ANTITILEARRAYDISTANCE");
                }
                if (keywords.IsKeywordEnabled("_TBDISABLE_DISTANCERESAMPLE") && blendKeywords.Contains("_DISTANCERESAMPLE"))
                {
                    blendKeywords.Remove("_DISTANCERESAMPLE");
                }

                blendShader = Compile(blendKeywords.ToArray(), nm, null, true);
            }



            string meshBlendShader = null;

            if (keywords.IsKeywordEnabled("_MESHOVERLAYSPLATS"))
            {
                List <string> blendKeywords = new List <string> (keywords.keywords);
                if (blendKeywords.Contains("_TESSDISTANCE"))
                {
                    blendKeywords.Remove("_TESSDISTANCE");
                }
                meshBlendShader = Compile(blendKeywords.ToArray(), nm, null, true);
            }

            MicroSplatUtilities.Checkout(path);
            System.IO.File.WriteAllText(path, terrainShader);

            if (!keywords.IsKeywordEnabled("_MICROMESH"))
            {
                // generate fallback
                string[] oldKeywords = new string[keywords.keywords.Count];
                System.Array.Copy(keywords.keywords.ToArray(), oldKeywords, keywords.keywords.Count);
                keywords.DisableKeyword("_TESSDISTANCE");
                keywords.DisableKeyword("_PARALLAX");
                keywords.DisableKeyword("_DETAILNOISE");
                keywords.EnableKeyword("_MICROSPLATBASEMAP");

                string fallback = Compile(keywords.keywords.ToArray(), baseName);
                keywords.keywords = new List <string> (oldKeywords);
                string fallbackPath = path.Replace(".shader", "_Base.shader");
                MicroSplatUtilities.Checkout(fallbackPath);
                System.IO.File.WriteAllText(fallbackPath, fallback);
            }


            string terrainBlendPath = path.Replace(".shader", "_TerrainObjectBlend.shader");
            string meshBlendPath    = path.Replace(".shader", "_MeshOverlay.shader");

            if (blendShader != null)
            {
                MicroSplatUtilities.Checkout(terrainBlendPath);
                System.IO.File.WriteAllText(terrainBlendPath, blendShader);
            }
            if (meshBlendShader != null)
            {
                MicroSplatUtilities.Checkout(meshBlendPath);
                System.IO.File.WriteAllText(meshBlendPath, meshBlendShader);
            }

            EditorUtility.SetDirty(m);
            AssetDatabase.Refresh();
            MicroSplatObject.SyncAll();
        }
Esempio n. 6
0
    public static Material NewShaderAndMaterial(string path, string name, string[] keywords = null)
    {
        // if no branch sampling is specified, go straight to aggressive. Usually defaults are not done this way, but this seems
        // to make the most sense..
        if (!keywords.Contains("_BRANCHSAMPLES"))
        {
            System.Array.Resize(ref keywords, keywords.Length + 2);
            keywords [keywords.Length - 2] = "_BRANCHSAMPLES";
            keywords [keywords.Length - 1] = "_BRANCHSAMPLESARG";
        }
        string shaderPath     = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplat.shader");
        string shaderBasePath = shaderPath.Replace(".shader", "_Base.shader");
        string matPath        = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplat.mat");

        shaderPath     = shaderPath.Replace("//", "/");
        shaderBasePath = shaderBasePath.Replace("//", "/");
        matPath        = matPath.Replace("//", "/");

        MicroSplatCompiler compiler = new MicroSplatCompiler();

        compiler.Init();

        if (keywords == null)
        {
            keywords = new string[0];
        }

        var pipeline = MicroSplatUtilities.DetectPipeline();

        if (pipeline == MicroSplatUtilities.PipelineType.HDPipeline)
        {
            System.Array.Resize(ref keywords, keywords.Length + 1);
            keywords [keywords.Length - 1] = "_MSRENDERLOOP_UNITYHD";
        }
        else if (pipeline == MicroSplatUtilities.PipelineType.UniversalPipeline)
        {
            System.Array.Resize(ref keywords, keywords.Length + 1);
            keywords [keywords.Length - 1] = "_MSRENDERLOOP_UNITYLD";
        }


        string baseName = "Hidden/MicroSplat/" + name + "_Base";

        string baseShader    = compiler.Compile(keywords, baseName);
        string regularShader = compiler.Compile(keywords, name, baseName);

        System.IO.File.WriteAllText(shaderPath, regularShader);
        System.IO.File.WriteAllText(shaderBasePath, baseShader);

        compiler.GenerateAuxShaders(name, shaderPath, new List <string>(keywords));

        AssetDatabase.Refresh();
        Shader s = AssetDatabase.LoadAssetAtPath <Shader> (shaderPath);

        if (s == null)
        {
            Debug.LogError("Shader not found at path " + shaderPath);
        }
        Material m = new Material(s);

        AssetDatabase.CreateAsset(m, matPath);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        var kwds = MicroSplatUtilities.FindOrCreateKeywords(m);

        kwds.keywords = new List <string> (keywords);
        EditorUtility.SetDirty(kwds);
        var propData = MicroSplatShaderGUI.FindOrCreatePropTex(m);

        if (propData != null)
        {
            EditorUtility.SetDirty(propData);
        }
        AssetDatabase.SaveAssets();

        return(AssetDatabase.LoadAssetAtPath <Material> (matPath));
    }
    public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
    {
        Undo.undoRedoPerformed -= Undo_UndoRedoPerformed;
        Undo.undoRedoPerformed += Undo_UndoRedoPerformed;
        Material targetMat = materialEditor.target as Material;

        if (cachedTitle == null)
        {
            cachedTitle = "Shader Generator        v:" + MicroSplatVersion;
        }
        if (moduleLabelStyle == null)
        {
            moduleLabelStyle           = new GUIStyle(EditorStyles.foldout);
            moduleLabelStyle.fontStyle = FontStyle.Bold;
        }
        if (GUI.enabled == false || string.IsNullOrEmpty(AssetDatabase.GetAssetPath(targetMat)))
        {
            EditorGUILayout.HelpBox("You must edit the template material, not the instance being used. You can find this in the MicroSplatData directory, or assigned on your MicroSplatTerrain component", MessageType.Info);
            return;
        }
        EditorGUI.BeginChangeCheck(); // sync materials

        var keywordSO = MicroSplatUtilities.FindOrCreateKeywords(targetMat);

        cachedKeywordCount = keywordSO.keywords.Count; // for undo
        cachedMaterial     = targetMat;

        compiler.Init();
        // must unpack everything before the generator draws- otherwise we get IMGUI errors
        for (int i = 0; i < compiler.extensions.Count; ++i)
        {
            var ext = compiler.extensions[i];
            ext.Unpack(keywordSO.keywords.ToArray());
        }

        string shaderName = targetMat.shader.name;

        DrawModules();

        EditorGUI.BeginChangeCheck(); // needs compile
        var propTex = FindOrCreatePropTex(targetMat);

        Undo.RecordObjects(new Object[3] {
            targetMat, keywordSO, propTex
        }, "MicroSplat Material Edit");
        using (new GUILayout.VerticalScope(MicroSplatUtilities.boxStyle))
        {
            if (MicroSplatUtilities.DrawRollup(cachedTitle))
            {
                GUILayout.BeginHorizontal();
                GUILayout.FlexibleSpace();
                if (bulkEditMode)
                {
                    if (GUILayout.Button("Exit Bulk Shader Feature Edit Mode", GUILayout.Width(230)))
                    {
                        bulkEditMode = false;
                        needsCompile = true;
                    }
                }
                else
                {
                    if (GUILayout.Button("Enter Bulk Shader Feature Edit Mode", GUILayout.Width(230)))
                    {
                        bulkEditMode = true;
                    }
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
                if (bulkEditMode)
                {
                    EditorGUILayout.HelpBox("Shader is in bulk edit mode, allowing you to change many options without recompiling the shader. No material properties will be shown during bulk editing, and the shader will be recompiled and properties shown once you exit this mode", MessageType.Warning);
                }

                shaderName = EditorGUILayout.DelayedTextField(CShaderName, shaderName);

                if (DrawRenderLoopGUI(keywordSO, targetMat))
                {
                    needsCompile = true;
                }

                for (int i = 0; i < compiler.extensions.Count; ++i)
                {
                    var e = compiler.extensions [i];
                    if (e.GetVersion() == MicroSplatVersion)
                    {
                        needsCompile = EditorGUI.EndChangeCheck() || needsCompile;

                        if (!moduleFoldoutState.ContainsKey(e.ModuleName()))
                        {
                            moduleFoldoutState [e.ModuleName()] = true;
                        }
                        // hack for invisible modules- need to make this more formal somehow?
                        bool empty = (e.ModuleName() == "Mesh" && (!keywordSO.IsKeywordEnabled("_MICROMESH") && !keywordSO.IsKeywordEnabled("_MICROVERTEXMESH")) || (e.ModuleName() == "MeshTerrain" && !keywordSO.IsKeywordEnabled("_MICROMESHTERRAIN")));


                        if (!empty)
                        {
                            using (new GUILayout.VerticalScope(MicroSplatUtilities.boxStyle))
                            {
                                EditorGUI.indentLevel++;
                                moduleFoldoutState [e.ModuleName()] = EditorGUILayout.Foldout(moduleFoldoutState [e.ModuleName()], e.ModuleName(), moduleLabelStyle);
                                //EditorGUILayout.LabelField (e.ModuleName (), moduleLabelStyle);
                                EditorGUI.BeginChangeCheck();
                                if (moduleFoldoutState [e.ModuleName()])
                                {
                                    //EditorGUI.indentLevel++;
                                    e.DrawFeatureGUI(keywordSO);
                                    //EditorGUI.indentLevel--;
                                }
                                EditorGUI.indentLevel--;
                            }
                        }
                        else
                        {
                            EditorGUI.BeginChangeCheck();
                        }
                    }
                    else
                    {
                        EditorGUILayout.HelpBox("Extension : " + e.ModuleName() + " is version " + e.GetVersion() + " and MicroSplat is version " + MicroSplatVersion + ", please update", MessageType.Error);
                    }
                }

                for (int i = 0; i < availableRenderLoops.Count; ++i)
                {
                    var rl = availableRenderLoops [i];
                    if (rl.GetVersion() != MicroSplatVersion)
                    {
                        EditorGUILayout.HelpBox("Render Loop : " + rl.GetDisplayName() + " is version " + rl.GetVersion() + " and MicroSplat is version " + MicroSplatVersion + ", please update", MessageType.Error);
                    }
                }
            }
            if (bulkEditMode)
            {
                if (!keywordSO.IsKeywordEnabled("_DISABLESPLATMAPS"))
                {
                    Texture2DArray diff = targetMat.GetTexture("_Diffuse") as Texture2DArray;
                    if (diff != null && MicroSplatUtilities.DrawRollup("Per Texture Properties"))
                    {
                        perTexIndex = MicroSplatUtilities.DrawTextureSelector(perTexIndex, diff);

                        for (int i = 0; i < compiler.extensions.Count; ++i)
                        {
                            var ext = compiler.extensions [i];
                            if (ext.GetVersion() == MicroSplatVersion)
                            {
                                ext.DrawPerTextureGUI(perTexIndex, keywordSO, targetMat, propTex);
                            }
                        }
                    }
                }

                needsCompile = needsCompile || EditorGUI.EndChangeCheck();
                if (needsCompile)
                {
                    keywordSO.keywords.Clear();
                    for (int i = 0; i < compiler.extensions.Count; ++i)
                    {
                        compiler.extensions [i].Pack(keywordSO);
                    }
                    if (compiler.renderLoop != null)
                    {
                        keywordSO.EnableKeyword(compiler.renderLoop.GetRenderLoopKeyword());
                    }
                    needsCompile = false;
                }
                return; // Don't draw rest of GUI
            }
        }
        needsCompile = needsCompile || EditorGUI.EndChangeCheck();

        int featureCount = keywordSO.keywords.Count;

        // note, ideally we wouldn't draw the GUI for the rest of stuff if we need to compile.
        // But we can't really do that without causing IMGUI to split warnings about
        // mismatched GUILayout blocks
        if (!needsCompile)
        {
            for (int i = 0; i < compiler.extensions.Count; ++i)
            {
                var ext = compiler.extensions [i];
                if (ext.GetVersion() == MicroSplatVersion)
                {
                    ext.DrawShaderGUI(this, keywordSO, targetMat, materialEditor, props);
                }
                else
                {
                    EditorGUILayout.HelpBox("Extension : " + ext.ModuleName() + " is version " + ext.GetVersion() + " and MicroSplat is version " + MicroSplatVersion + ", please update so that all modules are using the same version.", MessageType.Error);
                }
            }

            if (!keywordSO.IsKeywordEnabled("_DISABLESPLATMAPS"))
            {
                Texture2DArray diff = targetMat.GetTexture("_Diffuse") as Texture2DArray;
                if (diff != null && MicroSplatUtilities.DrawRollup("Per Texture Properties"))
                {
                    perTexIndex = MicroSplatUtilities.DrawTextureSelector(perTexIndex, diff);

                    for (int i = 0; i < compiler.extensions.Count; ++i)
                    {
                        var ext = compiler.extensions [i];
                        if (ext.GetVersion() == MicroSplatVersion)
                        {
                            ext.DrawPerTextureGUI(perTexIndex, keywordSO, targetMat, propTex);
                        }
                    }
                }
            }
        }

        if (!needsCompile)
        {
            if (featureCount != keywordSO.keywords.Count)
            {
                needsCompile = true;
            }
        }


        int arraySampleCount   = 0;
        int textureSampleCount = 0;
        int maxSamples         = 0;
        int tessSamples        = 0;
        int depTexReadLevel    = 0;

        builder.Length = 0;
        for (int i = 0; i < compiler.extensions.Count; ++i)
        {
            var ext = compiler.extensions [i];
            if (ext.GetVersion() == MicroSplatVersion)
            {
                ext.ComputeSampleCounts(keywordSO.keywords.ToArray(), ref arraySampleCount, ref textureSampleCount, ref maxSamples, ref tessSamples, ref depTexReadLevel);
            }
        }
        if (MicroSplatUtilities.DrawRollup("Debug"))
        {
            string shaderModel = compiler.GetShaderModel(keywordSO.keywords.ToArray());
            builder.Append("Shader Model : ");
            builder.AppendLine(shaderModel);
            if (maxSamples != arraySampleCount)
            {
                builder.Append("Texture Array Samples : ");
                builder.AppendLine(arraySampleCount.ToString());

                builder.Append("Regular Samples : ");
                builder.AppendLine(textureSampleCount.ToString());
            }
            else
            {
                builder.Append("Texture Array Samples : ");
                builder.AppendLine(arraySampleCount.ToString());
                builder.Append("Regular Samples : ");
                builder.AppendLine(textureSampleCount.ToString());
            }
            if (tessSamples > 0)
            {
                builder.Append("Tessellation Samples : ");
                builder.AppendLine(tessSamples.ToString());
            }
            if (depTexReadLevel > 0)
            {
                builder.Append(depTexReadLevel.ToString());
                builder.AppendLine(" areas with dependent texture reads");
            }

            EditorGUILayout.HelpBox(builder.ToString(), MessageType.Info);
        }

        if (EditorGUI.EndChangeCheck() && !needsCompile)
        {
            MicroSplatObject.SyncAll();
        }

        if (needsCompile)
        {
            needsCompile = false;
            keywordSO.keywords.Clear();
            for (int i = 0; i < compiler.extensions.Count; ++i)
            {
                compiler.extensions [i].Pack(keywordSO);
            }
            if (compiler.renderLoop != null)
            {
                keywordSO.EnableKeyword(compiler.renderLoop.GetRenderLoopKeyword());
            }

            // horrible workaround to GUI warning issues
            compileMat     = targetMat;
            compileName    = shaderName;
            targetCompiler = compiler;
            EditorApplication.delayCall += TriggerCompile;
        }
    }
Esempio n. 8
0
    bool DoConvertGUI(MicroSplatTerrain t)
    {
        if (t.templateMaterial == null)
        {
            InitConvertConfigs();
            using (new GUILayout.VerticalScope(GUI.skin.box))
            {
                EditorGUILayout.LabelField("Select any integrations you want to add:");
                // integrations
                for (int i = 0; i < integrationConfigs.Count; ++i)
                {
                    var ic = integrationConfigs [i];
                    if (!ic.assetInstalled)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField(ic.name, GUILayout.Width(120));
                        EditorGUILayout.LabelField("Not Installed", GUILayout.Width(120));
                        if (GUILayout.Button("Link", GUILayout.Width(120)))
                        {
                            Application.OpenURL(ic.assetLink);
                        }
                        EditorGUILayout.EndHorizontal();
                    }
                    else
                    {
                        EditorGUILayout.BeginHorizontal();
                        ic.include = EditorGUILayout.Toggle(ic.include, GUILayout.Width(20));
                        EditorGUILayout.LabelField(ic.name);
                        EditorGUILayout.EndHorizontal();
                        if (ic.include && ic.missingModules.Count > 0)
                        {
                            using (new GUILayout.VerticalScope(GUI.skin.box))
                            {
                                EditorGUILayout.HelpBox("Some MicroSplat modules requested by this module are not installed. Some or all features of the integration will not be active.", MessageType.Warning);
                                for (int j = 0; j < ic.missingModules.Count; ++j)
                                {
                                    var m = ic.missingModules [j];
                                    DrawMissingModule(m);
                                }
                            }
                        }
                    }
                }

                if (GUILayout.Button("Convert to MicroSplat"))
                {
                    // get all terrains in selection, not just this one, and treat as one giant terrain
                    var            objs     = Selection.gameObjects;
                    List <Terrain> terrains = new List <Terrain> ();
                    for (int i = 0; i < objs.Length; ++i)
                    {
                        Terrain ter = objs [i].GetComponent <Terrain> ();
                        if (ter != null)
                        {
                            terrains.Add(ter);
                        }
                        Terrain [] trs = objs [i].GetComponentsInChildren <Terrain> ();
                        for (int x = 0; x < trs.Length; ++x)
                        {
                            if (!terrains.Contains(trs [x]))
                            {
                                terrains.Add(trs [x]);
                            }
                        }
                    }


                    Terrain       terrain  = t.GetComponent <Terrain> ();
                    int           texcount = terrain.terrainData.terrainLayers.Length;
                    List <string> keywords = new List <string> (defaultKeywords);
                    // set initial render pipleine
                    var pipeline = MicroSplatUtilities.DetectPipeline();
                    if (pipeline == MicroSplatUtilities.PipelineType.HDPipeline)
                    {
                        keywords.Add("_MSRENDERLOOP_UNITYHD");
                    }
                    else if (pipeline == MicroSplatUtilities.PipelineType.UniversalPipeline)
                    {
                        keywords.Add("_MSRENDERLOOP_UNITYLD");
                    }


                    // Because new users won't read the manual or read settings before they act, we don't clamp the texture count
                    // down for maximum performance. Way to many support requests complaining of black terrain after adding textures because
                    // they didn't realize they needed to up the max texture count. So now, 16 minimum. This is why we can't have nice things.

                    /*
                     * if (texcount <= 4)
                     * {
                     * keywords.Add ("_MAX4TEXTURES");
                     * }
                     * else if (texcount <= 8)
                     * {
                     * keywords.Add ("_MAX8TEXTURES");
                     * }
                     * else if (texcount <= 12)
                     * {
                     * keywords.Add ("_MAX12TEXTURES");
                     * }
                     */
                    if (texcount > 16 && texcount <= 20)
                    {
                        keywords.Add("_MAX20TEXTURES");
                    }
                    else if (texcount <= 24)
                    {
                        keywords.Add("_MAX24TEXTURES");
                    }
                    else if (texcount <= 28)
                    {
                        keywords.Add("_MAX28TEXTURES");
                    }
                    else if (texcount > 28)
                    {
                        keywords.Add("_MAX32TEXTURES");
                    }


                    for (int i = 0; i < integrationConfigs.Count; ++i)
                    {
                        var ic = integrationConfigs [i];
                        if (ic.include)
                        {
                            keywords.AddRange(ic.keywords);
                        }
                    }

                    // setup this terrain
                    t.templateMaterial = MicroSplatShaderGUI.NewShaderAndMaterial(terrain, keywords.ToArray());

                    var config = TextureArrayConfigEditor.CreateConfig(terrain);
                    t.templateMaterial.SetTexture("_Diffuse", config.diffuseArray);
                    t.templateMaterial.SetTexture("_NormalSAO", config.normalSAOArray);

                    t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);
                    EditorUtility.SetDirty(t);
                    if (terrain.terrainData.terrainLayers != null)
                    {
                        if (terrain.terrainData.terrainLayers.Length > 0)
                        {
                            Vector2 min = new Vector2(99999, 99999);
                            Vector2 max = Vector2.zero;


                            for (int x = 0; x < terrain.terrainData.terrainLayers.Length; ++x)
                            {
                                var uv = terrain.terrainData.terrainLayers [x].tileSize;
                                if (min.x > uv.x)
                                {
                                    min.x = uv.x;
                                }
                                if (min.y > uv.y)
                                {
                                    min.y = uv.y;
                                }
                                if (max.x < uv.x)
                                {
                                    max.x = uv.x;
                                }
                                if (max.y < uv.y)
                                {
                                    max.y = uv.y;
                                }
                            }
                            Vector2 average = Vector2.Lerp(min, max, 0.5f);
                            // use per texture UVs instead..
                            float diff = Vector2.Distance(min, max);
                            if (diff > 0.1)
                            {
                                keywords.Add("_PERTEXUVSCALEOFFSET");

                                // if the user has widely different UVs, use the LOD sampler. This is because the gradient mode blends between mip levels,
                                // which looks bad with hugely different UVs. I still don't understand why people do this kind of crap though, ideally
                                // your UVs should not differ per texture, and if so, not by much..
                                if (diff > 10)
                                {
                                    Debug.LogWarning("Terrain has wildly varing UV scales, it's best to keep consistent texture resolution. ");
                                }
                                if (!keywords.Contains("_USEGRADMIP"))
                                {
                                    keywords.Add("_USEGRADMIP");
                                }
                                Vector4 scaleOffset = new Vector4(1, 1, 0, 0);
                                t.templateMaterial.SetVector("_UVScale", scaleOffset);
                                var propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);

                                for (int x = 0; x < terrain.terrainData.terrainLayers.Length; ++x)
                                {
                                    var uvScale  = terrain.terrainData.terrainLayers [x].tileSize;
                                    var uvOffset = terrain.terrainData.terrainLayers [x].tileOffset;
                                    uvScale   = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain);
                                    uvScale.x = Mathf.RoundToInt(uvScale.x);
                                    uvScale.y = Mathf.RoundToInt(uvScale.y);
                                    propData.SetValue(x, MicroSplatPropData.PerTexVector2.SplatUVScale, uvScale);
                                    propData.SetValue(x, MicroSplatPropData.PerTexVector2.SplatUVOffset, Vector2.zero);
                                }
                                for (int x = terrain.terrainData.terrainLayers.Length; x < 32; ++x)
                                {
                                    propData.SetValue(x, MicroSplatPropData.PerTexVector2.SplatUVScale, average);
                                    propData.SetValue(x, MicroSplatPropData.PerTexVector2.SplatUVOffset, Vector2.zero);
                                }
                                // must init the data, or the editor will write over it.

                                propData.SetValue(0, 15, Color.white);
                                EditorUtility.SetDirty(propData);

                                t.templateMaterial.SetVector("_TriplanarUVScale",
                                                             new Vector4(
                                                                 10.0f / t.terrain.terrainData.size.x,
                                                                 10.0f / t.terrain.terrainData.size.x, 0, 0));
                            }
                            else
                            {
                                var uvScale  = terrain.terrainData.terrainLayers [0].tileSize;
                                var uvOffset = terrain.terrainData.terrainLayers [0].tileOffset;

                                uvScale    = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain);
                                uvOffset.x = uvScale.x / terrain.terrainData.size.x * 0.5f * uvOffset.x;
                                uvOffset.y = uvScale.y / terrain.terrainData.size.x * 0.5f * uvOffset.y;
                                Vector4 scaleOffset = new Vector4(uvScale.x, uvScale.y, uvOffset.x, uvOffset.y);
                                t.templateMaterial.SetVector("_UVScale", scaleOffset);
                                t.templateMaterial.SetVector("_TriplanarUVScale",
                                                             new Vector4(
                                                                 10.0f / t.terrain.terrainData.size.x,
                                                                 10.0f / t.terrain.terrainData.size.x, 0, 0));
                            }
                        }
                    }


                    // now make sure others all have the same settings as well.
                    for (int i = 0; i < terrains.Count; ++i)
                    {
                        var nt  = terrains [i];
                        var mgr = nt.GetComponent <MicroSplatTerrain> ();
                        if (mgr == null)
                        {
                            mgr = nt.gameObject.AddComponent <MicroSplatTerrain> ();
                        }
                        mgr.templateMaterial = t.templateMaterial;

                        if (mgr.propData == null)
                        {
                            mgr.propData = MicroSplatShaderGUI.FindOrCreatePropTex(mgr.templateMaterial);
                        }
                    }


                    Selection.SetActiveObjectWithContext(config, config);
                    t.keywordSO = MicroSplatUtilities.FindOrCreateKeywords(t.templateMaterial);

                    t.keywordSO.keywords.Clear();
                    t.keywordSO.keywords = new List <string> (keywords);



                    // force recompile, so that basemap shader name gets reset correctly..
                    MicroSplatShaderGUI.MicroSplatCompiler comp = new MicroSplatShaderGUI.MicroSplatCompiler();
                    comp.Compile(t.templateMaterial);
                    // for some reason, often when  people create terrains with Gaia but this is unconfirmed,
                    // if instancing is set, the terrain will not draw until a shader feature is toggled.
                    // So for now, turn off instancing when doing conversion.
                    for (int i = 0; i < terrains.Count; ++i)
                    {
                        var nt = terrains [i];
                        nt.drawInstanced = false;
                    }


                    MicroSplatTerrain.SyncAll();

                    /*
                     * // turn on draw instanced if enabled and tessellation is disabled, unless render loop is LWRP/URP in which case it does work..
                     * if (t.keywordSO != null && (!t.keywordSO.IsKeywordEnabled("_TESSDISTANCE") || t.keywordSO.IsKeywordEnabled("_MSRENDERLOOP_UNITYLD")))
                     * {
                     * for (int i = 0; i < terrains.Count; ++i)
                     * {
                     *    var nt = terrains [i];
                     *    var mgr = nt.GetComponent<MicroSplatTerrain> ();
                     *    if (mgr != null && mgr.keywordSO != null && !mgr.keywordSO.IsKeywordEnabled("_MSRENDERLOOP_UNITYLD"))
                     *    {
                     *       nt.drawInstanced = true;
                     *    }
                     * }
                     * }
                     */
                    return(true);
                }
            }
        }
        return(false);
    }
Esempio n. 9
0
    public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
    {
        if (cachedTitle == null)
        {
            cachedTitle = "Shader Generator        v:" + MicroSplatVersion;
        }
        if (GUI.enabled == false)
        {
            EditorGUILayout.HelpBox("You must edit the template material, not the instance being used", MessageType.Info);
            return;
        }
        EditorGUI.BeginChangeCheck(); // sync materials
        Material       targetMat = materialEditor.target as Material;
        Texture2DArray diff      = targetMat.GetTexture("_Diffuse") as Texture2DArray;

        var keywordSO = MicroSplatUtilities.FindOrCreateKeywords(targetMat);

        compiler.Init();
        // must unpack everything before the generator draws- otherwise we get IMGUI errors
        for (int i = 0; i < compiler.extensions.Count; ++i)
        {
            var ext = compiler.extensions[i];
            ext.Unpack(keywordSO.keywords.ToArray());
        }

        string shaderName = targetMat.shader.name;

        DrawModules();

        EditorGUI.BeginChangeCheck(); // needs compile

        if (MicroSplatUtilities.DrawRollup(cachedTitle))
        {
            shaderName = EditorGUILayout.DelayedTextField(CShaderName, shaderName);

            if (DrawRenderLoopGUI(keywordSO, targetMat))
            {
                needsCompile = true;
            }

            for (int i = 0; i < compiler.extensions.Count; ++i)
            {
                var e = compiler.extensions[i];
                if (e.GetVersion() == MicroSplatVersion)
                {
                    //using (new GUILayout.VerticalScope(GUI.skin.box))
                    {
                        e.DrawFeatureGUI(keywordSO);
                    }
                }
                else
                {
                    EditorGUILayout.HelpBox("Extension : " + e + " is version " + e.GetVersion() + " and MicroSplat is version " + MicroSplatVersion + ", please update", MessageType.Error);
                }
            }

            for (int i = 0; i < availableRenderLoops.Count; ++i)
            {
                var rl = availableRenderLoops[i];
                if (rl.GetVersion() != MicroSplatVersion)
                {
                    EditorGUILayout.HelpBox("Render Loop : " + rl.GetDisplayName() + " is version " + rl.GetVersion() + " and MicroSplat is version " + MicroSplatVersion + ", please update", MessageType.Error);
                }
            }
        }
        needsCompile = needsCompile || EditorGUI.EndChangeCheck();

        int featureCount = keywordSO.keywords.Count;

        // note, ideally we wouldn't draw the GUI for the rest of stuff if we need to compile.
        // But we can't really do that without causing IMGUI to split warnings about
        // mismatched GUILayout blocks
        if (!needsCompile)
        {
            for (int i = 0; i < compiler.extensions.Count; ++i)
            {
                var ext = compiler.extensions[i];
                if (ext.GetVersion() == MicroSplatVersion)
                {
                    ext.DrawShaderGUI(this, keywordSO, targetMat, materialEditor, props);
                }
                else
                {
                    EditorGUILayout.HelpBox("Extension : " + ext + " is version " + ext.GetVersion() + " and MicroSplat is version " + MicroSplatVersion + ", please update so that all modules are using the same version.", MessageType.Error);
                }
            }


            if (diff != null && MicroSplatUtilities.DrawRollup("Per Texture Properties"))
            {
                var propTex = FindOrCreatePropTex(targetMat);
                perTexIndex = MicroSplatUtilities.DrawTextureSelector(perTexIndex, diff);
                for (int i = 0; i < compiler.extensions.Count; ++i)
                {
                    var ext = compiler.extensions[i];
                    if (ext.GetVersion() == MicroSplatVersion)
                    {
                        ext.DrawPerTextureGUI(perTexIndex, keywordSO, targetMat, propTex);
                    }
                }
            }
        }

        if (!needsCompile)
        {
            if (featureCount != keywordSO.keywords.Count)
            {
                needsCompile = true;
            }
        }


        int arraySampleCount   = 0;
        int textureSampleCount = 0;
        int maxSamples         = 0;
        int tessSamples        = 0;
        int depTexReadLevel    = 0;

        builder.Length = 0;
        for (int i = 0; i < compiler.extensions.Count; ++i)
        {
            var ext = compiler.extensions[i];
            if (ext.GetVersion() == MicroSplatVersion)
            {
                ext.ComputeSampleCounts(keywordSO.keywords.ToArray(), ref arraySampleCount, ref textureSampleCount, ref maxSamples, ref tessSamples, ref depTexReadLevel);
            }
        }
        if (MicroSplatUtilities.DrawRollup("Debug"))
        {
            string shaderModel = compiler.GetShaderModel(keywordSO.keywords.ToArray());
            builder.Append("Shader Model : ");
            builder.AppendLine(shaderModel);
            if (maxSamples != arraySampleCount)
            {
                builder.Append("Texture Array Samples : ");
                builder.AppendLine(arraySampleCount.ToString());

                builder.Append("Regular Samples : ");
                builder.AppendLine(textureSampleCount.ToString());
            }
            else
            {
                builder.Append("Texture Array Samples : ");
                builder.AppendLine(arraySampleCount.ToString());
                builder.Append("Regular Samples : ");
                builder.AppendLine(textureSampleCount.ToString());
            }
            if (tessSamples > 0)
            {
                builder.Append("Tessellation Samples : ");
                builder.AppendLine(tessSamples.ToString());
            }
            if (depTexReadLevel > 0)
            {
                builder.Append(depTexReadLevel.ToString());
                builder.AppendLine(" areas with dependent texture reads");
            }

            EditorGUILayout.HelpBox(builder.ToString(), MessageType.Info);
        }

        if (EditorGUI.EndChangeCheck() && !needsCompile)
        {
            MicroSplatTerrain.SyncAll();
#if __MICROSPLAT_MESH__
            MicroSplatMesh.SyncAll();
#endif
        }

        if (needsCompile)
        {
            needsCompile = false;
            keywordSO.keywords.Clear();
            for (int i = 0; i < compiler.extensions.Count; ++i)
            {
                compiler.extensions[i].Pack(keywordSO);
            }
            if (compiler.renderLoop != null)
            {
                keywordSO.EnableKeyword(compiler.renderLoop.GetRenderLoopKeyword());
            }

            // horrible workaround to GUI warning issues
            compileMat     = targetMat;
            compileName    = shaderName;
            targetCompiler = compiler;
            EditorApplication.delayCall += TriggerCompile;
        }
    }
   public static Texture2D Bake(MicroSplatTerrain mst, BakingPasses p, int resolution, Texture2D worldPos, Texture2D worldNormal)
   {
      Camera cam = new GameObject("cam").AddComponent<Camera>();
      cam.orthographic = true;
      cam.orthographicSize = 0.5f;
      cam.transform.position = new Vector3(0.5f, 10000.5f, -1);
      cam.nearClipPlane = 0.1f;
      cam.farClipPlane = 2.0f;
      cam.enabled = false;
      cam.depthTextureMode = DepthTextureMode.None;
      cam.clearFlags = CameraClearFlags.Color;
      cam.backgroundColor = Color.grey;

      var debugOutput = OutputFromPass(p);
      var readWrite = (debugOutput == MicroSplatBaseFeatures.DebugOutput.Albedo || debugOutput == MicroSplatBaseFeatures.DebugOutput.Emission) ?
         RenderTextureReadWrite.sRGB : RenderTextureReadWrite.Linear;

      RenderTexture rt = RenderTexture.GetTemporary(resolution, resolution, 0, RenderTextureFormat.ARGB32, readWrite);
      RenderTexture.active = rt;
      cam.targetTexture = rt;

      GameObject go = GameObject.CreatePrimitive(PrimitiveType.Quad);
      go.transform.position = new Vector3(0, 10000, 0);
      cam.transform.position = new Vector3(0, 10000, -1);
      Material renderMat = SetupMaterial(MicroSplatUtilities.FindOrCreateKeywords(mst.templateMaterial), mst.matInstance, debugOutput, worldPos != null);
      renderMat.SetTexture("_DebugWorldPos", worldPos);
      renderMat.SetTexture("_DebugWorldNormal", worldNormal);

      go.GetComponent<MeshRenderer>().sharedMaterial = renderMat;
      bool fog = RenderSettings.fog;
      if (p == BakingPasses.Normal)
      {
         cam.backgroundColor = Color.blue;
      }
      else
      {
         cam.backgroundColor = Color.gray;
      }

      // this is a strange one, at 0,0,0 rotation the albedo won't render on Windows platforms, so parent the cam to the quad and rotate it a bit
      cam.transform.SetParent(go.transform);
      go.transform.rotation = Quaternion.Euler(0.01f, 0, 0);

      var ambInt = RenderSettings.ambientIntensity;
      var reflectInt = RenderSettings.reflectionIntensity;
      RenderSettings.ambientIntensity = 0;
      RenderSettings.reflectionIntensity = 0;
      Unsupported.SetRenderSettingsUseFogNoDirty(false);
      cam.Render();
      Unsupported.SetRenderSettingsUseFogNoDirty(fog);

      RenderSettings.ambientIntensity = ambInt;
      RenderSettings.reflectionIntensity = reflectInt;
      Texture2D tex = new Texture2D(resolution, resolution, TextureFormat.ARGB32, false);
      tex.ReadPixels(new Rect(0, 0, resolution, resolution), 0, 0);
      RenderTexture.active = null;
      RenderTexture.ReleaseTemporary(rt);

      tex.Apply();


      MeshRenderer mr = go.GetComponent<MeshRenderer>();
      if (mr != null)
      {
         if (mr.sharedMaterial != null)
         {
            if (mr.sharedMaterial.shader != null)
               GameObject.DestroyImmediate(mr.sharedMaterial.shader);
            GameObject.DestroyImmediate(mr.sharedMaterial);
         }
      }

      GameObject.DestroyImmediate(go); // cam is child, so will be destroyed too

      return tex;
   }
    public override void OnInspectorGUI()
    {
        MicroSplatTerrain t = target as MicroSplatTerrain;

        if (t == null)
        {
            EditorGUILayout.HelpBox("No Terrain Present, please put this component on a terrain", MessageType.Error);
            return;
        }
        EditorGUI.BeginChangeCheck();
        t.templateMaterial = EditorGUILayout.ObjectField(CTemplateMaterial, t.templateMaterial, typeof(Material), false) as Material;
        if (EditorGUI.EndChangeCheck())
        {
            MicroSplatTerrain.SyncAll();
        }
        EditorGUI.BeginChangeCheck();


        if (DoConvertGUI(t))
        {
            return;
        }

        if (t.templateMaterial == null)
        {
            return;
        }

        if (t.propData == null)
        {
            t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);
            EditorUtility.SetDirty(t);
            MicroSplatObject.SyncAll();
        }

        if (t.keywordSO == null)
        {
            t.keywordSO = MicroSplatUtilities.FindOrCreateKeywords(t.templateMaterial);
            EditorUtility.SetDirty(t);
        }

        EditorGUI.BeginChangeCheck();

#if __MICROSPLAT_PROCTEX__
        if (t.keywordSO.IsKeywordEnabled("_PROCEDURALTEXTURE") || t.keywordSO.IsKeywordEnabled("_PCHEIGHTGRADIENT") || t.keywordSO.IsKeywordEnabled("_PCHEIGHTHSV"))
        {
            var old = t.procTexCfg;
            t.procTexCfg = MicroSplatProceduralTexture.FindOrCreateProceduralConfig(t.templateMaterial);
            if (old != t.procTexCfg)
            {
                EditorUtility.SetDirty(t);
                MicroSplatObject.SyncAll();
            }
        }
#endif

#if __MICROSPLAT_TERRAINBLEND__ || __MICROSPLAT_STREAMS__
        DoTerrainDescGUI();
#endif

        DoPerPixelNormalGUI();

#if __MICROSPLAT_PROCTEX__
        if (t.keywordSO.IsKeywordEnabled(MicroSplatProceduralTexture.GetFeatureName(MicroSplatProceduralTexture.DefineFeature._PCCAVITY)) ||
            t.keywordSO.IsKeywordEnabled(MicroSplatProceduralTexture.GetFeatureName(MicroSplatProceduralTexture.DefineFeature._PCFLOW)))
        {
            DoCavityMapGUI();
        }
#endif
        // could move this to some type of interfaced component created by the module if this becomes a thing,
        // but I think this will be most of the cases?

        MicroSplatUtilities.DrawTextureField(t, CCustomSplat0, ref t.customControl0, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat1, ref t.customControl1, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat2, ref t.customControl2, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat3, ref t.customControl3, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat4, ref t.customControl4, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat5, ref t.customControl5, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat6, ref t.customControl6, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat7, ref t.customControl7, "_CUSTOMSPLATTEXTURES");

        // perpixel normal
        MicroSplatUtilities.DrawTextureField(t, perPixelNormal, ref t.perPixelNormal, "_PERPIXELNORMAL");

        // global texture overrides
#if __MICROSPLAT_GLOBALTEXTURE__
        MicroSplatUtilities.DrawTextureField(t, geoTexOverride, ref t.geoTextureOverride, "_GEOMAP");
        MicroSplatUtilities.DrawTextureField(t, geoTintOverride, ref t.tintMapOverride, "_GLOBALTINT");
        MicroSplatUtilities.DrawTextureField(t, geoNormalOverride, ref t.globalNormalOverride, "_GLOBALNORMALS");
        MicroSplatUtilities.DrawTextureField(t, geoSAOMOverride, ref t.globalSAOMOverride, "_GLOBALSMOOTHAOMETAL");
        MicroSplatUtilities.DrawTextureField(t, geoEmisOverride, ref t.globalEmisOverride, "_GLOBALEMIS");
#endif

#if __MICROSPLAT_SNOW__
        MicroSplatUtilities.DrawTextureField(t, snowMaskOverride, ref t.snowMaskOverride, "_SNOWMASK");
#endif

#if __MICROSPLAT_ALPHAHOLE__
        // alpha hole override
        MicroSplatUtilities.DrawTextureField(t, clipMapOverride, ref t.clipMap, "_ALPHAHOLETEXTURE");
#endif

#if (VEGETATION_STUDIO || VEGETATION_STUDIO_PRO)
        // vsstudio overrides
        MicroSplatUtilities.DrawTextureField(t, CVSGrassMap, ref t.vsGrassMap, "_VSGRASSMAP");
        MicroSplatUtilities.DrawTextureField(t, CVSShadowMap, ref t.vsShadowMap, "_VSSHADOWMAP");
#endif


#if __MICROSPLAT_PROCTEX__
        MicroSplatUtilities.DrawTextureField(t, biomeOverride, ref t.procBiomeMask, "_PROCEDURALTEXTURE");
#endif

#if __MICROSPLAT_STREAMS__
        MicroSplatUtilities.DrawTextureField(t, streamOverride, ref t.streamTexture, "_WETNESS", "_PUDDLES", "_STREAMS", "_LAVA", false);
#endif

#if __MICROSPLAT_ADVANCED_DETAIL__
        DrawAdvancedModuleDetailGUI(t);
#endif


        if (t.propData == null && t.templateMaterial != null)
        {
            t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);
            if (t.propData == null)
            {
                // this should really never happen, but users seem to have issues with unassigned propData's a lot. I think
                // this is from external tools like MapMagic not creating it, but the above call should create it.
                EditorGUILayout.HelpBox("PropData is null, please assign", MessageType.Error);
                t.propData = EditorGUILayout.ObjectField("Per Texture Data", t.propData, typeof(MicroSplatPropData), false) as MicroSplatPropData;
            }
        }

        if (EditorGUI.EndChangeCheck())
        {
            MicroSplatTerrain.SyncAll();
        }


        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("Sync"))
        {
            var mgr = target as MicroSplatTerrain;
            mgr.Sync();
        }
        if (GUILayout.Button("Sync All"))
        {
            MicroSplatTerrain.SyncAll();
        }
        EditorGUILayout.EndHorizontal();

        BakingGUI(t);
        WeightLimitingGUI(t);
        ImportExportGUI();

#if __MICROSPLAT_ADVANCED_DETAIL__
        DrawAdvancedModuleDetailTooset(t);
#endif

        if (MicroSplatUtilities.DrawRollup("Debug", false, true))
        {
            EditorGUI.indentLevel += 2;
            EditorGUILayout.HelpBox("These should not need to be edited unless something funky has happened. They are automatically managed by MicroSplat.", MessageType.Info);
            t.propData = EditorGUILayout.ObjectField("Per Texture Data", t.propData, typeof(MicroSplatPropData), false) as MicroSplatPropData;
#if __MICROSPLAT_PROCTEX__
            t.procTexCfg = EditorGUILayout.ObjectField("Procedural Config", t.procTexCfg, typeof(MicroSplatProceduralTextureConfig), false) as MicroSplatProceduralTextureConfig;
#endif
            t.keywordSO            = EditorGUILayout.ObjectField("Keywords", t.keywordSO, typeof(MicroSplatKeywords), false) as MicroSplatKeywords;
            t.blendMat             = EditorGUILayout.ObjectField(CBlendMat, t.blendMat, typeof(Material), false) as Material;
            t.addPass              = EditorGUILayout.ObjectField("Add Pass", t.addPass, typeof(Shader), false) as Shader;
            EditorGUI.indentLevel -= 2;
        }
        if (EditorGUI.EndChangeCheck())
        {
            EditorUtility.SetDirty(t);
        }
    }
Esempio n. 12
0
    public override void OnInspectorGUI()
    {
        MicroSplatTerrain t = target as MicroSplatTerrain;

        if (t == null)
        {
            EditorGUILayout.HelpBox("No Terrain Present, please put this component on a terrain", MessageType.Error);
            return;
        }
        EditorGUI.BeginChangeCheck();
        t.templateMaterial = EditorGUILayout.ObjectField(CTemplateMaterial, t.templateMaterial, typeof(Material), false) as Material;


        if (t.templateMaterial == null)
        {
            if (GUILayout.Button("Convert to MicroSplat"))
            {
                // get all terrains in selection, not just this one, and treat as one giant terrain
                var            objs     = Selection.gameObjects;
                List <Terrain> terrains = new List <Terrain>();
                for (int i = 0; i < objs.Length; ++i)
                {
                    Terrain ter = objs[i].GetComponent <Terrain>();
                    if (ter != null)
                    {
                        terrains.Add(ter);
                    }
                    Terrain[] trs = objs[i].GetComponentsInChildren <Terrain>();
                    for (int x = 0; x < trs.Length; ++x)
                    {
                        if (!terrains.Contains(trs[x]))
                        {
                            terrains.Add(trs[x]);
                        }
                    }
                }
                // setup this terrain
                Terrain terrain = t.GetComponent <Terrain>();
                t.templateMaterial = MicroSplatShaderGUI.NewShaderAndMaterial(terrain);
                var config = TextureArrayConfigEditor.CreateConfig(terrain);
                t.templateMaterial.SetTexture("_Diffuse", config.diffuseArray);
                t.templateMaterial.SetTexture("_NormalSAO", config.normalSAOArray);

                t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);
#if UNITY_2018_3_OR_NEWER
                if (terrain.terrainData.terrainLayers.Length > 0)
                {
                    var uvScale  = terrain.terrainData.terrainLayers[0].tileSize;
                    var uvOffset = terrain.terrainData.terrainLayers[0].tileOffset;

                    uvScale    = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain);
                    uvOffset.x = uvScale.x / terrain.terrainData.size.x * 0.5f * uvOffset.x;
                    uvOffset.y = uvScale.y / terrain.terrainData.size.x * 0.5f * uvOffset.y;
                    Vector4 scaleOffset = new Vector4(uvScale.x, uvScale.y, uvOffset.x, uvOffset.y);
                    t.templateMaterial.SetVector("_UVScale", scaleOffset);
                }
#else
                if (terrain.terrainData.splatPrototypes.Length > 0)
                {
                    var uvScale  = terrain.terrainData.splatPrototypes[0].tileSize;
                    var uvOffset = terrain.terrainData.splatPrototypes[0].tileOffset;

                    uvScale    = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain);
                    uvOffset.x = uvScale.x / terrain.terrainData.size.x * 0.5f * uvOffset.x;
                    uvOffset.y = uvScale.y / terrain.terrainData.size.x * 0.5f * uvOffset.y;
                    Vector4 scaleOffset = new Vector4(uvScale.x, uvScale.y, uvOffset.x, uvOffset.y);
                    t.templateMaterial.SetVector("_UVScale", scaleOffset);
                }
#endif

                // now make sure others all have the same settings as well.
                for (int i = 0; i < terrains.Count; ++i)
                {
                    var nt  = terrains[i];
                    var mgr = nt.GetComponent <MicroSplatTerrain>();
                    if (mgr == null)
                    {
                        mgr = nt.gameObject.AddComponent <MicroSplatTerrain>();
                    }
                    mgr.templateMaterial = t.templateMaterial;

                    if (mgr.propData == null)
                    {
                        mgr.propData = MicroSplatShaderGUI.FindOrCreatePropTex(mgr.templateMaterial);
                    }
                }
                Selection.SetActiveObjectWithContext(config, config);
            }
            MicroSplatTerrain.SyncAll();
            return;
        }

        if (t.propData == null)
        {
            t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);
            EditorUtility.SetDirty(t);
        }

        if (t.keywordSO == null)
        {
            t.keywordSO = MicroSplatUtilities.FindOrCreateKeywords(t.templateMaterial);
            EditorUtility.SetDirty(t);
        }

        EditorGUI.BeginChangeCheck();

#if __MICROSPLAT_PROCTEX__
        if (t.keywordSO.IsKeywordEnabled("_PROCEDURALTEXTURE") || t.keywordSO.IsKeywordEnabled("_PCHEIGHTGRADIENT") || t.keywordSO.IsKeywordEnabled("_PCHEIGHTHSV"))
        {
            var old = t.procTexCfg;
            t.procTexCfg = MicroSplatProceduralTexture.FindOrCreateProceduralConfig(t.templateMaterial);
            if (old != t.procTexCfg)
            {
                EditorUtility.SetDirty(t);
            }
        }
#endif

#if __MICROSPLAT_TERRAINBLEND__ || __MICROSPLAT_STREAMS__
        DoTerrainDescGUI();
#endif

        DoPerPixelNormalGUI();

#if __MICROSPLAT_PROCTEX__
        if (t.keywordSO.IsKeywordEnabled(MicroSplatProceduralTexture.GetFeatureName(MicroSplatProceduralTexture.DefineFeature._PCCAVITY)) ||
            t.keywordSO.IsKeywordEnabled(MicroSplatProceduralTexture.GetFeatureName(MicroSplatProceduralTexture.DefineFeature._PCFLOW)))
        {
            DoCavityMapGUI();
        }
#endif
        // could move this to some type of interfaced component created by the module if this becomes a thing,
        // but I think this will be most of the cases?

        MicroSplatUtilities.DrawTextureField(t, CCustomSplat0, ref t.customControl0, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat1, ref t.customControl1, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat2, ref t.customControl2, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat3, ref t.customControl3, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat4, ref t.customControl4, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat5, ref t.customControl5, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat6, ref t.customControl6, "_CUSTOMSPLATTEXTURES");
        MicroSplatUtilities.DrawTextureField(t, CCustomSplat7, ref t.customControl7, "_CUSTOMSPLATTEXTURES");

        // perpixel normal
        MicroSplatUtilities.DrawTextureField(t, perPixelNormal, ref t.perPixelNormal, "_PERPIXELNORMAL");

        // global texture overrides
#if __MICROSPLAT_GLOBALTEXTURE__
        MicroSplatUtilities.DrawTextureField(t, geoTexOverride, ref t.geoTextureOverride, "_GEOMAP");
        MicroSplatUtilities.DrawTextureField(t, geoTintOverride, ref t.tintMapOverride, "_GLOBALTINT");
        MicroSplatUtilities.DrawTextureField(t, geoNormalOverride, ref t.globalNormalOverride, "_GLOBALNORMALS");
        MicroSplatUtilities.DrawTextureField(t, geoSAOMOverride, ref t.globalSAOMOverride, "_GLOBALSMOOTHAOMETAL");
        MicroSplatUtilities.DrawTextureField(t, geoEmisOverride, ref t.globalEmisOverride, "_GLOBALEMIS");
#endif

#if __MICROSPLAT_ALPHAHOLE__
        // alpha hole override
        MicroSplatUtilities.DrawTextureField(t, clipMapOverride, ref t.clipMap, "_ALPHAHOLETEXTURE");
#endif

#if (VEGETATION_STUDIO || VEGETATION_STUDIO_PRO)
        // vsstudio overrides
        MicroSplatUtilities.DrawTextureField(t, CVSGrassMap, ref t.vsGrassMap, "_VSGRASSMAP");
        MicroSplatUtilities.DrawTextureField(t, CVSShadowMap, ref t.vsShadowMap, "_VSSHADOWMAP");
#endif


#if __MICROSPLAT_PROCTEX__
        MicroSplatUtilities.DrawTextureField(t, biomeOverride, ref t.procBiomeMask, "_PROCEDURALTEXTURE");
#endif

#if __MICROSPLAT_ADVANCED_DETAIL__
        DrawAdvancedModuleDetailGUI(t);
#endif


        if (t.propData == null && t.templateMaterial != null)
        {
            t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);
            if (t.propData == null)
            {
                // this should really never happen, but users seem to have issues with unassigned propData's a lot. I think
                // this is from external tools like MapMagic not creating it, but the above call should create it.
                EditorGUILayout.HelpBox("PropData is null, please assign", MessageType.Error);
                t.propData = EditorGUILayout.ObjectField("Per Texture Data", t.propData, typeof(MicroSplatPropData), false) as MicroSplatPropData;
            }
        }

        if (EditorGUI.EndChangeCheck())
        {
            MicroSplatTerrain.SyncAll();
        }


        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("Sync"))
        {
            var mgr = target as MicroSplatTerrain;
            mgr.Sync();
        }
        if (GUILayout.Button("Sync All"))
        {
            MicroSplatTerrain.SyncAll();
        }
        EditorGUILayout.EndHorizontal();

        BakingGUI(t);
        WeightLimitingGUI(t);
        ImportExportGUI();

#if __MICROSPLAT_ADVANCED_DETAIL__
        DrawAdvancedModuleDetailTooset(t);
#endif

        if (MicroSplatUtilities.DrawRollup("Debug", false, true))
        {
            EditorGUI.indentLevel += 2;
            EditorGUILayout.HelpBox("These should not need to be edited unless something funky has happened. They are automatically managed by MicroSplat.", MessageType.Info);
            t.propData = EditorGUILayout.ObjectField("Per Texture Data", t.propData, typeof(MicroSplatPropData), false) as MicroSplatPropData;
#if __MICROSPLAT_PROCTEX__
            t.procTexCfg = EditorGUILayout.ObjectField("Procedural Config", t.procTexCfg, typeof(MicroSplatProceduralTextureConfig), false) as MicroSplatProceduralTextureConfig;
#endif
            t.keywordSO            = EditorGUILayout.ObjectField("Keywords", t.keywordSO, typeof(MicroSplatKeywords), false) as MicroSplatKeywords;
            t.blendMat             = EditorGUILayout.ObjectField(CBlendMat, t.blendMat, typeof(Material), false) as Material;
            t.terrainDesc          = EditorGUILayout.ObjectField("Terrain Descriptor", t.terrainDesc, typeof(Texture2D), false) as Texture2D;
            t.perPixelNormal       = EditorGUILayout.ObjectField("Normal Data", t.perPixelNormal, typeof(Texture2D), false) as Texture2D;
            t.addPass              = EditorGUILayout.ObjectField("Add Pass", t.addPass, typeof(Shader), false) as Shader;
            EditorGUI.indentLevel -= 2;
        }
        if (EditorGUI.EndChangeCheck())
        {
            EditorUtility.SetDirty(t);
        }
    }
Esempio n. 13
0
    bool DoConvertGUI(MicroSplatTerrain t)
    {
        if (t.templateMaterial == null)
        {
            InitConvertConfigs();
            using (new GUILayout.VerticalScope(GUI.skin.box))
            {
                EditorGUILayout.LabelField("Select a Template:");

                EditorGUILayout.BeginHorizontal();
                for (int i = 0; i < convertConfigs.Count; ++i)
                {
                    var c = convertConfigs [i];
                    if (DrawConvertButton(c, i == selectedConvertConfig))
                    {
                        selectedConvertConfig = i;
                    }
                }
                EditorGUILayout.EndHorizontal();

                var selectedConfig = convertConfigs [selectedConvertConfig];
                if (selectedConfig.missingModules.Count > 0)
                {
                    EditorGUILayout.HelpBox("You are missing some MicroSplat modules needed by this template. The preset may still be used but some features will not be enabled. Missing modules are listed below:", MessageType.Warning);
                    for (int i = 0; i < selectedConfig.missingModules.Count; ++i)
                    {
                        var m = selectedConfig.missingModules [i];
                        DrawMissingModule(m);
                    }
                }

                EditorGUILayout.LabelField("Select any integrations you want to add:");
                // integrations
                for (int i = 0; i < integrationConfigs.Count; ++i)
                {
                    var ic = integrationConfigs [i];
                    if (!ic.assetInstalled)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField(ic.name, GUILayout.Width(120));
                        EditorGUILayout.LabelField("Not Installed", GUILayout.Width(120));
                        if (GUILayout.Button("Link", GUILayout.Width(120)))
                        {
                            Application.OpenURL(ic.assetLink);
                        }
                        EditorGUILayout.EndHorizontal();
                    }
                    else
                    {
                        EditorGUILayout.BeginHorizontal();
                        ic.include = EditorGUILayout.Toggle(ic.include, GUILayout.Width(20));
                        EditorGUILayout.LabelField(ic.name);
                        EditorGUILayout.EndHorizontal();
                        if (ic.include && ic.missingModules.Count > 0)
                        {
                            using (new GUILayout.VerticalScope(GUI.skin.box))
                            {
                                EditorGUILayout.HelpBox("Some MicroSplat modules requested by this module are not installed. Some or all features of the integration will not be active.", MessageType.Warning);
                                for (int j = 0; j < ic.missingModules.Count; ++j)
                                {
                                    var m = ic.missingModules [j];
                                    DrawMissingModule(m);
                                }
                            }
                        }
                    }
                }

                if (GUILayout.Button("Convert to MicroSplat"))
                {
                    // get all terrains in selection, not just this one, and treat as one giant terrain
                    var            objs     = Selection.gameObjects;
                    List <Terrain> terrains = new List <Terrain> ();
                    for (int i = 0; i < objs.Length; ++i)
                    {
                        Terrain ter = objs [i].GetComponent <Terrain> ();
                        if (ter != null)
                        {
                            terrains.Add(ter);
                        }
                        Terrain [] trs = objs [i].GetComponentsInChildren <Terrain> ();
                        for (int x = 0; x < trs.Length; ++x)
                        {
                            if (!terrains.Contains(trs [x]))
                            {
                                terrains.Add(trs [x]);
                            }
                        }
                    }

                    Terrain terrain  = t.GetComponent <Terrain> ();
                    int     texcount = 16;
#if UNITY_2018_3_OR_NEWER
                    texcount = terrain.terrainData.terrainLayers.Length;
#else
                    texcount = terrain.terrainData.splatPrototypes.Length;
#endif
                    List <string> keywords = new List <string> (selectedConfig.keywords);
                    if (texcount <= 4)
                    {
                        keywords.Add("_MAX4TEXTURES");
                    }
                    else if (texcount <= 8)
                    {
                        keywords.Add("_MAX8TEXTURES");
                    }
                    else if (texcount <= 12)
                    {
                        keywords.Add("_MAX12TEXTURES");
                    }
                    else if (texcount <= 20)
                    {
                        keywords.Add("_MAX20TEXTURES");
                    }
                    else if (texcount <= 24)
                    {
                        keywords.Add("_MAX24TEXTURES");
                    }
                    else if (texcount <= 28)
                    {
                        keywords.Add("_MAX28TEXTURES");
                    }
                    else if (texcount > 28)
                    {
                        keywords.Add("_MAX32TEXTURES");
                    }

                    for (int i = 0; i < integrationConfigs.Count; ++i)
                    {
                        var ic = integrationConfigs [i];
                        if (ic.include)
                        {
                            keywords.AddRange(ic.keywords);
                        }
                    }

                    // setup this terrain
                    t.templateMaterial = MicroSplatShaderGUI.NewShaderAndMaterial(terrain, keywords.ToArray());

                    var config = TextureArrayConfigEditor.CreateConfig(terrain);
                    t.templateMaterial.SetTexture("_Diffuse", config.diffuseArray);
                    t.templateMaterial.SetTexture("_NormalSAO", config.normalSAOArray);

                    t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial);
#if UNITY_2018_3_OR_NEWER
                    if (terrain.terrainData.terrainLayers.Length > 0)
                    {
                        var uvScale  = terrain.terrainData.terrainLayers[0].tileSize;
                        var uvOffset = terrain.terrainData.terrainLayers[0].tileOffset;

                        uvScale    = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain);
                        uvOffset.x = uvScale.x / terrain.terrainData.size.x * 0.5f * uvOffset.x;
                        uvOffset.y = uvScale.y / terrain.terrainData.size.x * 0.5f * uvOffset.y;
                        Vector4 scaleOffset = new Vector4(uvScale.x, uvScale.y, uvOffset.x, uvOffset.y);
                        t.templateMaterial.SetVector("_UVScale", scaleOffset);
                    }
#else
                    if (terrain.terrainData.splatPrototypes.Length > 0)
                    {
                        var uvScale  = terrain.terrainData.splatPrototypes [0].tileSize;
                        var uvOffset = terrain.terrainData.splatPrototypes [0].tileOffset;

                        uvScale    = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain);
                        uvOffset.x = uvScale.x / terrain.terrainData.size.x * 0.5f * uvOffset.x;
                        uvOffset.y = uvScale.y / terrain.terrainData.size.x * 0.5f * uvOffset.y;
                        Vector4 scaleOffset = new Vector4(uvScale.x, uvScale.y, uvOffset.x, uvOffset.y);
                        t.templateMaterial.SetVector("_UVScale", scaleOffset);
                    }
#endif
                    // we need to set a few things on the material if certain features are enabled.
                    // Test for property existence as module might not be installed and feature was culled.
                    if (System.Array.Exists(selectedConfig.keywords, x => x == "_TRIPLANAR"))
                    {
                        if (t.templateMaterial.HasProperty("_TriplanarUVScale"))
                        {
                            t.templateMaterial.SetVector("_TriplanarUVScale", new Vector4(0.25f, 0.25f, 0, 0));
                        }
                    }

                    if (System.Array.Exists(selectedConfig.keywords, x => x == "_NORMALNOISE"))
                    {
                        if (t.templateMaterial.HasProperty("_NormalNoise"))
                        {
                            t.templateMaterial.SetTexture("_NormalNoise", MicroSplatUtilities.GetAutoTexture("microsplat_def_detail_normal_01"));
                        }
                    }

                    // now make sure others all have the same settings as well.
                    for (int i = 0; i < terrains.Count; ++i)
                    {
                        var nt  = terrains [i];
                        var mgr = nt.GetComponent <MicroSplatTerrain> ();
                        if (mgr == null)
                        {
                            mgr = nt.gameObject.AddComponent <MicroSplatTerrain> ();
                        }
                        mgr.templateMaterial = t.templateMaterial;

                        if (mgr.propData == null)
                        {
                            mgr.propData = MicroSplatShaderGUI.FindOrCreatePropTex(mgr.templateMaterial);
                        }
                    }


                    Selection.SetActiveObjectWithContext(config, config);
                    t.keywordSO = MicroSplatUtilities.FindOrCreateKeywords(t.templateMaterial);

                    t.keywordSO.keywords.Clear();
                    t.keywordSO.keywords = new List <string> (keywords);

                    // force recompile, so that basemap shader name gets reset correctly..
                    MicroSplatShaderGUI.MicroSplatCompiler comp = new MicroSplatShaderGUI.MicroSplatCompiler();
                    comp.Compile(t.templateMaterial);

                    MicroSplatTerrain.SyncAll();

                    // trun on draw instanced if enabled and tessellation is disabled, unless render loop is LWRP/URP in which case it does work..
#if UNITY_2018_3_OR_NEWER
                    if (t.keywordSO != null && (!t.keywordSO.IsKeywordEnabled("_TESSDISTANCE") || t.keywordSO.IsKeywordEnabled("_MSRENDERLOOP_UNITYLD")))
                    {
                        for (int i = 0; i < terrains.Count; ++i)
                        {
                            var nt  = terrains [i];
                            var mgr = nt.GetComponent <MicroSplatTerrain> ();
                            if (mgr != null && mgr.keywordSO != null && !mgr.keywordSO.IsKeywordEnabled("_MSRENDERLOOP_UNITYLD"))
                            {
                                nt.drawInstanced = true;
                            }
                        }
                    }
#endif
                    return(true);
                }
            }
        }
        return(false);
    }