예제 #1
0
    public static void GenerateTerrainBlendData(MicroSplatTerrain bt)
    {
        Terrain t = bt.GetComponent <Terrain>();
        int     w = t.terrainData.heightmapResolution;
        int     h = t.terrainData.heightmapResolution;

        Texture2D data = new Texture2D(w, h, TextureFormat.RGBAHalf, true, true);

        for (int x = 0; x < w; ++x)
        {
            for (int y = 0; y < h; ++y)
            {
                float   height = t.terrainData.GetHeight(x, y);
                Vector3 normal = t.terrainData.GetInterpolatedNormal((float)x / w, (float)y / h);
                // When you save a texture to EXR format, either in the saving or import stage,
                // some type of gamma curve is applied regardless of the fact that the textures is
                // set to linear. So we pow it here to counteract it, whis is total BS, but works..
                normal.x = (normal.x >= 0) ? Mathf.Pow(normal.x, 2.0f) : Mathf.Pow(normal.x, 2) * -1;
                normal.z = (normal.z >= 0) ? Mathf.Pow(normal.z, 2.0f) : Mathf.Pow(normal.z, 2) * -1;
                data.SetPixel(x, y, new Color(normal.x, normal.y, normal.z, height));
            }
        }
        data.Apply();

        var path = MicroSplatUtilities.RelativePathFromAsset(t.terrainData);

        path += "/" + t.name + ".exr";
        var bytes = data.EncodeToEXR(Texture2D.EXRFlags.OutputAsFloat);

        System.IO.File.WriteAllBytes(path, bytes);
        GameObject.DestroyImmediate(data);
        AssetDatabase.Refresh();
        bt.terrainDesc = AssetDatabase.LoadAssetAtPath <Texture2D>(path);
        var ai = AssetImporter.GetAtPath(path);
        var ti = ai as TextureImporter;
        var ps = ti.GetDefaultPlatformTextureSettings();

        if (ti.isReadable == true ||
            ti.wrapMode != TextureWrapMode.Clamp ||
            ps.format != TextureImporterFormat.RGBAHalf ||
            ps.textureCompression != TextureImporterCompression.Uncompressed ||
            ps.overridden != true ||
            ti.filterMode != FilterMode.Bilinear ||
            ti.sRGBTexture != false)
        {
            ti.sRGBTexture        = false;
            ti.filterMode         = FilterMode.Bilinear;
            ti.mipmapEnabled      = true;
            ti.wrapMode           = TextureWrapMode.Clamp;
            ti.isReadable         = false;
            ps.format             = TextureImporterFormat.RGBAHalf;
            ps.textureCompression = TextureImporterCompression.Uncompressed;
            ps.overridden         = true;
            ti.SetPlatformTextureSettings(ps);
            ti.SaveAndReimport();
        }
        bt.sTerrainDirty = false;
        EditorUtility.SetDirty(bt);
        MicroSplatTerrain.SyncAll();
    }
예제 #2
0
    void Bake(MicroSplatTerrain mst)
    {
        // for each pass
        int pass = 1;

        while (pass <= (int)(BakingPasses.Emissive))
        {
            BakingPasses p = (BakingPasses)pass;
            pass *= 2;
            if (!IsEnabled(p))
            {
                continue;
            }
            Texture2D worldPos, worldNormal;
            GenerateWorldData(mst.terrain, out worldNormal, out worldPos, (int)res);

            var debugOutput = OutputFromPass(p);
            var tex         = Bake(mst, p, (int)res, worldPos, worldNormal);
            var bytes       = tex.EncodeToPNG();

            DestroyImmediate(worldPos, worldNormal);
            string texPath = MicroSplatUtilities.RelativePathFromAsset(mst.terrain) + "/" + mst.terrain.name + "_" + debugOutput.ToString();
            System.IO.File.WriteAllBytes(texPath + ".png", bytes);
        }

        AssetDatabase.Refresh();
    }
