public static void DrawTextureField(MicroSplatObject t, GUIContent content, ref Texture2D tex,
                                            string keyword, string keyword2 = null, string keyword3 = null, string keyword4 = null, bool allKeywordsRequired = true)
        {
            if (allKeywordsRequired)
            {
                if (keyword != null && !t.keywordSO.IsKeywordEnabled(keyword))
                {
                    return;
                }
                if (keyword2 != null && !t.keywordSO.IsKeywordEnabled(keyword2))
                {
                    return;
                }
                if (keyword3 != null && !t.keywordSO.IsKeywordEnabled(keyword3))
                {
                    return;
                }
                if (keyword4 != null && !t.keywordSO.IsKeywordEnabled(keyword4))
                {
                    return;
                }
            }
            else
            {
                bool pass = false;
                if (keyword != null && t.keywordSO.IsKeywordEnabled(keyword))
                {
                    pass = true;
                }
                if (keyword2 != null && t.keywordSO.IsKeywordEnabled(keyword2))
                {
                    pass = true;
                }
                if (keyword3 != null && t.keywordSO.IsKeywordEnabled(keyword3))
                {
                    pass = true;
                }
                if (keyword4 != null && t.keywordSO.IsKeywordEnabled(keyword4))
                {
                    pass = true;
                }
                if (!pass)
                {
                    return;
                }
            }

            EditorGUI.BeginChangeCheck();

            Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(18));

            r.width -= 18; // shrik for boxed contents.. which unity doesn't seem to handle right..
            tex      = EditorGUI.ObjectField(r, content, tex, typeof(Texture2D), false) as Texture2D;

            if (EditorGUI.EndChangeCheck())
            {
                EditorUtility.SetDirty(t);
                MicroSplatObject.SyncAll();
            }
        }
Exemplo n.º 2
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();
        }
        public static void DrawGUI(MicroSplatObject mso, Options o)
        {
            if (MicroSplatUtilities.DrawRollup("Compressor", false))
            {
                EditorGUILayout.HelpBox("You can use this section to automatically covert various maps to compressed formats before a build. Please note, that once compressed, external files will be used for things like the terrain splat maps, and changing the terrain through Unity's tools will have no effect", MessageType.Info);
                EditorGUILayout.LabelField("Compression Options");

                o.splatMaps = EditorGUILayout.Toggle(CCompSplatMaps, o.splatMaps);
                if (o.splatMaps)
                {
                    EditorGUILayout.HelpBox("This will remove the terrain painting from your terrain file to save memory! The Uncompress button will restore this from the output textures, but if you delete or unhook them your painting may be lost.", MessageType.Error);
                }
                o.streamMaps = EditorGUILayout.Toggle(CCompStreamMap, o.streamMaps);
                o.snowMask   = EditorGUILayout.Toggle(CCompSnowMaps, o.snowMask);
                o.biomeMask  = EditorGUILayout.Toggle(CCompBiomeMaps, o.biomeMask);
                o.tintMap    = EditorGUILayout.Toggle(CCompTintMaps, o.tintMap);

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.Space();
                if (GUILayout.Button("Compress"))
                {
                    MicroSplatCompressor comp = new MicroSplatCompressor();
                    comp.Compress(mso, o);
                }
                if (GUILayout.Button("Uncompress"))
                {
                    MicroSplatCompressor comp = new MicroSplatCompressor();
                    comp.Revert(mso);
                }
                EditorGUILayout.Space();
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.Space();
                if (GUILayout.Button("Compress Scene"))
                {
                    MicroSplatCompressor comp = new MicroSplatCompressor();
                    MicroSplatObject []  objs = GameObject.FindObjectsOfType <MicroSplatObject> ();
                    foreach (var obj in objs)
                    {
                        comp.Compress(obj, o);
                    }
                }
                if (GUILayout.Button("Uncompress Scene"))
                {
                    MicroSplatCompressor comp = new MicroSplatCompressor();
                    MicroSplatObject []  objs = GameObject.FindObjectsOfType <MicroSplatObject> ();
                    foreach (var obj in objs)
                    {
                        comp.Revert(obj);
                    }
                }
                EditorGUILayout.Space();
                EditorGUILayout.EndHorizontal();
            }
        }
