public static void DrawMegaSplat(MatrixGenerators.MegaSplatOutput200 gen) { #if !__MEGASPLAT__ using (Cell.LinePx(60)) Draw.Helpbox("MicroSplat doesn't seem to be installed, or MicroSplat compatibility is not enabled in settings"); #endif if (GraphWindow.current.mapMagic != null) { using (Cell.LineStd) { GeneratorDraw.DrawGlobalVar(ref GraphWindow.current.mapMagic.terrainSettings.material, "Material"); if (Cell.current.valChanged) { GraphWindow.current.mapMagic.ApplyTerrainSettings(); } } using (Cell.LineStd) { #if __MEGASPLAT__ MegaSplatTextureList texList = GraphWindow.current.mapMagic.globals.megaSplatTexList as MegaSplatTextureList; GeneratorDraw.DrawGlobalVar(ref texList, "TexList"); GraphWindow.current.mapMagic.globals.megaSplatTexList = texList; #endif } } using (Cell.LinePx(0)) CheckShader(gen); }
public static void DrawMegaSplat(MegaSplatOutput200 gen) { #if !__MEGASPLAT__ using (Cell.LinePx(60)) Draw.Helpbox("MicroSplat doesn't seem to be installed, or MicroSplat compatibility is not enabled in settings"); #endif if (GraphWindow.current.mapMagic != null) { using (Cell.LineStd) { GeneratorDraw.DrawGlobalVar(ref GraphWindow.current.mapMagic.terrainSettings.material, "Material"); if (Cell.current.valChanged) { GraphWindow.current.mapMagic.ApplyTerrainSettings(); } } using (Cell.LineStd) { #if __MEGASPLAT__ MegaSplatTextureList texList = GraphWindow.current.mapMagic.globals.megaSplatTexList as MegaSplatTextureList; GeneratorDraw.DrawGlobalVar(ref texList, "TexList"); GraphWindow.current.mapMagic.globals.megaSplatTexList = texList; #endif } } else { using (Cell.LinePx(18 + 18)) Draw.Label("Not assigned to current \nMapMagic object"); } using (Cell.LinePx(0)) CheckShader(gen); using (Cell.LinePx(20)) GeneratorDraw.DrawLayersAddRemove(gen, ref gen.layers, inversed: true, unlinkBackground: true); using (Cell.LinePx(0)) GeneratorDraw.DrawLayersThemselves(gen, gen.layers, inversed: true, layerEditor: DrawCTSLayer); }
private static void DrawCTSLayer(Generator tgen, int num) { MegaSplatOutput200 gen = (MegaSplatOutput200)tgen; MegaSplatOutput200.MegaSplatLayer layer = gen.layers[num]; if (layer == null) { return; } #if __MEGASPLAT__ MegaSplatTextureList textureList = GraphWindow.current.mapMagic?.globals.megaSplatTexList as MegaSplatTextureList; #endif Cell.EmptyLinePx(3); using (Cell.LinePx(28)) { //Cell.current.margins = new Padding(0,0,0,1); //1-pixel more padding from the bottom since layers are 1 pixel overlayed if (num != 0) { using (Cell.RowPx(0)) GeneratorDraw.DrawInlet(layer, gen); } else //disconnecting last layer inlet if (GraphWindow.current.graph.IsLinked(layer)) { GraphWindow.current.graph.UnlinkInlet(layer); } Cell.EmptyRowPx(10); //icon Texture2DArray icon = null; int index = -2; Material material = null; if (GraphWindow.current.mapMagic != null) { material = GraphWindow.current.mapMagic.terrainSettings.material; } if (material != null && material.HasProperty("_Diffuse")) { icon = (Texture2DArray)material?.GetTexture("_Diffuse"); } #if __MEGASPLAT__ if (textureList != null) { //icon = textureList.clusters[num].previewTex; //preview textures doesnt seem to be working in recent versions index = textureList.clusters[num].indexes[0]; } #endif using (Cell.RowPx(28)) { if (icon != null && index >= 0) { Draw.TextureIcon(icon, index); } } //channel Cell.EmptyRowPx(3); using (Cell.Row) { Cell.EmptyLine(); using (Cell.LineStd) { Cell.current.fieldWidth = 0.4f; #if __MEGASPLAT__ if (textureList != null) { Draw.PopupSelector(ref layer.channelNum, textureList.textureNames); } else { Draw.Field(ref layer.channelNum, "Channel"); } #else Draw.Field(ref layer.channelNum, "Channel"); #endif } Cell.EmptyLine(); } Cell.EmptyRowPx(10); using (Cell.RowPx(0)) GeneratorDraw.DrawOutlet(layer); } Cell.EmptyLinePx(3); }
public override void OnGUI (GeneratorsAsset gens) { #if __MEGASPLAT__ layout.fieldSize = 0.5f; //finding texture list from other generators if (textureList == null) foreach (MegaSplatOutput gen in gens.GeneratorsOfType<MegaSplatOutput>(onlyEnabled: true, checkBiomes: true)) if (gen.textureList != null) textureList = gen.textureList; //wrong material and settings warnings if (MapMagic.instance.showBaseMap) { layout.Par(30); layout.Label("Show Base Map is turned on in Settings.", rect:layout.Inset(0.8f), helpbox:true); if (layout.Button("Fix",rect:layout.Inset(0.2f))) MapMagic.instance.showBaseMap = false; } if (MapMagic.instance.terrainMaterialType != Terrain.MaterialType.Custom) { layout.Par(30); layout.Label("Material Type is not switched to Custom.", rect:layout.Inset(0.8f), helpbox:true); if (layout.Button("Fix",rect:layout.Inset(0.2f))) { MapMagic.instance.terrainMaterialType = Terrain.MaterialType.Custom; foreach (Chunk tw in MapMagic.instance.chunks.All()) tw.SetSettings(); } } if (MapMagic.instance.customTerrainMaterial == null || !MapMagic.instance.customTerrainMaterial.shader.name.Contains("MegaSplat")) { layout.Par(42); layout.Label("No MegaSplat material is assigned as Custom Material in Terrain Settings.", rect:layout.Inset(), helpbox:true); } if (MapMagic.instance.customTerrainMaterial != null) { if (!MapMagic.instance.customTerrainMaterial.IsKeywordEnabled("_TERRAIN") || !MapMagic.instance.customTerrainMaterial.HasProperty("_SplatControl")) { layout.Par(42); layout.Label("Material must use a MegaSplat shader set to Terrain.", rect:layout.Inset(), helpbox:true); } if (MapMagic.instance.customTerrainMaterial.GetTexture("_Diffuse") == null) { layout.Par(42); layout.Label("Material does not have texture arrays assigned, please assign them.", rect:layout.Inset(), helpbox:true); } } /*if (!MapMagic.instance.materialTemplateMode) { layout.Par(30); layout.Label("Material Template Mode is off.", rect:layout.Inset(0.8f), helpbox:true); if (layout.Button("Fix",rect:layout.Inset(0.2f))) MapMagic.instance.materialTemplateMode = true; }*/ if (MapMagic.instance.assignCustomTerrainMaterial) { layout.Par(30); layout.Label("Assign Custom Material is turned on.", rect:layout.Inset(0.8f), helpbox:true); if (layout.Button("Fix",rect:layout.Inset(0.2f))) { MapMagic.instance.assignCustomTerrainMaterial = false; } } if (textureList == null || textureList.clusters == null || textureList.clusters.Length <= 0) { layout.Par(30); layout.Label("Please assign textures and list with clusters below:", rect:layout.Inset(), helpbox:true); layout.Field<MegaSplatTextureList>(ref textureList, "TextureList"); foreach(Input input in Inputs()) input.link = null; return; } //drawing texture list field layout.Field<MegaSplatTextureList>(ref textureList, "TextureList"); //setting all of the generators list to this one if (layout.change) foreach (MegaSplatOutput gen in gens.GeneratorsOfType<MegaSplatOutput>(onlyEnabled: true, checkBiomes: true)) gen.textureList = textureList; //noise field layout.Par(5); layout.Field<float>(ref clusterNoiseScale, "Noise Scale"); layout.Toggle(ref smoothFallof, "Smooth Fallof"); //texture format layout.Par(5); layout.Toggle(ref MegaSplatOutput.formatARGB, "ARGB (since MS 1.14)"); //gathering cluster names if (clusterNames.Length != textureList.clusters.Length) clusterNames = new string[textureList.clusters.Length]; for (int i=0; i<clusterNames.Length; i++) clusterNames[i] = textureList.clusters[i].name; //drawing layers layout.Par(5); layout.Label("Layers:"); //needed to reset label bold style layout.margin = 20; layout.rightMargin = 20; for (int i=baseLayers.Length-1; i>=0; i--) { if (baseLayers[i] == null) baseLayers[i] = new Layer(); if (layout.DrawWithBackground(OnLayerGUI, active:i==selected, num:i, frameDisabled:false)) selected = i; } layout.Par(3); layout.Par(); layout.DrawArrayAdd(ref baseLayers, ref selected, layout.Inset(0.25f)); layout.DrawArrayRemove(ref baseLayers, ref selected, layout.Inset(0.25f)); layout.DrawArrayUp(ref baseLayers, ref selected, layout.Inset(0.25f), reverseOrder:true); layout.DrawArrayDown(ref baseLayers, ref selected, layout.Inset(0.25f), reverseOrder:true); //drawing effect layers layout.Par(5); layout.Par(20); wetnessIn.DrawIcon(layout); layout.Label("Wetness", layout.Inset()); layout.Par(20); puddlesIn.DrawIcon(layout); layout.Label("Puddles", layout.Inset()); layout.Par(20); displaceDampenIn.DrawIcon(layout); layout.Label("Displace Dampen", layout.Inset()); #else layout.margin = 5; layout.rightMargin = 5; layout.Par(65); layout.Label("MegaSplat is not installed. Please install it from the Asset Store, it's really amazing, you'll like it..\n\t Jason Booth", rect:layout.Inset(), helpbox:true); //What about adding a link to MegaSplat asset store page? Denis layout.Par(30); layout.Label("Restart Unity if you have just installed it.", rect:layout.Inset(), helpbox:true); #endif }
public static void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func<float,bool> stop = null) { #if __MEGASPLAT__ if (stop!=null && stop(0)) return; //using the first texture list for all MegaSplatTextureList textureList = null; bool smoothFallof = false; float clusterScale = 0.05f; foreach (MegaSplatOutput gen in gens.GeneratorsOfType<MegaSplatOutput>(onlyEnabled: true, checkBiomes: true)) { if (gen.textureList != null) textureList = gen.textureList; smoothFallof = gen.smoothFallof; clusterScale = gen.clusterNoiseScale; } //creating color arrays MegaSplatData result = new MegaSplatData(); result.control = new Color[MapMagic.instance.resolution * MapMagic.instance.resolution]; result.param = new Color[MapMagic.instance.resolution * MapMagic.instance.resolution]; //creating all and special layers/biomes lists List<Layer> allLayers = new List<Layer>(); //all layers count = gen num * layers num in each gen (excluding empty biomes, matrices, etc) List<Matrix> allMatrices = new List<Matrix>(); List<Matrix> allBiomeMasks = new List<Matrix>(); List<Matrix> specialWetnessMatrices = new List<Matrix>(); //special count = number of generators (excluding empty biomes only) List<Matrix> specialPuddlesMatrices = new List<Matrix>(); List<Matrix> specialDampeningMatrices = new List<Matrix>(); List<Matrix> specialBiomeMasks = new List<Matrix>(); //filling all layers/biomes foreach (MegaSplatOutput gen in gens.GeneratorsOfType<MegaSplatOutput>(onlyEnabled: true, checkBiomes: true)) { gen.textureList = textureList; //loading biome matrix Matrix biomeMask = null; if (gen.biome != null) { object biomeMaskObj = gen.biome.mask.GetObject(results); if (biomeMaskObj == null) continue; //adding nothing if biome has no mask biomeMask = (Matrix)biomeMaskObj; if (biomeMask == null) continue; if (biomeMask.IsEmpty()) continue; //optimizing empty biomes } for (int i = 0; i < gen.baseLayers.Length; i++) { //reading output directly Output output = gen.baseLayers[i].output; if (stop!=null && stop(0)) return; //checking stop before reading output if (!results.results.ContainsKey(output)) continue; Matrix matrix = (Matrix)results.results[output]; if (matrix.IsEmpty()) continue; if (i >= textureList.clusters.Length) { Debug.LogError("Cluster out of range"); continue; } //adding to lists allLayers.Add(gen.baseLayers[i]); allMatrices.Add(matrix); allBiomeMasks.Add(gen.biome == null ? null : biomeMask); } //adding special object wetnessObj = gen.wetnessIn.GetObject(results); specialWetnessMatrices.Add( wetnessObj!=null? (Matrix)wetnessObj : null ); object puddlesObj = gen.puddlesIn.GetObject(results); specialPuddlesMatrices.Add( puddlesObj!=null? (Matrix)puddlesObj : null ); object dampeingObj = gen.displaceDampenIn.GetObject(results); specialDampeningMatrices.Add( dampeingObj!=null? (Matrix)dampeingObj : null ); specialBiomeMasks.Add(gen.biome == null ? null : biomeMask); } //if no texture list found in any of generators - returning if (textureList == null || allLayers.Count==0) return; //processing int allLayersCount = allLayers.Count; int specialCount = specialWetnessMatrices.Count; for (int x = 0; x<rect.size.x; x++) for (int z = 0; z<rect.size.z; z++) { int pos = rect.GetPos(x + rect.offset.x, z + rect.offset.z); // doesn't use height, normal, but I'm not sure how to get that here.. Vector3 worldPos = new Vector3( 1f * (x+rect.offset.x) / MapMagic.instance.resolution * rect.size.x, 0, 1f * (z+rect.offset.z) / MapMagic.instance.resolution * rect.size.z); float heightRatio = results.heights!=null? results.heights.array[pos] : 0.5f; //0 is the bottom point, 1 is the maximum top Vector3 normal = new Vector3(0,1,0); // find highest two layers int botIdx = 0; int topIdx = 0; float botWeight = 0; float topWeight = 0; for (int i = 0; i<allLayersCount; i++) { float val = allMatrices[i].array[pos]; if (allBiomeMasks[i] != null) val *= allBiomeMasks[i].array[pos]; // really want world position, Normal, and height ratio for brushes, but for now, just use x/z.. if (val > botWeight) { topWeight = botWeight; topIdx = botIdx; botWeight = val; botIdx = i; } else if (val > topWeight) { topIdx = i; topWeight = val; } } //converting layer index to texture index topIdx = textureList.clusters[ allLayers[topIdx].index ].GetIndex(worldPos * clusterScale, normal, heightRatio); botIdx = textureList.clusters[ allLayers[botIdx].index ].GetIndex(worldPos * clusterScale, normal, heightRatio); //swapping indexes to make topIdx always on top if (botIdx > topIdx) { int tempIdx = topIdx; topIdx = botIdx; botIdx = tempIdx; float tempWeight = topWeight; topWeight = botWeight; botWeight = tempWeight; } //finding blend float totalWeight = topWeight + botWeight; if (totalWeight<0.01f) totalWeight = 0.01f; //Mathf.Max and Clamp are slow float blend = botWeight / totalWeight; if (blend>1) blend = 1; //adjusting blend curve if (smoothFallof) blend = (Mathf.Sqrt(blend) * (1-blend)) + blend*blend*blend; //Magic secret formula! Inverse to 3*x^2 - 2*x^3 //setting color result.control[pos] = new Color(botIdx / 255.0f, topIdx / 255.0f, 1.0f - blend, 1.0f); //params for (int i = 0; i<specialCount; i++) { float biomeVal = specialBiomeMasks[i]!=null? specialBiomeMasks[i].array[pos] : 1; if (specialWetnessMatrices[i]!=null) result.param[pos].b = specialWetnessMatrices[i].array[pos] * biomeVal; if (specialPuddlesMatrices[i]!=null) { result.param[pos].a = specialPuddlesMatrices[i].array[pos] * biomeVal; result.param[pos].r = 0.5f; result.param[pos].g = 0.5f; } if (specialDampeningMatrices[i]!=null) result.control[pos].a = specialDampeningMatrices[i].array[pos] * biomeVal; } } //pushing to apply if (stop!=null && stop(0)) return; results.apply.CheckAdd(typeof(MegaSplatOutput), result, replace: true); #endif }
public static Color[] BlendMegaSplat(Area area, Matrix heights, MegaSplatTextureList textureList, Matrix[] matrices, Matrix[] biomeMasks, float[] opacities, int[] channelNums, StopToken stop = null) { CoordRect activeRect = area.active.rect; Color[] controlMap = new Color[activeRect.Count]; //getting matrices rect CoordRect matrixRect = new CoordRect(0, 0, 0, 0); for (int m = 0; m < matrices.Length; m++) { if (matrices[m] != null) { matrixRect = matrices[m].rect; } } //checking rect for (int m = 0; m < matrices.Length; m++) { if (matrices[m] != null && matrices[m].rect != matrixRect) { throw new System.Exception("MapMagic: Matrix rect mismatch"); } } for (int b = 0; b < biomeMasks.Length; b++) { if (biomeMasks[b] != null && biomeMasks[b].rect != matrixRect) { throw new System.Exception("MapMagic: Biome matrix rect mismatch"); } } //preparing row re-use array float[] values = new float[matrices.Length]; //blending for (int x = 0; x < activeRect.size.x; x++) { for (int z = 0; z < activeRect.size.z; z++) { int matrixPosX = activeRect.offset.x + x; int matrixPosZ = activeRect.offset.z + z; int matrixPos = (matrixPosZ - matrixRect.offset.z) * matrixRect.size.x + matrixPosX - matrixRect.offset.x; int colorsPos = z * activeRect.size.x + x; //(z-colorsRect.offset.z)*colorsRect.size.x + x - colorsRect.offset.x; // find highest two layers int botOutputIdx = 0; int topOutputIdx = 0; float botWeight = 0; float topWeight = 0; for (int i = 0; i < matrices.Length; i++) { //value float val = matrices[i].arr[matrixPos]; //multiply with biome Matrix biomeMask = biomeMasks[i]; if (biomeMask != null) //no empty biomes in list (so no mask == root biome) { val *= biomeMask.arr[matrixPos]; //if mask is not assigned biome was ignored, so only main outs with mask==null left here } //clamp if (val < 0) { val = 0; } if (val > 1) { val = 1; } //finding if it's highest if (val > botWeight) { topWeight = botWeight; topOutputIdx = botOutputIdx; botWeight = val; botOutputIdx = i; } //or 2nd highest else if (val > topWeight) { topOutputIdx = i; topWeight = val; } } //converting layer index to texture index int topClusterIdx = channelNums[topOutputIdx]; int botClusterIdx = channelNums[botOutputIdx]; Vector3 worldPos = area.active.CoordToWorld(x, z); float heightRatio = heights != null? heights.arr[matrixPos] : 0.5f; //0 is the bottom point, 1 is the maximum top Vector3 normal = new Vector3(0, 1, 0); //TODO: get normal from matrix int topTexIdx = textureList.clusters[topClusterIdx].GetIndex(worldPos * clusterNoiseScale, normal, heightRatio); int botTexIdx = textureList.clusters[botClusterIdx].GetIndex(worldPos * clusterNoiseScale, normal, heightRatio); //swapping indexes to make topIdx always on top /*if (botIdx > topIdx) * { * int tempIdx = topIdx; * topIdx = botIdx; * botIdx = tempIdx; * * float tempWeight = topWeight; * topWeight = botWeight; * botWeight = tempWeight; * }*/ //finding blend float totalWeight = topWeight + botWeight; if (totalWeight < 0.01f) { totalWeight = 0.01f; //Mathf.Max and Clamp are slow } float blend = botWeight / totalWeight; if (blend > 1) { blend = 1; } //adjusting blend curve if (smoothFallof) { blend = (Mathf.Sqrt(blend) * (1 - blend)) + blend * blend * blend; //Magic secret formula! Inverse to 3*x^2 - 2*x^3 } //setting color controlMap[colorsPos] = new Color(botTexIdx / 255.0f, topTexIdx / 255.0f, 1.0f - blend, 1.0f); //params /*for (int i = 0; i<specialCount; i++) * { * float biomeVal = specialBiomeMasks[i]!=null? specialBiomeMasks[i].array[pos] : 1; * * if (specialWetnessMatrices[i]!=null) result.param[pos].b = specialWetnessMatrices[i].array[pos] * biomeVal; * if (specialPuddlesMatrices[i]!=null) * { * result.param[pos].a = specialPuddlesMatrices[i].array[pos] * biomeVal; * result.param[pos].r = 0.5f; * result.param[pos].g = 0.5f; * } * if (specialDampeningMatrices[i]!=null) result.control[pos].a = specialDampeningMatrices[i].array[pos] * biomeVal; * }*/ } } return(controlMap); }