예제 #3
0
    public void ComputeCavityFlowMap(MicroSplatTerrain bt)
    {
        Terrain   t    = bt.terrain;
        Texture2D data = new Texture2D(t.terrainData.heightmapResolution, t.terrainData.heightmapResolution, TextureFormat.RGBA32, true, true);

        CurvatureMapGenerator.CreateMap(t.terrainData.GetHeights(0, 0, data.width, data.height), data);

        var path = MicroSplatUtilities.RelativePathFromAsset(t.terrainData);

        path += "/" + t.name + "_cavity.png";
        var bytes = data.EncodeToPNG();

        System.IO.File.WriteAllBytes(path, bytes);
        GameObject.DestroyImmediate(data);
        AssetDatabase.Refresh();
        bt.cavityMap = AssetDatabase.LoadAssetAtPath <Texture2D>(path);
        var ai = AssetImporter.GetAtPath(path);
        var ti = ai as TextureImporter;

        if (ti.sRGBTexture != false)
        {
            ti.sRGBTexture = false;
            ti.SaveAndReimport();
        }
        bt.sTerrainDirty = false;
        EditorUtility.SetDirty(bt);
        EditorUtility.SetDirty(t);
        MicroSplatTerrain.SyncAll();
        AssetDatabase.SaveAssets();
    }
예제 #4
0
        public void GenerateAuxShaders(string name, string path, List <string> keywords)
        {
            var exts = new List <FeatureDescriptor> (extensions); // prevent recursive access due to init

            foreach (var e in exts)
            {
                var aux = e.GetAuxShader();
                if (aux != null)
                {
                    if (keywords.Contains(aux.trigger))
                    {
                        var okeys = new List <string> (keywords);

                        // remove all other trigger keywords
                        foreach (var oe in exts)
                        {
                            if (oe != e)
                            {
                                var oaux = oe.GetAuxShader();
                                if (oaux != null)
                                {
                                    okeys.Remove(oaux.trigger);
                                }
                            }
                        }

                        string opath = path.Replace(".shader", aux.extension + ".shader");
                        e.ModifyKeywordsForAuxShader(okeys);
                        var shader = this.Compile(okeys.ToArray(), name, null, aux);
                        MicroSplatUtilities.Checkout(opath);
                        System.IO.File.WriteAllText(opath, shader);
                    }
                }
            }
        }
예제 #5
0
        private static void SetupMicroSplatMaterial(DiggerSystem diggerSystem)
        {
            var microSplat = diggerSystem.Terrain.GetComponent <MicroSplatTerrain>();

            if (!microSplat)
            {
                Debug.LogError($"Could not find MicroSplatTerrain on terrain {diggerSystem.Terrain.name}");
                return;
            }

            var microSplatShader = MicroSplatUtilities.GetDiggerShader(microSplat);

            if (microSplatShader == null)
            {
                Debug.LogError($"Could not find MicroSplat Digger shader");
                return;
            }

            var material = new Material(microSplatShader);

            material.CopyPropertiesFromMaterial(microSplat.matInstance);

            var matPath = Path.Combine(diggerSystem.BasePathData, $"diggerMicroSplat.mat");

            material = EditorUtils.CreateOrReplaceAsset(material, matPath);
            AssetDatabase.ImportAsset(matPath, ImportAssetOptions.ForceUpdate);
            diggerSystem.Materials[0] = material;
        }