Exemplo n.º 4
0
    static Vector2 WorldToTerrain(MicroSplatObject ter, Vector3 point, int width, int height)
    {
        Bounds b = ter.GetBounds();

        point = ter.transform.worldToLocalMatrix.MultiplyPoint(point);
        float x = (point.x / b.size.x) * width;
        float z = (point.z / b.size.z) * height;

        return(new Vector2(x, z));
    }
        public void Revert(MicroSplatObject mso)
        {
            MicroSplatTerrain t = mso as MicroSplatTerrain;

            if (t != null)
            {
                if (t.templateMaterial == null)
                {
                    Debug.LogError("MicroSplatTerrain " + mso.gameObject.name + " does not have template material");
                }
                else
                {
                    RevertTerrainSplats(t);
                }
            }

#if __MICROSPLAT_MESH__
            MicroSplatMesh msm = mso as MicroSplatMesh;
            if (msm != null)
            {
                foreach (var subMesh in msm.subMeshEntries)
                {
                    foreach (var tex in subMesh.subMeshOverride.controlTextures)
                    {
                        UncompressTexture(tex);
                    }
                }
            }
#endif

#if __MICROSPLAT_PROCTEX__
            UncompressTexture(mso.procBiomeMask);
            UncompressTexture(mso.procBiomeMask2);
            UncompressTexture(mso.templateMaterial, "_ProcTexBiomeMask");
            UncompressTexture(mso.templateMaterial, "_ProcTexBiomeMask2");
#endif
#if __MICROSPLAT_SNOW__
            UncompressTexture(mso.snowMaskOverride);
            UncompressTexture(mso.templateMaterial, "_SnowMask");
#endif
#if __MICROSPLAT_STREAMS__
            UncompressTexture(mso.streamTexture);
            UncompressTexture(mso.templateMaterial, "_StreamControl");
#endif
#if __MICROSPLAT_GLOBALTEXTURE__
            UncompressTexture(mso.streamTexture);
            UncompressTexture(mso.templateMaterial, "_GlobalTintTex");
#endif
        }
        bool VerifyData()
        {
            if (rawTerrains == null || rawTerrains.Count == 0)
            {
                return(false);
            }

            for (int i = 0; i < rawTerrains.Count; ++i)
            {
                Terrain          t   = rawTerrains [i];
                MicroSplatObject mso = t.GetComponent <MicroSplatObject> ();
                if (t.materialTemplate == null || mso == null || !mso.keywordSO.IsKeywordEnabled("_MICROSPLAT"))
                {
                    EditorGUILayout.HelpBox("Terrain(s) are not setup for MicroSplat, please set them up", MessageType.Error);
                    return(false);
                }
            }
            return(true);
        }
    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;
        }
    }
