static Material SetupMaterial(MicroSplatKeywords kwds, Material mat, MicroSplatBaseFeatures.DebugOutput debugOutput, bool useDebugTopo) { MicroSplatShaderGUI.MicroSplatCompiler comp = new MicroSplatShaderGUI.MicroSplatCompiler(); List<string> keywords = new List<string>(kwds.keywords); RemoveKeyword(keywords, "_SNOW"); RemoveKeyword(keywords, "_TESSDISTANCE"); RemoveKeyword(keywords, "_WINDPARTICULATE"); RemoveKeyword(keywords, "_SNOWPARTICULATE"); RemoveKeyword(keywords, "_GLITTER"); RemoveKeyword(keywords, "_SNOWGLITTER"); keywords.Add(FeatureFromOutput(debugOutput).ToString()); if (useDebugTopo) { keywords.Add("_DEBUG_USE_TOPOLOGY"); } string shader = comp.Compile(keywords.ToArray(), "RenderBake_" + debugOutput.ToString()); Shader s = ShaderUtil.CreateShaderAsset(shader); Material renderMat = new Material(mat); renderMat.shader = s; return renderMat; }
void RevertTerrainSplats(MicroSplatTerrain t) { MicroSplatKeywords keywords = MicroSplatUtilities.FindOrCreateKeywords(t.templateMaterial); if (keywords.IsKeywordEnabled("_CUSTOMSPLATTEXTURES")) { if (t.customControl0 == null) { Debug.LogError("Could not revert terrain because textures are missing!"); return; } UncompressTexture(t.customControl0); UncompressTexture(t.customControl1); UncompressTexture(t.customControl2); UncompressTexture(t.customControl3); UncompressTexture(t.customControl4); UncompressTexture(t.customControl5); UncompressTexture(t.customControl6); UncompressTexture(t.customControl7); int size = t.customControl0.width; int layers = t.terrain.terrainData.alphamapLayers; t.terrain.terrainData.alphamapResolution = size; var maps = t.terrain.terrainData.GetAlphamaps(0, 0, size, size); ExtractSplats(ref maps, t.customControl0, 0, layers); ExtractSplats(ref maps, t.customControl1, 4, layers); ExtractSplats(ref maps, t.customControl2, 8, layers); ExtractSplats(ref maps, t.customControl3, 12, layers); ExtractSplats(ref maps, t.customControl4, 16, layers); ExtractSplats(ref maps, t.customControl5, 20, layers); ExtractSplats(ref maps, t.customControl6, 24, layers); ExtractSplats(ref maps, t.customControl7, 28, layers); t.terrain.terrainData.SetAlphamaps(0, 0, maps); EditorUtility.SetDirty(t.terrain.terrainData); keywords.DisableKeyword("_CUSTOMSPLATTEXTURES"); MicroSplatShaderGUI.MicroSplatCompiler compiler = new MicroSplatShaderGUI.MicroSplatCompiler(); compiler.Compile(t.templateMaterial); t.customControl0 = null; t.customControl1 = null; t.customControl2 = null; t.customControl3 = null; t.customControl4 = null; t.customControl5 = null; t.customControl6 = null; t.customControl7 = null; EditorUtility.SetDirty(t); MicroSplatTerrain.SyncAll(); } }
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); } } } }
static Material SetupMaterial(MicroSplatKeywords kwds, Material mat, MicroSplatBaseFeatures.DebugOutput debugOutput, bool useDebugTopo) { MicroSplatShaderGUI.MicroSplatCompiler comp = new MicroSplatShaderGUI.MicroSplatCompiler(); List <string> keywords = new List <string>(kwds.keywords); RemoveKeyword(keywords, "_SNOW"); RemoveKeyword(keywords, "_TESSDISTANCE"); RemoveKeyword(keywords, "_WINDPARTICULATE"); RemoveKeyword(keywords, "_SNOWPARTICULATE"); RemoveKeyword(keywords, "_GLITTER"); RemoveKeyword(keywords, "_SNOWGLITTER"); RemoveKeyword(keywords, "_SPECULARFROMMETALLIC"); RemoveKeyword(keywords, "_USESPECULARWORKFLOW"); RemoveKeyword(keywords, "_BDRFLAMBERT"); RemoveKeyword(keywords, "_BDRF1"); RemoveKeyword(keywords, "_BDRF2"); RemoveKeyword(keywords, "_BDRF3"); keywords.Add(FeatureFromOutput(debugOutput).ToString()); if (useDebugTopo) { keywords.Add("_DEBUG_USE_TOPOLOGY"); } keywords.Add("_RENDERBAKE"); string shader = comp.Compile(keywords.ToArray(), "RenderBake_" + debugOutput.ToString()); Shader s = ShaderUtil.CreateShaderAsset(shader); Material renderMat = new Material(mat); renderMat.shader = s; renderMat.CopyPropertiesFromMaterial(mat); // because the constructor doesn't do it right in URP renderMat.enableInstancing = false; // for some reason instance drawing breaks in URP return(renderMat); }
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); }
void CompressTerrainSplats(MicroSplatTerrain t) { int splatCount = t.terrain.terrainData.alphamapTextureCount; // write out for (int i = 0; i < splatCount; ++i) { var tex = t.terrain.terrainData.GetAlphamapTexture(i); var path = MicroSplatUtilities.RelativePathFromAsset(t); path += "/" + t.name + "_splat" + i + ".tga"; System.IO.File.WriteAllBytes(path, tex.EncodeToTGA()); } AssetDatabase.Refresh(); // load and adjust importer for (int i = 0; i < splatCount; ++i) { var path = MicroSplatUtilities.RelativePathFromAsset(t); path += "/" + t.name + "_splat" + i + ".tga"; var tex = CompressTexture(path, false); if (i == 0) { t.customControl0 = tex; } else if (i == 1) { t.customControl1 = tex; } else if (i == 2) { t.customControl2 = tex; } else if (i == 3) { t.customControl3 = tex; } else if (i == 4) { t.customControl4 = tex; } else if (i == 5) { t.customControl5 = tex; } else if (i == 6) { t.customControl6 = tex; } else if (i == 7) { t.customControl7 = tex; } } EditorUtility.SetDirty(t); MicroSplatKeywords keywords = MicroSplatUtilities.FindOrCreateKeywords(t.templateMaterial); if (!keywords.IsKeywordEnabled("_CUSTOMSPLATTEXTURES")) { keywords.EnableKeyword("_CUSTOMSPLATTEXTURES"); MicroSplatShaderGUI.MicroSplatCompiler compiler = new MicroSplatShaderGUI.MicroSplatCompiler(); compiler.Compile(t.templateMaterial); MicroSplatTerrain.SyncAll(); } // destructive operation t.terrain.terrainData.alphamapResolution = 16; }
bool DoConvertGUI(MicroSplatTerrain t) { if (t.templateMaterial == null) { InitConvertConfigs(); using (new GUILayout.VerticalScope(GUI.skin.box)) { EditorGUILayout.LabelField("Select a Template:"); EditorGUILayout.BeginHorizontal(); for (int i = 0; i < convertConfigs.Count; ++i) { var c = convertConfigs [i]; if (DrawConvertButton(c, i == selectedConvertConfig)) { selectedConvertConfig = i; } } EditorGUILayout.EndHorizontal(); var selectedConfig = convertConfigs [selectedConvertConfig]; if (selectedConfig.missingModules.Count > 0) { EditorGUILayout.HelpBox("You are missing some MicroSplat modules needed by this template. The preset may still be used but some features will not be enabled. Missing modules are listed below:", MessageType.Warning); for (int i = 0; i < selectedConfig.missingModules.Count; ++i) { var m = selectedConfig.missingModules [i]; DrawMissingModule(m); } } EditorGUILayout.LabelField("Select any integrations you want to add:"); // integrations for (int i = 0; i < integrationConfigs.Count; ++i) { var ic = integrationConfigs [i]; if (!ic.assetInstalled) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(ic.name, GUILayout.Width(120)); EditorGUILayout.LabelField("Not Installed", GUILayout.Width(120)); if (GUILayout.Button("Link", GUILayout.Width(120))) { Application.OpenURL(ic.assetLink); } EditorGUILayout.EndHorizontal(); } else { EditorGUILayout.BeginHorizontal(); ic.include = EditorGUILayout.Toggle(ic.include, GUILayout.Width(20)); EditorGUILayout.LabelField(ic.name); EditorGUILayout.EndHorizontal(); if (ic.include && ic.missingModules.Count > 0) { using (new GUILayout.VerticalScope(GUI.skin.box)) { EditorGUILayout.HelpBox("Some MicroSplat modules requested by this module are not installed. Some or all features of the integration will not be active.", MessageType.Warning); for (int j = 0; j < ic.missingModules.Count; ++j) { var m = ic.missingModules [j]; DrawMissingModule(m); } } } } } if (GUILayout.Button("Convert to MicroSplat")) { // get all terrains in selection, not just this one, and treat as one giant terrain var objs = Selection.gameObjects; List <Terrain> terrains = new List <Terrain> (); for (int i = 0; i < objs.Length; ++i) { Terrain ter = objs [i].GetComponent <Terrain> (); if (ter != null) { terrains.Add(ter); } Terrain [] trs = objs [i].GetComponentsInChildren <Terrain> (); for (int x = 0; x < trs.Length; ++x) { if (!terrains.Contains(trs [x])) { terrains.Add(trs [x]); } } } Terrain terrain = t.GetComponent <Terrain> (); int texcount = 16; #if UNITY_2018_3_OR_NEWER texcount = terrain.terrainData.terrainLayers.Length; #else texcount = terrain.terrainData.splatPrototypes.Length; #endif List <string> keywords = new List <string> (selectedConfig.keywords); if (texcount <= 4) { keywords.Add("_MAX4TEXTURES"); } else if (texcount <= 8) { keywords.Add("_MAX8TEXTURES"); } else if (texcount <= 12) { keywords.Add("_MAX12TEXTURES"); } else if (texcount <= 20) { keywords.Add("_MAX20TEXTURES"); } else if (texcount <= 24) { keywords.Add("_MAX24TEXTURES"); } else if (texcount <= 28) { keywords.Add("_MAX28TEXTURES"); } else if (texcount > 28) { keywords.Add("_MAX32TEXTURES"); } for (int i = 0; i < integrationConfigs.Count; ++i) { var ic = integrationConfigs [i]; if (ic.include) { keywords.AddRange(ic.keywords); } } // setup this terrain t.templateMaterial = MicroSplatShaderGUI.NewShaderAndMaterial(terrain, keywords.ToArray()); var config = TextureArrayConfigEditor.CreateConfig(terrain); t.templateMaterial.SetTexture("_Diffuse", config.diffuseArray); t.templateMaterial.SetTexture("_NormalSAO", config.normalSAOArray); t.propData = MicroSplatShaderGUI.FindOrCreatePropTex(t.templateMaterial); #if UNITY_2018_3_OR_NEWER if (terrain.terrainData.terrainLayers.Length > 0) { var uvScale = terrain.terrainData.terrainLayers[0].tileSize; var uvOffset = terrain.terrainData.terrainLayers[0].tileOffset; uvScale = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain); uvOffset.x = uvScale.x / terrain.terrainData.size.x * 0.5f * uvOffset.x; uvOffset.y = uvScale.y / terrain.terrainData.size.x * 0.5f * uvOffset.y; Vector4 scaleOffset = new Vector4(uvScale.x, uvScale.y, uvOffset.x, uvOffset.y); t.templateMaterial.SetVector("_UVScale", scaleOffset); } #else if (terrain.terrainData.splatPrototypes.Length > 0) { var uvScale = terrain.terrainData.splatPrototypes [0].tileSize; var uvOffset = terrain.terrainData.splatPrototypes [0].tileOffset; uvScale = MicroSplatRuntimeUtil.UnityUVScaleToUVScale(uvScale, terrain); uvOffset.x = uvScale.x / terrain.terrainData.size.x * 0.5f * uvOffset.x; uvOffset.y = uvScale.y / terrain.terrainData.size.x * 0.5f * uvOffset.y; Vector4 scaleOffset = new Vector4(uvScale.x, uvScale.y, uvOffset.x, uvOffset.y); t.templateMaterial.SetVector("_UVScale", scaleOffset); } #endif // we need to set a few things on the material if certain features are enabled. // Test for property existence as module might not be installed and feature was culled. if (System.Array.Exists(selectedConfig.keywords, x => x == "_TRIPLANAR")) { if (t.templateMaterial.HasProperty("_TriplanarUVScale")) { t.templateMaterial.SetVector("_TriplanarUVScale", new Vector4(0.25f, 0.25f, 0, 0)); } } if (System.Array.Exists(selectedConfig.keywords, x => x == "_NORMALNOISE")) { if (t.templateMaterial.HasProperty("_NormalNoise")) { t.templateMaterial.SetTexture("_NormalNoise", MicroSplatUtilities.GetAutoTexture("microsplat_def_detail_normal_01")); } } // now make sure others all have the same settings as well. for (int i = 0; i < terrains.Count; ++i) { var nt = terrains [i]; var mgr = nt.GetComponent <MicroSplatTerrain> (); if (mgr == null) { mgr = nt.gameObject.AddComponent <MicroSplatTerrain> (); } mgr.templateMaterial = t.templateMaterial; if (mgr.propData == null) { mgr.propData = MicroSplatShaderGUI.FindOrCreatePropTex(mgr.templateMaterial); } } Selection.SetActiveObjectWithContext(config, config); t.keywordSO = MicroSplatUtilities.FindOrCreateKeywords(t.templateMaterial); t.keywordSO.keywords.Clear(); t.keywordSO.keywords = new List <string> (keywords); // force recompile, so that basemap shader name gets reset correctly.. MicroSplatShaderGUI.MicroSplatCompiler comp = new MicroSplatShaderGUI.MicroSplatCompiler(); comp.Compile(t.templateMaterial); MicroSplatTerrain.SyncAll(); // trun on draw instanced if enabled and tessellation is disabled, unless render loop is LWRP/URP in which case it does work.. #if UNITY_2018_3_OR_NEWER if (t.keywordSO != null && (!t.keywordSO.IsKeywordEnabled("_TESSDISTANCE") || t.keywordSO.IsKeywordEnabled("_MSRENDERLOOP_UNITYLD"))) { for (int i = 0; i < terrains.Count; ++i) { var nt = terrains [i]; var mgr = nt.GetComponent <MicroSplatTerrain> (); if (mgr != null && mgr.keywordSO != null && !mgr.keywordSO.IsKeywordEnabled("_MSRENDERLOOP_UNITYLD")) { nt.drawInstanced = true; } } } #endif return(true); } } } return(false); }
/// <summary> /// Attempt to recompile MicroSplat shader, ensuring the name matches the landscape name /// USAGE: /// bool isSuccessful = MicroSplatCompileShader(landscape, customTerrainMaterial, true); /// </summary> /// <param name="landscape"></param> /// <param name="terrainMat"></param> /// <param name="showErrors"></param> /// <returns></returns> public static bool MicroSplatCompileShader(LBLandscape landscape, Material terrainMat, bool showErrors) { bool isSuccessful = false; string methodName = "LBEditorIntegration.MicroSplatCompileShader"; //System.Type MicroSplatShaderGUIType = null; try { if (landscape == null) { if (showErrors) { Debug.LogWarning("ERROR: " + methodName + " landscape is null. Please Report"); } } else if (terrainMat == null) { if (showErrors) { Debug.LogWarning("ERROR: " + methodName + " terrainMat is null. Please Report"); } } else { Shader shader = terrainMat.shader; if (shader == null) { if (showErrors) { Debug.LogWarning(methodName + " - could not find MicroSplat shader. Please Report."); } } else if (!shader.name.Contains("MicroSplat")) { if (showErrors) { Debug.LogWarning(methodName + " - terrain material is not using a MicroSplat shader. [" + shader.name + "]. Please Report"); } } else { // Create a new instance of the compiler class MicroSplatShaderGUI.MicroSplatCompiler microSplatCompiler = new MicroSplatShaderGUI.MicroSplatCompiler(); string shaderPath = AssetDatabase.GetAssetPath(shader); string shaderBasePath = shaderPath.Replace(".shader", "_Base.shader"); if (microSplatCompiler == null) { if (showErrors) { Debug.LogWarning(methodName + " - could not create MicroSplatCompiler instance. Please Report."); } } else { microSplatCompiler.Init(); string[] shaderFeatures = terrainMat.shaderKeywords; // Ensure shader names match the landscape name string baseName = "Hidden/MicroSplat/" + landscape.name + "_Base"; string baseShaderOutput = microSplatCompiler.Compile(shaderFeatures, baseName); string regularShaderOutput = microSplatCompiler.Compile(shaderFeatures, "MicroSplat/" + landscape.name, baseName); //Debug.Log("[DEBUG] regularShaderOutput: " + regularShaderOutput); // Copy the output back to the shader files in the project folder. System.IO.File.WriteAllText(shaderPath, regularShaderOutput); System.IO.File.WriteAllText(shaderBasePath, baseShaderOutput); // Currently we don't use this but we "might" in the future if (shaderFeatures.Contains("_MESHOVERLAYSPLATS")) { string meshOverlayShader = microSplatCompiler.Compile(shaderFeatures, "MicroSplat/" + landscape.name, null, true); System.IO.File.WriteAllText(shaderPath.Replace(".shader", "_MeshOverlay.shader"), meshOverlayShader); } AssetDatabase.Refresh(); isSuccessful = !string.IsNullOrEmpty(baseShaderOutput) && !string.IsNullOrEmpty(regularShaderOutput); } } } } catch (System.Exception ex) { if (showErrors) { Debug.LogWarning("LBIntegration.MegaSplatCompileShader something has gone wrong. Please report. " + ex.Message); } } return(isSuccessful); }
void DrawScatterGUI() { if (MicroSplatUtilities.DrawRollup("Brush Settings")) { brushSize = EditorGUILayout.Slider("Brush Size", brushSize, 0.01f, 30.0f); brushFlow = EditorGUILayout.Slider("Brush Flow", brushFlow, 0.1f, 128.0f); brushFalloff = EditorGUILayout.Slider("Brush Falloff", brushFalloff, 0.1f, 3.5f); Material tempMat = null; for (int i = 0; i < rawTerrains.Count; ++i) { Terrain t = rawTerrains [i]; MicroSplatTerrain mst = t.GetComponent <MicroSplatTerrain> (); if (mst != null) { if (mst.templateMaterial != null && mst.templateMaterial.HasProperty("_ScatterDiffuse")) { Texture2DArray diff = mst.templateMaterial.GetTexture("_ScatterDiffuse") as Texture2DArray; scatterIndex = MicroSplatUtilities.DrawTextureSelector(scatterIndex, diff, false); tempMat = mst.templateMaterial; } else { scatterIndex = EditorGUILayout.IntField("Scatter Index", scatterIndex); } } else { scatterIndex = EditorGUILayout.IntField("Scatter Index", scatterIndex); } } //EditorGUILayout.MinMaxSlider (CSlopeRange, ref slopeRange.x, ref slopeRange.y, 0.0f, 1.0f); paintValue = EditorGUILayout.Slider("Target Opacity", paintValue, 0.0f, 1.0f); #if __MICROSPLAT_SCATTER__ if (tempMat != null) { scatterLayer = (ScatterLayer)EditorGUILayout.EnumPopup(CScatterLayer, scatterLayer); EditorGUILayout.Separator(); using (new GUILayout.VerticalScope(GUI.skin.box)) { EditorGUI.BeginChangeCheck(); EditorGUILayout.LabelField("Per Texture Properties"); bool changed = MicroSplatScatter.DrawPerTexExternal(tempMat, scatterIndex); EditorGUILayout.Separator(); // sync compile changes if (changed) { MicroSplatShaderGUI.MicroSplatCompiler comp = new MicroSplatShaderGUI.MicroSplatCompiler(); comp.Init(); comp.Compile(tempMat); } // sync property changes if (EditorGUI.EndChangeCheck()) { MicroSplatObject.SyncAll(); } } } #endif GUILayout.Box("", new GUILayoutOption [] { GUILayout.ExpandWidth(true), GUILayout.Height(1) }); EditorGUILayout.Separator(); } DrawFillGUI(); }