예제 #6
0
    public void DoPerPixelNormalGUI()
    {
        MicroSplatTerrain bt = target as MicroSplatTerrain;
        Terrain           t  = bt.GetComponent <Terrain>();

        if (t == null || t.terrainData == null)
        {
            EditorGUILayout.HelpBox("No Terrain data found", MessageType.Error);
            return;
        }
        if (t.materialTemplate == null)
        {
            return;
        }

        if (bt.keywordSO == null)
        {
            return;
        }

        if (bt.terrain.drawInstanced && bt.perPixelNormal != null && !bt.keywordSO.IsKeywordEnabled("_TERRAINBLENDING"))
        {
            EditorGUILayout.HelpBox("Per Pixel Normal is assigned, but shader is using Instance rendering, which automatically provides per-pixel normal. You may turn off per pixel normal if it's on and clear the normal data to save memory.", MessageType.Warning);
            if (bt.perPixelNormal != null && GUILayout.Button("Clear"))
            {
                bt.perPixelNormal = null;
                EditorUtility.SetDirty(bt);
                EditorUtility.SetDirty(bt.terrain);
            }
        }

        MicroSplatUtilities.DrawTextureField(bt, CPerPixelNormal, ref bt.perPixelNormal, "_PERPIXNORMAL", "_TERRAINBLENDING", null, null, false);

        if (bt.perPixelNormal == null &&
            (bt.keywordSO.IsKeywordEnabled("_PERPIXNORMAL") || bt.keywordSO.IsKeywordEnabled("_TERRAINBLENDING")))
        {
            EditorGUILayout.HelpBox("Terrain Normal Data is not present, please generate", MessageType.Warning);
        }

        if (bt.keywordSO.IsKeywordEnabled("_PERPIXNORMAL") || bt.keywordSO.IsKeywordEnabled("_TERRAINBLENDING"))
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PrefixLabel("Normal Data");
            if (GUILayout.Button(bt.perPixelNormal == null ? "Generate" : "Update"))
            {
                GenerateTerrainNormalMap(bt);
                EditorUtility.SetDirty(bt);
                EditorUtility.SetDirty(bt.terrain);
            }

            if (bt.perPixelNormal != null && GUILayout.Button("Clear"))
            {
                bt.perPixelNormal = null;
                EditorUtility.SetDirty(bt);
                EditorUtility.SetDirty(bt.terrain);
            }
            EditorGUILayout.EndHorizontal();
        }
    }
예제 #7
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;
         }
     }
 }