Exemplo n.º 8
0
    public override void OnInspectorGUI()
    {
        StreamManager sm = target as StreamManager;

        MicroSplatObject mso = sm.GetComponent <MicroSplatObject>();


        if (mso == null)
        {
            EditorGUILayout.HelpBox("Must be on a MicroSplatObject (terrain, mesh terrain, etc)", MessageType.Error);
            return;
        }
        if (mso.keywordSO == null)
        {
            EditorGUILayout.HelpBox("MicroSplat Terrain is missing keywords", MessageType.Error);
            return;
        }
        if (!mso.keywordSO.IsKeywordEnabled("_DYNAMICFLOWS"))
        {
            EditorGUILayout.HelpBox("Must have Dynamic Flows ON in your terrain material", MessageType.Error);
            return;
        }

        EditorGUI.BeginChangeCheck();
        if (MicroSplatUtilities.DrawRollup("Streams", true, false))
        {
            sm.strength.x         = EditorGUILayout.Slider(CStrength, sm.strength.x, 0, 1);
            sm.evaporation.x      = EditorGUILayout.Slider(CEvaporation, sm.evaporation.x, 0, 0.5f);
            sm.speed.x            = EditorGUILayout.Slider(CSpeed, sm.speed.x, 0, 10);
            sm.resistance.x       = EditorGUILayout.Slider(CResistance, sm.resistance.x, 0.005f, 0.75f);
            sm.wetnessEvaporation = EditorGUILayout.Slider(CWetnessEvap, sm.wetnessEvaporation, 0.0f, 0.5f);
            if (Application.isPlaying)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Space(5);
                if (GUILayout.Button("Save State"))
                {
                    SaveStream(sm);
                }
                GUILayout.Space(5);
                GUILayout.EndHorizontal();
            }
        }

        if (MicroSplatUtilities.DrawRollup("Lava", true, false))
        {
            sm.strength.y      = EditorGUILayout.Slider(CStrength, sm.strength.y, 0, 1);
            sm.evaporation.y   = EditorGUILayout.Slider(CEvaporation, sm.evaporation.y, 0, 0.5f);
            sm.speed.y         = EditorGUILayout.Slider(CSpeed, sm.speed.y, 0, 10);
            sm.resistance.y    = EditorGUILayout.Slider(CResistance, sm.resistance.y, 0.005f, 0.75f);
            sm.burnEvaporation = EditorGUILayout.Slider(CBurnEvap, sm.burnEvaporation, 0.0f, 0.5f);
            if (Application.isPlaying)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Space(5);
                if (GUILayout.Button("Save State"))
                {
                    SaveLava(sm);
                }
                GUILayout.Space(5);
                GUILayout.EndHorizontal();
            }
        }
        if (EditorGUI.EndChangeCheck())
        {
            EditorUtility.SetDirty(sm);
        }
        if (sm.updateBuffer != null)
        {
            if (sm.updateBuffer.GetCurrent() != null)
            {
                EditorGUILayout.BeginHorizontal();
                GUILayout.Label("Dynamic Buffer");
                int mem = sm.updateBuffer.width * sm.updateBuffer.height * 2;
                mem /= 128;
                EditorGUILayout.LabelField("Buffer Memory: " + mem.ToString() + "kb");
                EditorGUILayout.EndHorizontal();
                GUILayout.Box(sm.updateBuffer.GetCurrent(), GUILayout.Width(256), GUILayout.Height(256));
            }
        }
    }
 private void OnSceneSave(Scene scene)
 {
     MicroSplatObject.SyncAll();
 }
 private static void OnScriptsReloaded()
 {
     MicroSplatObject.SyncAll();
 }
Exemplo n.º 11
0
    public static float GetSnowCoverage(Terrain t, Vector3 worldPos, int maxDistance = 2)
    {
        MicroSplatObject mso = t.GetComponent <MicroSplatTerrain>();

        if (mso != null)
        {
            if (mso.keywordSO.IsKeywordEnabled("_SNOW"))
            {
                var terrainLocalPos = worldPos - t.transform.position;
                var normalizedPos   = new Vector2(Mathf.InverseLerp(0.0f, t.terrainData.size.x, terrainLocalPos.x),
                                                  Mathf.InverseLerp(0.0f, t.terrainData.size.z, terrainLocalPos.z));

                Vector3 worldNormal = t.terrainData.GetInterpolatedNormal(normalizedPos.x, normalizedPos.y);
                float   worldheight = t.terrainData.GetInterpolatedHeight(normalizedPos.x, normalizedPos.y);

                float snowLevel;
                var   mat = mso.templateMaterial;
                float snowMin;
                float snowMax;
                float angleRangeW;
                float angleRangeZ;

                if (mso.keywordSO.IsKeywordEnabled("_USEGLOBALSNOWLEVEL"))
                {
                    snowLevel = Shader.GetGlobalFloat("_Global_SnowLevel");
                }
                else
                {
                    snowLevel = mat.GetFloat("_SnowAmount");
                }

                if (mso.keywordSO.IsKeywordEnabled("_USEGLOBALSNOWHEIGHT"))
                {
                    var g = Shader.GetGlobalVector("_Global_SnowMinMaxHeight");
                    snowMin     = g.x;
                    snowMax     = g.y;
                    angleRangeZ = g.z;
                    angleRangeW = g.w;
                }
                else
                {
                    var g = mat.GetVector("_SnowHeightAngleRange");
                    snowMin     = g.x;
                    snowMax     = g.y;
                    angleRangeZ = g.z;
                    angleRangeW = g.w;
                }

                Vector4 _SnowParams  = mat.GetVector("_SnowParams");
                Vector3 snowUpVector = mat.GetVector("_SnowUpVector");


                float snowDot       = Mathf.Max(snowLevel / 2, Vector3.Dot(worldNormal, snowUpVector));
                float snowDotVertex = snowDot;
                float ao            = 1;
                float oheight       = 0;

                float snowFade = SnowFade(worldheight, snowMin, snowMax, snowDot, snowDotVertex, snowLevel, angleRangeZ, angleRangeW);

                float height  = Mathf.Clamp01(oheight - (1.0f - _SnowParams.x));
                float erosion = Mathf.Clamp01(ao * _SnowParams.y);
                erosion *= erosion;
                float snowMask = Mathf.Clamp01(snowFade - erosion - height);
                snowMask = snowMask * snowMask * snowMask;
                float snowAmount = snowMask * Mathf.Clamp01(snowDot - (height + erosion) * 0.5f); // up
                snowAmount = Mathf.Clamp01(snowAmount * 8);


                return(snowAmount);
            }
        }

        return(0);
    }