예제 #9
0
    public static void GenerateTerrainNormalMap(MicroSplatTerrain bt)
    {
        Terrain t = bt.GetComponent <Terrain>();
        int     w = t.terrainData.heightmapResolution;
        int     h = t.terrainData.heightmapResolution;

        Texture2D data = new Texture2D(w, h, TextureFormat.RGBA32, true, true);

        for (int x = 0; x < w; ++x)
        {
            for (int y = 0; y < h; ++y)
            {
                Vector3 normal = t.terrainData.GetInterpolatedNormal((float)x / w, (float)y / h);
                data.SetPixel(x, y, new Color(normal.x * 0.5f + 0.5f, normal.z * 0.5f + 0.5f, normal.y));
            }
        }
        data.Apply();

        var path = MicroSplatUtilities.RelativePathFromAsset(t.terrainData);

        path += "/" + t.name + "_normal.png";
        var bytes = data.EncodeToPNG();

        System.IO.File.WriteAllBytes(path, bytes);
        GameObject.DestroyImmediate(data);
        AssetDatabase.Refresh();
        bt.perPixelNormal = AssetDatabase.LoadAssetAtPath <Texture2D>(path);
        var ai = AssetImporter.GetAtPath(path);
        var ti = ai as TextureImporter;
        var ps = ti.GetDefaultPlatformTextureSettings();

        if (ti.isReadable == true ||
            ti.wrapMode != TextureWrapMode.Clamp ||
            ps.overridden != true ||
            ti.textureType != TextureImporterType.NormalMap)

        {
            ti.textureType   = TextureImporterType.NormalMap;
            ti.mipmapEnabled = true;
            ti.wrapMode      = TextureWrapMode.Clamp;
            ti.isReadable    = false;
            ps.overridden    = true;
            ti.SetPlatformTextureSettings(ps);
            ti.SaveAndReimport();
        }
        bt.sTerrainDirty = false;
        EditorUtility.SetDirty(bt);
        EditorUtility.SetDirty(bt.terrain);
        MicroSplatTerrain.SyncAll();
        AssetDatabase.SaveAssets();
    }
    public static Shader NewShader()
    {
        string path = "Assets";

        foreach (UnityEngine.Object obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
        {
            path = AssetDatabase.GetAssetPath(obj);
            if (System.IO.File.Exists(path))
            {
                path = System.IO.Path.GetDirectoryName(path);
            }
            break;
        }
        path = path.Replace("\\", "/");

        path = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplat.shader");
        string name = path.Substring(path.LastIndexOf("/"));

        name = name.Substring(0, name.IndexOf("."));
        name = name.Replace("/", "");

        ;
        string [] keywords = new string [0];
        var       pipeline = MicroSplatUtilities.DetectPipeline();

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


        MicroSplatCompiler compiler = new MicroSplatCompiler();

        compiler.Init();
        string ret = compiler.Compile(keywords, name, null);

        System.IO.File.WriteAllText(path, ret);
        AssetDatabase.Refresh();
        return(AssetDatabase.LoadAssetAtPath <Shader> (path));
    }
    void WeightLimitingGUI(MicroSplatTerrain t)
    {
        if (MicroSplatUtilities.DrawRollup("Weight Limiting", false))
        {
            weightLimit          = EditorGUILayout.IntSlider("Weight Limit", weightLimit, 2, 4);
            multipassWeightLimit = EditorGUILayout.Toggle(CMultipassWeight, multipassWeightLimit);

            if (GUILayout.Button("Limit"))
            {
                WeightLimitTerrain(t, weightLimit, false);
                if (multipassWeightLimit)
                {
                    WeightLimitTerrain(t, weightLimit, 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));
    }
    static void RegenAllShaders()
    {
        var mats = AssetDatabase.FindAssets("t:Material");

        foreach (var m in mats)
        {
            Material mat = AssetDatabase.LoadAssetAtPath <Material> (AssetDatabase.GUIDToAssetPath(m));
            if (mat != null && mat.shader != null)
            {
                if (MicroSplatUtilities.CanFindKeywords(mat))
                {
                    Debug.Log("Regenerating shader " + AssetDatabase.GetAssetPath(mat.shader));
                    MicroSplatShaderGUI.MicroSplatCompiler compiler = new MicroSplatShaderGUI.MicroSplatCompiler();
                    compiler.Compile(mat);
                }
            }
        }
    }
    void ImportExportGUI()
    {
        if (MicroSplatUtilities.DrawRollup("Splat Import/Export", false))
        {
            EditorGUI.BeginChangeCheck();
            serializedObject.Update();
            SerializedProperty prop = serializedObject.FindProperty("importSplatMaps");
            EditorGUILayout.PropertyField(prop, true);
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }

            if (GUILayout.Button("Import"))
            {
                ImportSplatMaps();
            }
            if (GUILayout.Button("Export"))
            {
                ExportSplatMaps();
            }
        }
    }
    public void BakingGUI(MicroSplatTerrain t)
    {
        if (needsBake && Event.current.type == EventType.Repaint)
        {
            needsBake = false;
            Bake(t);
        }
        if (MicroSplatUtilities.DrawRollup("Render Baking", false))
        {
            res = (BakingResolutions)EditorGUILayout.EnumPopup(new GUIContent("Resolution"), res);

         #if UNITY_2017_3_OR_NEWER
            passes = (BakingPasses)EditorGUILayout.EnumFlagsField(new GUIContent("Features"), passes);
         #else
            passes = (BakingPasses)EditorGUILayout.EnumMaskPopup(new GUIContent("Features"), passes);
         #endif

            if (GUILayout.Button("Export Selected"))
            {
                needsBake = 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;
        }
    }
예제 #17
0
    public void BakingGUI(MicroSplatTerrain t)
    {
        if (needsBake && Event.current.type == EventType.Repaint)
        {
            needsBake = false;
            Bake(t);
        }
#if __MICROSPLAT_PROCTEX__
        if (bakeSplats && Event.current.type == EventType.Repaint)
        {
            bakeSplats = false;

            int alphaLayerCount = t.terrain.terrainData.alphamapLayers;
            int splatRes        = t.terrain.terrainData.alphamapResolution;
            int splatCount      = t.terrain.terrainData.terrainLayers.Length;
            float[,,] splats = new float[splatRes, splatRes, splatCount];

            // World/normals are used in texturing, so we have to make them match.
            Texture2D worldPos, worldNormal;
            GenerateWorldData(t.terrain, out worldNormal, out worldPos, splatRes);


            for (int i = 0; i < alphaLayerCount; i = i + 4)
            {
                Texture2D tex   = Texture2D.blackTexture;
                Texture2D alpha = Texture2D.blackTexture;

                if (i == 0)
                {
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput0, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput0A, splatRes, worldPos, worldNormal);
                }
                if (i == 4)
                {
                    DestroyTex(tex);
                    DestroyTex(alpha);
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput1, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput1A, splatRes, worldPos, worldNormal);
                }
                else if (i == 8)
                {
                    DestroyTex(tex);
                    DestroyTex(alpha);
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput2, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput2A, splatRes, worldPos, worldNormal);
                }
                else if (i == 12)
                {
                    DestroyTex(tex);
                    DestroyTex(alpha);
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput3, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput3A, splatRes, worldPos, worldNormal);
                }
                else if (i == 16)
                {
                    DestroyTex(tex);
                    DestroyTex(alpha);
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput4, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput4A, splatRes, worldPos, worldNormal);
                }
                else if (i == 20)
                {
                    DestroyTex(tex);
                    DestroyTex(alpha);
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput5, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput5A, splatRes, worldPos, worldNormal);
                }
                else if (i == 24)
                {
                    DestroyTex(tex);
                    DestroyTex(alpha);
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput6, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput6A, splatRes, worldPos, worldNormal);
                }
                else if (i == 28)
                {
                    DestroyTex(tex);
                    DestroyTex(alpha);
                    tex   = Bake(t, BakingPasses.ProceduralSplatOutput7, splatRes, worldPos, worldNormal);
                    alpha = Bake(t, BakingPasses.ProceduralSplatOutput7A, splatRes, worldPos, worldNormal);
                }

                for (int x = 0; x < splatRes; ++x)
                {
                    for (int y = 0; y < splatRes; ++y)
                    {
                        Color c = tex.GetPixel(x, y);
                        Color a = alpha.GetPixel(x, y);
                        if (i < splatCount)
                        {
                            splats[y, x, i] = c.r;
                        }
                        if (i + 1 < splatCount)
                        {
                            splats[y, x, i + 1] = c.g;
                        }
                        if (i + 2 < splatCount)
                        {
                            splats[y, x, i + 2] = c.b;
                        }
                        if (i + 3 < splatCount)
                        {
                            splats[y, x, i + 3] = a.g;
                        }
                    }
                }
            }
            DestroyImmediate(worldPos);
            DestroyImmediate(worldNormal);
            t.terrain.terrainData.SetAlphamaps(0, 0, splats);
            EditorUtility.SetDirty(t.terrain.terrainData);
        }
#endif

        if (MicroSplatUtilities.DrawRollup("Render Baking", false))
        {
            res = (BakingResolutions)EditorGUILayout.EnumPopup(new GUIContent("Resolution"), res);

         #if UNITY_2017_3_OR_NEWER
            passes = (BakingPasses)EditorGUILayout.EnumFlagsField(new GUIContent("Features"), passes);
         #else
            passes = (BakingPasses)EditorGUILayout.EnumMaskPopup(new GUIContent("Features"), passes);
         #endif

            if (GUILayout.Button("Export Selected"))
            {
                needsBake = true;
            }
        }
#if __MICROSPLAT_PROCTEX__
        if (t.templateMaterial != null && t.keywordSO != null && t.keywordSO.IsKeywordEnabled("_PROCEDURALTEXTURE"))
        {
            if (MicroSplatUtilities.DrawRollup("Procedural Baking", false))
            {
                EditorGUILayout.Space();
                if (GUILayout.Button("Bake Procedural to Terrain"))
                {
                    bakeSplats = true;
                }
                EditorGUILayout.Space();
            }
        }
#endif
        MicroSplatCompressor.DrawGUI(t, compressOptions);
    }
예제 #18
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);
    }
예제 #19
0
    public static void GenerateTerrainBlendData(MicroSplatTerrain bt)
    {
        Terrain t = bt.GetComponent <Terrain>();
        int     w = t.terrainData.heightmapResolution;
        int     h = t.terrainData.heightmapResolution;

        Texture2D data = null;

        if (SystemInfo.SupportsTextureFormat(TextureFormat.RGBAHalf))
        {
            data = new Texture2D(w, h, TextureFormat.RGBAHalf, true, true);
        }
#if UNITY_2018_3_OR_NEWER
        else if (SystemInfo.SupportsTextureFormat(TextureFormat.RGBAFloat))
        {
            data = new Texture2D(w, h, TextureFormat.RGBAFloat, true, true);
        }
#endif
        else
        {
            Debug.LogError("System does not support RGBAHalf or RGBAFloat texture formats, Terrain Descriptor cannot be generated.");
            return;
        }

        for (int x = 0; x < w; ++x)
        {
            for (int y = 0; y < h; ++y)
            {
                float   height = t.terrainData.GetHeight(x, y);
                Vector3 normal = t.terrainData.GetInterpolatedNormal((float)x / w, (float)y / h);
                // When you save a texture to EXR format, either in the saving or import stage,
                // some type of gamma curve is applied regardless of the fact that the textures is
                // set to linear. So we pow it here to counteract it, whis is total BS, but works..
                normal.x = (normal.x >= 0) ? Mathf.Pow(normal.x, 2.0f) : Mathf.Pow(normal.x, 2) * -1;
                normal.z = (normal.z >= 0) ? Mathf.Pow(normal.z, 2.0f) : Mathf.Pow(normal.z, 2) * -1;
                data.SetPixel(x, y, new Color(normal.x, normal.y, normal.z, height));
            }
        }
        data.Apply();

        var path = MicroSplatUtilities.RelativePathFromAsset(t.terrainData);
        path += "/" + t.name + ".exr";
        var bytes = data.EncodeToEXR(Texture2D.EXRFlags.OutputAsFloat);
        System.IO.File.WriteAllBytes(path, bytes);
        GameObject.DestroyImmediate(data);
        AssetDatabase.Refresh();
        bt.terrainDesc = AssetDatabase.LoadAssetAtPath <Texture2D>(path);
        var ai = AssetImporter.GetAtPath(path);
        var ti = ai as TextureImporter;


        // default platform no longer supports RGBA half/float in newer unity, so we override all platforms
        bool changed   = false;
        var  platforms = System.Enum.GetNames(typeof(BuildTarget));
        for (int i = 0; i < platforms.Length; ++i)
        {
            string platform = platforms [i];
            var    ps       = ti.GetPlatformTextureSettings(platform);

            if (ti.isReadable == true ||
                ti.wrapMode != TextureWrapMode.Clamp ||
#if UNITY_2018_3_OR_NEWER
                (ps.format != TextureImporterFormat.RGBAHalf && ps.format != TextureImporterFormat.RGBAFloat) ||
#else
                ps.format != TextureImporterFormat.RGBAHalf ||
#endif
                ps.textureCompression != TextureImporterCompression.Uncompressed ||
                ps.overridden != true ||
                ti.filterMode != FilterMode.Bilinear ||
                ti.sRGBTexture != false)
            {
                ti.sRGBTexture   = false;
                ti.filterMode    = FilterMode.Bilinear;
                ti.mipmapEnabled = true;
                ti.wrapMode      = TextureWrapMode.Clamp;
                ti.isReadable    = false;

#if UNITY_2018_3_OR_NEWER
                if (SystemInfo.SupportsTextureFormat(TextureFormat.RGBAHalf))
                {
                    ps.format = TextureImporterFormat.RGBAHalf;
                }
                else
                {
                    ps.format = TextureImporterFormat.RGBAFloat;
                }
#else
                ps.format = TextureImporterFormat.RGBAHalf;
#endif
                ps.textureCompression = TextureImporterCompression.Uncompressed;
                ps.overridden         = true;
                try
                {
                    ti.SetPlatformTextureSettings(ps);
                    changed = true;
                }
                catch
                {
                }
            }
        }
        if (changed)
        {
            ti.SaveAndReimport();
        }
        bt.sTerrainDirty = false;
        EditorUtility.SetDirty(bt);
        EditorUtility.SetDirty(bt.terrain);
        MicroSplatTerrain.SyncAll();
        AssetDatabase.SaveAssets();
    }