Exemplo n.º 12
0
    public void Sync()
    {
      #if UNITY_EDITOR
        // If we have a terrain, we might be moved over another terrain. So lets see if we're in the bounds of our current terrain
        // and if not, clear it and try to get a new one..
        bool testForNewTerrain = false;
        if (msObject != null)
        {
            var tbounds = TransformBounds(msObject.GetBounds());

            Renderer rend = GetComponent <Renderer>();
            if (!tbounds.Intersects(rend.bounds))
            {
                testForNewTerrain = true;
            }
        }
        if (msObject == null || testForNewTerrain)
        {
            RaycastHit[] hits = Physics.RaycastAll(this.transform.position + Vector3.up * 100, Vector3.down, 500);
            for (int i = 0; i < hits.Length; ++i)
            {
                var h = hits[i];
                var t = h.collider.GetComponent <Terrain>();
                if (t != null)
                {
                    var nt = t.GetComponent <MicroSplatTerrain>();
                    if (nt != null)
                    {
                        msObject = nt;
                        break;
                    }
                }
#if __MICROSPLAT_MESH__
                var m = h.collider.GetComponent <MicroSplatMesh>();
                if (m != null)
                {
                    msObject = m;
                    break;
                }
#endif
            }
        }
      #endif

        Material bmInstance = msObject.GetBlendMatInstance();
        if (msObject == null && bmInstance)
        {
            return;
        }

        Renderer r           = GetComponent <Renderer>();
        var      materials   = r.sharedMaterials;
        bool     hasBlendMat = false;
        for (int i = 0; i < materials.Length; ++i)
        {
            if (materials[i] == bmInstance && bmInstance != null)
            {
                hasBlendMat = true;
            }
            else if (materials[i] == null || materials[i].IsKeywordEnabled("_TERRAINBLENDING"))
            {
                hasBlendMat       = true;
                materials[i]      = bmInstance;
                r.sharedMaterials = materials;
            }
        }
        if (!hasBlendMat)
        {
            System.Array.Resize <Material>(ref materials, materials.Length + 1);
            materials[materials.Length - 1] = bmInstance;
            r.sharedMaterials = materials;
        }

        if (props == null)
        {
            props = new MaterialPropertyBlock();
        }


        props.Clear();


        props.SetVector("_TerrainBlendParams", new Vector4(blendDistance, blendContrast, msObject.transform.position.y, blendCurve));
        props.SetVector("_SlopeBlendParams", new Vector4(slopeFilter, slopeContrast, slopeNoise, normalBlendDistance));
        props.SetVector("_SnowBlendParams", new Vector4(snowWidth, 0, 0, 0));
        props.SetVector("_FeatureFilters", new Vector4(doTerrainBlend ? 0.0f : 1.0f, doSnow ? 0.0f : 1.0f, 0, 0));

        if (normalFromObject != null)
        {
            props.SetTexture("_NormalOriginal", normalFromObject);
        }

        r.SetPropertyBlock(props);
    }