예제 #20
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);
        }
    }
   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;
   }
예제 #22
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();
        }
예제 #23
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 void BakingGUI(MicroSplatTerrain t)
   {
      if (needsBake && Event.current.type == EventType.Repaint)
      {
         needsBake = false;
         Bake(t);
      }
#if __MICROSPLAT_PROCTEX__


      if (bakeSplats && Event.current.type == EventType.Repaint)
      {
         bakeSplats = false;
         
         int alphaLayerCount = t.terrain.terrainData.alphamapLayers;
         int splatRes = t.terrain.terrainData.alphamapResolution;
      #if UNITY_2019_3_OR_NEWER
         int splatCount = t.terrain.terrainData.terrainLayers.Length;
      #else
         int splatCount = t.terrain.terrainData.splatPrototypes.Length;
      #endif
         float[,,] splats = new float[splatRes, splatRes, splatCount];

         // World/normals are used in texturing, so we have to make them match.
         Texture2D worldPos = new Texture2D(splatRes, splatRes, TextureFormat.RGBAFloat, true, true);
         Texture2D worldNormal = new Texture2D(splatRes, splatRes, TextureFormat.RGBAFloat, true, true);
         t.terrain.transform.rotation = Quaternion.identity;
         for (int x = 0; x < splatRes; ++x)
         {
            float u = (float)x / (float)splatRes;
            for (int y = 0; y < splatRes; ++y)
            {
               float v = (float)y / (float)splatRes;
               float h = t.terrain.terrainData.GetInterpolatedHeight(u, v);
               Vector3 n = t.terrain.terrainData.GetInterpolatedNormal(u, v);

               Vector3 wp = t.terrain.transform.localToWorldMatrix.MultiplyPoint(new Vector3(u * t.terrain.terrainData.size.x, h, v * t.terrain.terrainData.size.z));
               worldPos.SetPixel(x, y, new Color(wp.x, wp.y, wp.z));
               worldNormal.SetPixel(x, y, new Color(n.x, n.y, n.z));
            }
         }
         worldPos.Apply();
         worldNormal.Apply();

         for (int i = 0; i < alphaLayerCount; i=i+4)
         {
            Texture2D tex = Texture2D.blackTexture;
            Texture2D alpha = Texture2D.blackTexture;

            if (i == 0)
            {
               tex = Bake(t, BakingPasses.ProceduralSplatOutput0, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput0A, splatRes, worldPos, worldNormal);
            }
            if (i == 4)
            {
               DestroyImmediate(tex);
               DestroyImmediate(alpha);
               tex = Bake(t, BakingPasses.ProceduralSplatOutput1, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput1A, splatRes, worldPos, worldNormal);
            }
            else if (i == 8)
            {
               DestroyImmediate(tex);
               DestroyImmediate(alpha);
               tex = Bake(t, BakingPasses.ProceduralSplatOutput2, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput2A, splatRes, worldPos, worldNormal);
            }
            else if (i == 12)
            {
               DestroyImmediate(tex);
               DestroyImmediate(alpha);
               tex = Bake(t, BakingPasses.ProceduralSplatOutput3, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput3A, splatRes, worldPos, worldNormal);
            }
            else if (i == 16)
            {
               DestroyImmediate(tex);
               DestroyImmediate(alpha);
               tex = Bake(t, BakingPasses.ProceduralSplatOutput4, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput4A, splatRes, worldPos, worldNormal);
            }
            else if (i == 20)
            {
               DestroyImmediate(tex);
               DestroyImmediate(alpha);
               tex = Bake(t, BakingPasses.ProceduralSplatOutput5, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput5A, splatRes, worldPos, worldNormal);
            }
            else if (i == 24)
            {
               DestroyImmediate(tex);
               DestroyImmediate(alpha);
               tex = Bake(t, BakingPasses.ProceduralSplatOutput6, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput6A, splatRes, worldPos, worldNormal);
            }
            else if (i == 28)
            {
               DestroyImmediate(tex);
               DestroyImmediate(alpha);
               tex = Bake(t, BakingPasses.ProceduralSplatOutput7, splatRes, worldPos, worldNormal);
               alpha = Bake(t, BakingPasses.ProceduralSplatOutput7A, splatRes, worldPos, worldNormal);
            }

            for (int x = 0; x < splatRes; ++x)
            {
               for (int y = 0; y < splatRes; ++y)
               {
                  Color c = tex.GetPixel(x, y);
                  Color a = alpha.GetPixel(x, y);
                  if (i < splatCount)
                  {
                     splats[y, x, i] = c.r;
                  }
                  if (i + 1 < splatCount)
                  {
                     splats[y, x, i + 1] = c.g;
                  }
                  if (i + 2 < splatCount)
                  {
                     splats[y, x, i + 2] = c.b;
                  }
                  if (i + 3 < splatCount)
                  {
                     splats[y, x, i + 3] = a.g;
                  }
               }
            }
         }
         DestroyImmediate(worldPos);
         DestroyImmediate(worldNormal);
         t.terrain.terrainData.SetAlphamaps(0, 0, splats);
         EditorUtility.SetDirty(t.terrain.terrainData);

      }
#endif

      if (MicroSplatUtilities.DrawRollup("Render Baking", false))
      {
         res = (BakingResolutions)EditorGUILayout.EnumPopup(new GUIContent("Resolution"), res);

         #if UNITY_2017_3_OR_NEWER
            passes = (BakingPasses)EditorGUILayout.EnumFlagsField(new GUIContent("Features"), passes);
         #else
            passes = (BakingPasses)EditorGUILayout.EnumMaskPopup(new GUIContent("Features"), passes);
         #endif

         if (GUILayout.Button("Export Selected"))
         {
            needsBake = true;
         }

#if __MICROSPLAT_PROCTEX__
         if (t.templateMaterial != null && t.keywordSO != null && t.keywordSO.IsKeywordEnabled("_PROCEDURALTEXTURE"))
         {
            EditorGUILayout.Space();
            EditorGUILayout.Space();
            if (GUILayout.Button("Bake Procedural to Terrain"))
            {
               bakeSplats = true;
            }
            EditorGUILayout.Space();
            EditorGUILayout.Space();
         }
#endif

      }
   }
예제 #25
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));
            }
        }
    }
    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);
        }
    }
예제 #27
0
    public static Material NewShaderAndMaterial(Terrain t, string [] keywords = null)
    {
        string path = MicroSplatUtilities.RelativePathFromAsset(t.terrainData);

        return(NewShaderAndMaterial(path, t.name, keywords));
    }
예제 #28
0
    //static GUIContent AdvDetailControl = new GUIContent("Advanced Detail Control", "Control map for Advanced Details");

    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 (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);
                }

                // 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);
        }

#if __MICROSPLAT_TERRAINBLEND__ || __MICROSPLAT_STREAMS__
        DoTerrainDescGUI();
#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, geoTexOverride, ref t.geoTextureOverride, "_GEOMAP");

        MicroSplatUtilities.DrawTextureField(t, geoTintOverride, ref t.tintMapOverride, "_GLOBALTINT");

        MicroSplatUtilities.DrawTextureField(t, geoNormalOverride, ref t.globalNormalOverride, "_GLOBALNORMALS");

#if __MICROSPLAT_ADVANCED_DETAIL__
        DrawAdvancedModuleDetailGUI(t);
#endif

        if (t.templateMaterial.IsKeywordEnabled("_VSGRASSMAP"))
        {
            EditorGUI.BeginChangeCheck();

            t.vsGrassMap = EditorGUILayout.ObjectField(CVSGrassMap, t.vsGrassMap, typeof(Texture2D), false) as Texture2D;

            if (EditorGUI.EndChangeCheck())
            {
                EditorUtility.SetDirty(t);
            }
        }

        if (t.templateMaterial.IsKeywordEnabled("_VSSHADOWMAP"))
        {
            EditorGUI.BeginChangeCheck();


            t.vsShadowMap = EditorGUILayout.ObjectField(CVSShadowMap, t.vsShadowMap, typeof(Texture2D), false) as Texture2D;

            if (EditorGUI.EndChangeCheck())
            {
                EditorUtility.SetDirty(t);
            }
        }


        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);

#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;
            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.addPass              = EditorGUILayout.ObjectField("Add Pass", t.addPass, typeof(Shader), false) as Shader;
            EditorGUI.indentLevel -= 2;
        }
        if (EditorGUI.EndChangeCheck())
        {
            EditorUtility.SetDirty(t);
        }
    }
예제 #29
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));
    }
예제 #30
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;
        }
    }