Exemplo n.º 13
0
 void Awake()
 {
     msObject = GetComponent <MicroSplatObject>();
 }
        void DrawScatterGUI()
        {
            if (MicroSplatUtilities.DrawRollup("Brush Settings"))
            {
                brushSize    = EditorGUILayout.Slider("Brush Size", brushSize, 0.01f, 30.0f);
                brushFlow    = EditorGUILayout.Slider("Brush Flow", brushFlow, 0.1f, 128.0f);
                brushFalloff = EditorGUILayout.Slider("Brush Falloff", brushFalloff, 0.1f, 3.5f);


                Material tempMat = null;
                for (int i = 0; i < rawTerrains.Count; ++i)
                {
                    Terrain           t   = rawTerrains [i];
                    MicroSplatTerrain mst = t.GetComponent <MicroSplatTerrain> ();
                    if (mst != null)
                    {
                        if (mst.templateMaterial != null && mst.templateMaterial.HasProperty("_ScatterDiffuse"))
                        {
                            Texture2DArray diff = mst.templateMaterial.GetTexture("_ScatterDiffuse") as Texture2DArray;
                            scatterIndex = MicroSplatUtilities.DrawTextureSelector(scatterIndex, diff, false);
                            tempMat      = mst.templateMaterial;
                        }
                        else
                        {
                            scatterIndex = EditorGUILayout.IntField("Scatter Index", scatterIndex);
                        }
                    }
                    else
                    {
                        scatterIndex = EditorGUILayout.IntField("Scatter Index", scatterIndex);
                    }
                }


                //EditorGUILayout.MinMaxSlider (CSlopeRange, ref slopeRange.x, ref slopeRange.y, 0.0f, 1.0f);

                paintValue = EditorGUILayout.Slider("Target Opacity", paintValue, 0.0f, 1.0f);



#if __MICROSPLAT_SCATTER__
                if (tempMat != null)
                {
                    scatterLayer = (ScatterLayer)EditorGUILayout.EnumPopup(CScatterLayer, scatterLayer);
                    EditorGUILayout.Separator();

                    using (new GUILayout.VerticalScope(GUI.skin.box))
                    {
                        EditorGUI.BeginChangeCheck();
                        EditorGUILayout.LabelField("Per Texture Properties");
                        bool changed = MicroSplatScatter.DrawPerTexExternal(tempMat, scatterIndex);
                        EditorGUILayout.Separator();
                        // sync compile changes
                        if (changed)
                        {
                            MicroSplatShaderGUI.MicroSplatCompiler comp = new MicroSplatShaderGUI.MicroSplatCompiler();
                            comp.Init();
                            comp.Compile(tempMat);
                        }
                        // sync property changes
                        if (EditorGUI.EndChangeCheck())
                        {
                            MicroSplatObject.SyncAll();
                        }
                    }
                }
#endif
                GUILayout.Box("", new GUILayoutOption [] { GUILayout.ExpandWidth(true), GUILayout.Height(1) });
                EditorGUILayout.Separator();
            }
            DrawFillGUI();
        }
        public void Compress(MicroSplatObject mso, Options opt)
        {
            MicroSplatTerrain t = mso as MicroSplatTerrain;

            if (t != null)
            {
                if (t.templateMaterial == null)
                {
                    Debug.LogError("MicroSplatTerrain " + mso.gameObject.name + " does not have template material");
                }
                else
                {
                    if (opt.splatMaps)
                    {
                        CompressTerrainSplats(t);
                    }
                }
            }

#if __MICROSPLAT_MESH__
            MicroSplatMesh msm = mso as MicroSplatMesh;
            if (msm != null)
            {
                foreach (var subMesh in msm.subMeshEntries)
                {
                    foreach (var tex in subMesh.subMeshOverride.controlTextures)
                    {
                        CompressTexture(tex, false);
                    }
                }
            }
#endif

#if __MICROSPLAT_PROCTEX__
            if (opt.biomeMask)
            {
                CompressTexture(mso.procBiomeMask, false);
                CompressTexture(mso.procBiomeMask2, false);
                CompressTexture(mso.templateMaterial, "_ProcTexBiomeMask", false);
                CompressTexture(mso.templateMaterial, "_ProcTexBiomeMask2", false);
            }
#endif
#if __MICROSPLAT_SNOW__
            if (opt.snowMask)
            {
                CompressTexture(mso.snowMaskOverride, false);
                CompressTexture(mso.templateMaterial, "_SnowMask", false);
            }
#endif
#if __MICROSPLAT_STREAMS__
            if (opt.streamMaps)
            {
                CompressTexture(mso.streamTexture, false);
                CompressTexture(mso.templateMaterial, "_StreamControl", false);
            }
#endif
#if __MICROSPLAT_GLOBALTEXTURE__
            if (opt.tintMap)
            {
                CompressTexture(mso.streamTexture, true);
                CompressTexture(mso.templateMaterial, "_GlobalTintTex", true);
            }
#endif
        }
Exemplo n.º 16
0
    public void Sync()
    {
#if UNITY_EDITOR
        // If we have a terrain, we might be moved over another terrain. So lets see if we're in the bounds of our current terrain
        // and if not, clear it and try to get a new one..

        bool testForNewTerrain = false;



        // check bounds of existing terrain
        if (msObject != null && testForNewTerrain)
        {
            var tbounds = TransformBounds(msObject.GetBounds());

            Renderer rend = GetComponent <Renderer>();
            if (!tbounds.Intersects(rend.bounds))
            {
                testForNewTerrain = true;
            }
        }

        // see if we have override, if we do, skip terrain testing
        if (msOverrideObject != null)
        {
            if (msOverrideObject is MicroSplatTerrain
#if __MICROSPLAT_MESHTERRAIN__
                || msOverrideObject is MicroSplatMeshTerrain
#endif
                )
            {
                msObject          = msOverrideObject;
                testForNewTerrain = false;
            }
        }

        if (testForNewTerrain)
        {
            RaycastHit[] hits = Physics.RaycastAll(this.transform.position + Vector3.up * 100, Vector3.down, 500);
            for (int i = 0; i < hits.Length; ++i)
            {
                var h = hits[i];
                var t = h.collider.GetComponent <Terrain>();
                if (t != null)
                {
                    var nt = t.GetComponent <MicroSplatTerrain>();
                    if (nt != null)
                    {
                        msObject = nt;
                        break;
                    }
                }
            }
#if __MICROSPLAT_MESHTERRAIN__
            if (msObject == null)
            {
                for (int i = 0; i < hits.Length; ++i)
                {
                    var h = hits [i];
                    var m = h.collider.GetComponent <MicroSplatMeshTerrain> ();
                    if (m != null)
                    {
                        msObject = m;
                        break;
                    }
                    if (h.collider.transform.parent != null)
                    {
                        m = h.collider.transform.parent.GetComponent <MicroSplatMeshTerrain> ();
                        if (m != null)
                        {
                            msObject = m;
                            break;
                        }
                    }
                }
            }
#endif //__MICROSPLAT_MESHTERRAIN__
        }
#endif //UNITY_EDITOR
        if (msObject == null)
        {
            Debug.LogWarning("Terrain Blending: No Terrain Found");
            return;
        }
        Material bmInstance = msObject.GetBlendMatInstance();
        if (bmInstance == null)
        {
            Debug.LogWarning("Terrain Blending: No blend instance found from " + msObject.name);
            return;
        }

        Renderer r           = GetComponent <Renderer>();
        var      materials   = r.sharedMaterials;
        bool     hasBlendMat = false;
        for (int i = 0; i < materials.Length; ++i)
        {
            if (materials[i] == bmInstance && bmInstance != null)
            {
                hasBlendMat = true;
            }
            else if (materials[i] == null || materials[i].shader == null || materials[i].shader.name.Contains("_TerrainObjectBlend"))
            {
                hasBlendMat       = true;
                materials[i]      = bmInstance;
                r.sharedMaterials = materials;
            }
        }
        if (!hasBlendMat)
        {
            System.Array.Resize <Material>(ref materials, materials.Length + 1);
            materials[materials.Length - 1] = bmInstance;
            r.sharedMaterials = materials;
        }

        if (props == null)
        {
            props = new MaterialPropertyBlock();
        }


        props.Clear();

        props.SetVector("_TerrainBlendParams", new Vector4(blendDistance, blendContrast, msObject.transform.position.y, blendCurve));
        props.SetVector("_SlopeBlendParams", new Vector4(slopeFilter, slopeContrast, slopeNoise, normalBlendDistance));
        props.SetVector("_SnowBlendParams", new Vector4(snowWidth, 0, 0, 0));
        props.SetFloat("_TBNoiseScale", noiseScale);
        props.SetVector("_FeatureFilters", new Vector4(doTerrainBlend ? 0.0f : 1.0f, doSnow ? 0.0f : 1.0f, 0, 0));

        if (normalFromObject != null)
        {
            props.SetTexture("_NormalOriginal", normalFromObject);
        }
        r.SetPropertyBlock(props);
    }
    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 (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");

        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 (!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;
        }
    }
Exemplo n.º 18
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();
        }
    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);
        }
    }