static void CreateVoxeland (bool infinite=true) { GameObject go = new GameObject(); go.name = "Voxeland"; Voxeland voxeland = go.AddComponent<Voxeland>(); voxeland.chunks = new ChunkGrid<Chunk>(); voxeland.chunkSize = 30; Voxeland.instances.Add(voxeland); //adding empty layer voxeland.landTypes = new LandTypeList(); ArrayTools.Add(ref voxeland.landTypes.array, new BlockType()); voxeland.landTypes.array[0].mainTex = TextureExtensions.ColorTexture(2,2,new Color(0.666f, 0.666f, 0.666f, 0.5f), linear:false); #if UNITY_2017_3_OR_NEWER voxeland.landTypes.array[0].bumpMap = TextureExtensions.ColorTexture(2,2,new Color(0.5f, 0.5f, 0.5f, 1f), linear:true); #else voxeland.landTypes.array[0].bumpMap = TextureExtensions.ColorTexture(2,2,new Color(0.5f, 0.5f, 0.5f, 0.5f), linear:true); #endif //voxeland.landTypes.mainTexArray = new Texture2DArray(1024, 1024, 1, TextureFormat.DXT5, true) { name = "Albedo Height Array" }; //voxeland.landTypes.mainTexArray.SetTexture( TextureExtensions.ColorTexture(1024,1024,Color.gray), 0); //voxeland.landTypes.bumpMapArray = new Texture2DArray(1024, 1024, 1, TextureFormat.DXT5, true, linear:true) { name = "Normals Array" }; //voxeland.landTypes.bumpMapArray.SetTexture( TextureExtensions.ColorTexture(1024,1024,new Color(0.5f,0.5f,0.5f,0.5f)), 0); voxeland.landTypes.selected = 0; //adding empty grass voxeland.grassTypes = new GrassTypeList(); voxeland.grassTypes.selected = -1; //objects voxeland.objectsTypes = new ObjectTypeList(); voxeland.objectsTypes.selected = -1; //data voxeland.data = ScriptableObject.CreateInstance<Data>(); voxeland.data.areas = new ChunkGrid<Data.Area>(); voxeland.data.areaSize = 512; //materials voxeland.material = Voxeland.GetDefaultLandMaterial(); voxeland.farMaterial = Voxeland.GetDefaultFarMaterial(); voxeland.grassMaterial = Voxeland.GetDefaultGrassMaterial(); voxeland.landTypes.ApplyToMaterial(voxeland.material); voxeland.landTypes.ApplyToMaterial(voxeland.farMaterial, horizon:true); voxeland.grassTypes.ApplyToMaterial(voxeland.grassMaterial); if (voxeland.horizon != null) voxeland.horizon.meshRenderer.sharedMaterial = voxeland.farMaterial; //highlight if (voxeland.highlight == null) //could be created on de-prefab in onenable { voxeland.highlight = Highlight.Create(voxeland); voxeland.highlight.material = Voxeland.GetDefaultHighlightMaterial(); //new Material( Shader.Find("Voxeland/Highlight") ); } //static and infinite if (infinite) { voxeland.playmodeSizeMode = Voxeland.SizeMode.DynamicInfinite; voxeland.editorSizeMode = Voxeland.SizeMode.DynamicInfinite; voxeland.saveMeshes = false; voxeland.horizon = Horizon.Create(voxeland); } else { voxeland.playmodeSizeMode = Voxeland.SizeMode.Static; voxeland.editorSizeMode = Voxeland.SizeMode.Static; voxeland.saveMeshes = true; } //generators voxeland.data.generator.noiseGen.enabled = true; voxeland.data.generator.noiseGenB.enabled = false; voxeland.data.generator.noiseGenB.seed = 1234; voxeland.data.generator.noiseGenB.high = 0.1f; voxeland.data.generator.curveGen.enabled = true; voxeland.data.generator.blurGen.enabled = true; //registering undo Undo.RegisterCreatedObjectUndo (go, "Voxeland Create"); EditorUtility.SetDirty(go); }
public override void OnInspectorGUI () { voxeland = (Voxeland)target; Voxeland.current = voxeland; //assigning voxeland to mapmagic window #if MAPMAGIC if (MapMagic.MapMagicWindow.instance != null && MapMagic.MapMagicWindow.instance.mapMagic != (MapMagic.IMapMagic)voxeland && voxeland.data != null && voxeland.data.generator != null && voxeland.data.generator.mapMagicGens != null) MapMagic.MapMagicWindow.Show(voxeland.data.generator.mapMagicGens, voxeland, forceOpen:false); #endif if (layout == null) layout = new Layout(); layout.margin = 0; layout.rightMargin = 5; layout.field = Layout.GetInspectorRect(); layout.cursor = new Rect(); layout.undoObject = voxeland; layout.undoName = "Voxeland settings change"; layout.dragChange = true; layout.change = false; layout.delayed = true; if (voxeland.data == null) { layout.Par(30); layout.Label("Voxeland data is not assigned in Settings menu. No edit or rebuild allowed.", rect:layout.Inset(), helpbox:true); } #region Progress layout.Par(); if (ThreadWorker.IsWorking("Voxeland")) { float calculatedSum; float completeSum; float totalSum; ThreadWorker.GetProgresByTag("VoxelandChunk", out totalSum, out calculatedSum, out completeSum); if (totalSum>10) { Rect gaugeRect = layout.Inset(0.7f); layout.Gauge(0, "", gaugeRect); layout.Gauge(1, "", new Rect(gaugeRect.x, gaugeRect.y, gaugeRect.width * calculatedSum/totalSum, gaugeRect.height), disabled:true); layout.Gauge(1, "", new Rect(gaugeRect.x, gaugeRect.y, gaugeRect.width * completeSum/totalSum, gaugeRect.height)); // Rect cursor = layout.cursor; // layout.Gauge(calculatedSum/totalSum, "", layout.Inset(0.7f), disabled:true); // layout.cursor = cursor; // layout.Gauge(calculatedSum/totalSum, "", layout.Inset(0.7f)); //layout.Gauge(progress, "Progress: " + (int)completeSum + "(" + calculatedSum + ")" + "/" + (int)totalSum, layout.Inset(0.7f)); // layout.cursor = cursor; layout.Label("Progress: " + (int)completeSum + "(" + calculatedSum + ")" + "/" + (int)totalSum, gaugeRect); } else layout.Label("Progress: building", layout.Inset(0.7f)); gaugeDisplayed = true; Repaint(); } else { layout.Label("Progress: complete", layout.Inset(0.7f)); gaugeDisplayed = false; } if (layout.Button("Rebuild", layout.Inset(0.3f))) voxeland.Rebuild(); #endregion layout.margin = 0; layout.rightMargin = 5; #region Brush layout.Par(8); layout.Foldout(ref voxeland.guiBrush, "Brush"); if (voxeland.guiBrush) { Rect anchor = layout.lastRect; layout.Field(ref voxeland.brush.form, "Form"); voxeland.brush.extent = layout.Field(voxeland.brush.extent, "Extent", min:0, max: voxeland.brush.maxExtent, slider:true); layout.Toggle(ref voxeland.brush.round, "Round"); layout.Par(5); if (voxeland.brush.form==Brush.Form.stamp) { layout.Field(ref voxeland.brush.getStamp, "Get Stamp"); if (voxeland.brush.getStamp) { layout.Par(); layout.Label("Min:",rect:layout.Inset(0.25f)); layout.Field(ref voxeland.brush.getStampMin.x, "X", rect:layout.Inset(0.25f)); layout.Field(ref voxeland.brush.getStampMin.y, "Y", rect:layout.Inset(0.25f)); layout.Field(ref voxeland.brush.getStampMin.z, "Z", rect:layout.Inset(0.25f)); layout.Par(); layout.Label("Max:",rect:layout.Inset(0.25f)); layout.Field(ref voxeland.brush.getStampMax.x, "X", rect:layout.Inset(0.25f)); layout.Field(ref voxeland.brush.getStampMax.y, "Y", rect:layout.Inset(0.25f)); layout.Field(ref voxeland.brush.getStampMax.z, "Z", rect:layout.Inset(0.25f)); } } layout.Par(5); layout.Field(ref voxeland.standardEditMode, "Standard Edit"); layout.Field(ref voxeland.controlEditMode, "Control Mode"); layout.Field(ref voxeland.shiftEditMode, "Shift Mode"); layout.Field(ref voxeland.controlShiftEditMode, "Control+Shift Mode"); layout.Par(5); layout.Toggle(ref voxeland.continuousPainting, "Continuous Painting"); layout.Foreground(anchor); //if (voxeland.guiBrush) layout.Par(3); } #endregion #region Land Types layout.Par(8); layout.Foldout(ref voxeland.guiBlocks, "Land Blocks"); if (voxeland.guiBlocks) { Rect anchor = layout.lastRect; layout.margin += 5; layout.rightMargin += 5; LandTypeList types = voxeland.landTypes; //blocks if (types.textureArrays && types.mainTexArray != null && types.bumpMapArray != null) { if (types.mainTexArrDec == null || types.mainTexArrDec.texArr != types.mainTexArray) types.mainTexArrDec = new TextureArrayDecorator(types.mainTexArray); if (types.bumpTexArrDec == null || types.bumpTexArrDec.texArr != types.bumpMapArray) types.bumpTexArrDec = new TextureArrayDecorator(types.bumpMapArray); int minCount = Mathf.Min(types.mainTexArray.depth, types.bumpMapArray.depth); if (types.array.Length != minCount) ArrayTools.Resize(ref types.array, minCount, createElement:num => new BlockType() { name="Land Block" }); } layout.Par(4); for (int i=0; i<types.array.Length; i++) { /*#if RTP if (rtpMat) layout.DrawWithBackground(null, active:i==types.selected)) else layout.DrawWithBackground(types.array[i].OnGUI, active:i==types.selected)) if (layout.lastChange && !rtpMat) { voxeland.landTypes.ApplyToMaterial(voxeland.material); voxeland.landTypes.ApplyToMaterial(voxeland.farMaterial); } #else*/ layout.Layer(types, i); if (layout.lastChange) { types.ApplyToMaterial(voxeland.material); types.ApplyToMaterial(voxeland.farMaterial, horizon:true); } //#endif } //drawing buttons layout.Par(3); layout.Par(); layout.LayerButtons(types, types.array.Length, rect:layout.Inset(0.6f)); layout.Inset(0.05f); layout.Field(ref types.changeBlockData, "Sync Data", rect:layout.Inset(0.35f), fieldSize:0.15f); layout.Par(5); //layout.AssetNewSaveField(ref voxeland.material, "Material", saveFilename:"LandMaterial", saveType:"mat", create:Voxeland.GetDefaultLandMaterial); //common (material) layout.Par(6); layout.Par(); layout.Foldout(ref voxeland.guiLandCommon, "General Material", rect:layout.Inset(), bold:false); if (voxeland.guiLandCommon) { Rect internalAnchor = layout.lastRect; layout.change = false; layout.AssetNewSaveField(ref voxeland.material, "Material", saveFilename:"LandMaterial", saveType:"mat", create:Voxeland.GetDefaultLandMaterial); layout.Par(5); if (types.textureArrays) layout.Field(ref types.anisotropicFiltration, "Anisotropic Filtration", tooltip:"For TextureArray shader - enables/disables the anisotropic filtration in texture arrays created from blocks textures. Highly affects shader performance."); layout.Field(ref types.tile, "Tile"); layout.Field(ref types.mips, "MipMap Factor"); layout.Field(ref types.ambientOcclusion, "Ambient Occlusion"); layout.Field(ref types.blendMapFactor, "Blend Map Factor"); layout.Field(ref types.blendCrisp, "Blend Crispness"); layout.Field(ref types.previewType, "Preview"); if (layout.change) { types.ApplyToMaterial(voxeland.material); types.ApplyToMaterial(voxeland.farMaterial, horizon:true); } layout.Foreground(internalAnchor, layout.lastRect); } //texture arrays layout.Par(6); layout.Foldout(ref voxeland.guiLandTexarr, "Texture Arrays", bold:false); if (voxeland.guiLandTexarr) { Rect internalAnchor = layout.lastRect; layout.Toggle(ref types.textureArrays, "Use Texture Arrays"); if (layout.lastChange) { //for (int i=0; i<types.array.Length; i++) // types.array[i].icon = null; } if (types.textureArrays) { //if (voxeland.material==null || !voxeland.material.HasProperty("_MainTexArr")) // { layout.Par(30); layout.Label("Switch material to TextureArray shader in order to use texture arrays.", rect:layout.Inset(), helpbox:true); } layout.Par(); layout.Field(ref types.mainTexArray, "Albedo", rect:layout.Inset(layout.field.width-25-layout.margin-layout.rightMargin)); if (layout.lastChange) ChangeTextureArray(types.mainTexArray, ref types, isBump:false); layout.Inset(5); if (layout.Button("", rect:layout.Inset(20), icon:"DPLayout_New")) { Texture2DArray texArr = CreateTextureArrayAsset("MainTexArr", types, isBump:false); if (texArr != null) { types.mainTexArray = texArr; ChangeTextureArray(types.mainTexArray, ref types, isBump:false); } } layout.Par(); layout.Field(ref types.bumpMapArray, "Normal", rect:layout.Inset(layout.field.width-25-layout.margin-layout.rightMargin)); if (layout.lastChange) ChangeTextureArray(types.bumpMapArray, ref types, isBump:true); layout.Inset(5); if (layout.Button("", rect:layout.Inset(20), icon:"DPLayout_New")) { Texture2DArray texArr = CreateTextureArrayAsset("BumpMapArr", types, isBump:true); if (texArr != null) { types.bumpMapArray = texArr; ChangeTextureArray(types.bumpMapArray, ref types, isBump:true); } } if (types.bumpMapArray == null) { layout.Par(30); layout.Label("A normal map is required for proper terrain lighing.", rect:layout.Inset(), helpbox:true); } layout.Par(0); layout.Inset(); } //if (!types.textureArrays && voxeland.material!=null && voxeland.material.HasProperty("_MainTexArr")) // { layout.Par(30); layout.Label("Switch material to non-TextureArray (Voxeland/Land) shader in order to use the standard textures.", rect:layout.Inset(), helpbox:true); } layout.Foreground(internalAnchor, layout.lastRect); } //megasplat clusters (not yet implemented) /*#if __MEGASPLAT__ layout.Par(6); layout.Foldout(ref voxeland.guiLandMegaSplatClusters, "MegaSplat Clusters", bold:false); if (voxeland.guiLandMegaSplatClusters) { Rect internalAnchor = layout.lastRect; layout.Toggle(ref types.megaClusters, "Use MegaSplat"); if (layout.lastChange) { if (types.megaClusters) voxeland.channelEncoding = Voxeland.ChannelEncoding.MegaSplat; else voxeland.channelEncoding = Voxeland.ChannelEncoding.RTP; } if (types.megaClusters) { if (voxeland.material==null || !voxeland.material.HasProperty("_Diffuse") || !voxeland.material.HasProperty("_Normal")) { layout.Par(30); layout.Label("Assign a proper MegaSplat mesh material.", rect:layout.Inset(), helpbox:true); } layout.Field(ref types.megaTexList); if (layout.lastChange) { //if (types.megaTexList != null && types.array.Length != types.megaTexList.clusters.Length) // ArrayTools.Resize(ref types.array, types.megaTexList.clusters.Length, createElement:num => new BlockType() {name=types.megaTexList.clusters[num].name}); types.array = new BlockType[0]; if (types.megaTexList != null) ArrayTools.Resize(ref types.array, types.megaTexList.clusters.Length, createElement:num => new BlockType() {name=types.megaTexList.clusters[num].name}); } } layout.Foreground(internalAnchor, layout.lastRect); } #endif*/ //distant display layout.Par(6); layout.Foldout(ref voxeland.guiLandFar, "Distant Tile", bold:false); if (voxeland.guiLandFar) { Rect internalAnchor = layout.lastRect; layout.change = false; layout.Toggle(ref types.farEnabled, "Enabled"); layout.Field(ref types.farTile, "Tile"); layout.Field(ref types.farStart, "Start"); layout.Field(ref types.farEnd, "End"); if (layout.change) { types.ApplyToMaterial(voxeland.material); types.ApplyToMaterial(voxeland.farMaterial, horizon:true); } layout.Foreground(internalAnchor, layout.lastRect); } //horizon layout.Par(6); layout.Foldout(ref voxeland.guiLandHorizon, "Horizon", bold:false); if (voxeland.guiLandHorizon) { Rect internalAnchor = layout.lastRect; layout.change = false; layout.Field(ref types.horizonTile, "Tile"); layout.Field(ref types.horizonBorderLower, "Border Lower"); if (layout.change) { types.ApplyToMaterial(voxeland.material); types.ApplyToMaterial(voxeland.farMaterial, horizon:true); } layout.Foreground(internalAnchor, layout.lastRect); } layout.Par(5); layout.margin -= 5; layout.rightMargin -= 5; layout.Par(0,0,0); layout.Inset(1); layout.Foreground(anchor, layout.lastRect); } #endregion #region Object Types layout.Par(8); layout.Foldout(ref voxeland.guiObjects, "Object Blocks"); if (voxeland.guiObjects) { Rect anchor = layout.lastRect; layout.margin += 5; layout.rightMargin += 5; ObjectTypeList types = voxeland.objectsTypes; layout.Par(0); for (int i=0; i<types.array.Length; i++) layout.Layer(types, i); layout.Par(3); layout.Par(); layout.LayerButtons(types, types.array.Length, rect:layout.Inset(0.6f)); layout.Inset(0.05f); layout.Field(ref types.changeBlockData, "Sync Data", rect:layout.Inset(0.35f), fieldSize:0.15f); layout.Par(10); layout.Toggle(ref voxeland.objectsPool.regardPrefabRotation, "Regard Prefab Rotation"); layout.Toggle(ref voxeland.objectsPool.regardPrefabScale, "Regard Prefab Scale"); layout.Toggle(ref voxeland.objectsPool.instantiateClones, "Instantiate Clones"); layout.margin -= 5; layout.rightMargin -= 5; layout.Foreground(anchor); } #endregion #region Grass Types layout.Par(8); layout.Foldout(ref voxeland.guiGrass, "Grass"); if (voxeland.guiGrass) { Rect anchor = layout.lastRect; layout.margin += 5; layout.rightMargin += 5; GrassTypeList types = voxeland.grassTypes; //layers layout.Par(4); for (int i=0; i<types.array.Length; i++) { layout.Layer(types, i); if (layout.lastChange) types.ApplyToMaterial(voxeland.grassMaterial); } //drawing buttons layout.Par(3); layout.Par(); layout.LayerButtons(types, types.array.Length, rect:layout.Inset(0.6f)); layout.Inset(0.05f); layout.Field(ref types.changeBlockData, "Sync Data", rect:layout.Inset(0.35f), fieldSize:0.15f); layout.Par(5); //common (material) layout.Par(6); layout.Par(); layout.Foldout(ref voxeland.guiGrassCommon, "Grass Material", rect:layout.Inset(), bold:false); if (voxeland.guiGrassCommon) { Rect internalAnchor = layout.lastRect; layout.change = false; layout.AssetNewSaveField(ref voxeland.grassMaterial, "Material", saveFilename:"GrassMaterial", saveType:"mat", create:Voxeland.GetDefaultGrassMaterial); layout.Par(5); layout.Field(ref types.culling, "Culling"); layout.Field(ref types.cutoff, "Alpha Ref"); layout.Field(ref types.ambientPower, "Ambient"); layout.Field(ref types.mipFactor, "Mip Factor"); layout.Field(ref types.vanishAngle, "Vanish Angle"); layout.Field(ref types.appearAngle, "Appear Angle"); layout.Par(5); layout.Inset(); if (layout.change) types.ApplyToMaterial(voxeland.grassMaterial); layout.Foreground(internalAnchor, layout.lastRect); } //atlas layout.Par(6); layout.Par(); layout.Foldout(ref voxeland.guiGrassAtlas, "Atlas", rect:layout.Inset(), bold:false); if (voxeland.guiGrassAtlas) { Rect internalAnchor = layout.lastRect; layout.change = false; layout.Field(ref types.atlas, "Atlas Enabled"); if (layout.lastChange && types.atlas) //removing layer textures for (int i=0; i<types.array.Length; i++) { // types.array[i].mainTex = null; // types.array[i].bumpMap = null; // types.array[i].specSmoothMap = null; // types.array[i].sssVanishMap = null; } if (layout.lastChange && types.atlas) //removing assigned atlas { // types.mainTex = null; // types.bumpMap = null; // types.specSmoothMap = null; // types.sssVanishMap = null; } if (types.atlas) { layout.Field(ref types.mainTex, "Albedo/Alpha"); layout.Field(ref types.bumpMap, "Normal"); layout.Field(ref types.specSmoothMap, "Spec/Gloss"); layout.Field(ref types.sssVanishMap, "SSS"); } if (layout.change) types.ApplyToMaterial(voxeland.grassMaterial); layout.Foreground(internalAnchor, layout.lastRect); } //SSS layout.Par(6); layout.Par(); layout.Foldout(ref voxeland.guiGrassSSS, "Translucency", rect:layout.Inset(), bold:false); if (voxeland.guiGrassSSS) { Rect internalAnchor = layout.lastRect; layout.change = false; layout.Field(ref types.sss, "Value"); layout.Field(ref types.saturation, "Saturation"); layout.Field(ref types.sssDistance, "Distance"); layout.Par(5); layout.Inset(); if (layout.change) types.ApplyToMaterial(voxeland.grassMaterial); layout.Foreground(internalAnchor, layout.lastRect); } //Shake layout.Par(6); layout.Par(); layout.Foldout(ref voxeland.guiGrassShake, "Shake/Wind", rect:layout.Inset(), bold:false); if (voxeland.guiGrassShake) { Rect internalAnchor = layout.lastRect; layout.change = false; layout.Field(ref types.shakingAmplitude, "Shake Amplitude"); layout.Field(ref types.shakingFrequency, "Shake Frequency"); layout.Field(ref types.windTex, "Wind Texture"); layout.Field(ref types.windSize, "Wind Size"); layout.Field(ref types.windSpeed, "Wind Speed"); layout.Field(ref types.windStrength, "Wind Strength"); if (layout.change) types.ApplyToMaterial(voxeland.grassMaterial); layout.Foreground(internalAnchor, layout.lastRect); } layout.Par(5); layout.Inset(); layout.margin -= 5; layout.rightMargin -= 5; layout.Foreground(anchor); } #endregion #region Distances layout.Par(8); layout.Foldout(ref voxeland.guiDistances, "Mode and Ranges"); if (voxeland.guiDistances) { Rect anchor = layout.lastRect; layout.fieldSize = 0.4f; layout.Field(ref voxeland.editorSizeMode, "Editor Mode"); layout.Field(ref voxeland.playmodeSizeMode, "Playmode Mode"); layout.Par(5); if (voxeland.editorSizeMode!=Voxeland.SizeMode.DynamicInfinite || voxeland.playmodeSizeMode!=Voxeland.SizeMode.DynamicInfinite) { layout.Field(ref voxeland.terrainSize, "Terrain Size"); voxeland.terrainSize = ((int)(voxeland.terrainSize/voxeland.chunkSize)) * voxeland.chunkSize; } bool prevChange = layout.change; layout.change = false; if (voxeland.editorSizeMode!=Voxeland.SizeMode.Static || voxeland.playmodeSizeMode!=Voxeland.SizeMode.Static) { layout.Par(5); layout.Label("Terrain Ranges:"); if (voxeland.guiDistancesFullControl) { layout.fieldSize = 0.2f; voxeland.guiDistancesMax = layout.Field(voxeland.guiDistancesMax, "Max Distance", delayed:true); layout.fieldSize = 0.8f; layout.Par(5); layout.Label("Chunks"); DrawRange("Create", ref voxeland.createRange, 0.01f, voxeland.guiDistancesMax, voxeland.guiDistancesMax); DrawRange("Remove", ref voxeland.removeRange, voxeland.createRange, voxeland.guiDistancesMax, voxeland.guiDistancesMax); layout.Par(5); layout.Label("Voxel Meshes"); DrawRange("Low Detail", ref voxeland.voxelLoRange, voxeland.voxelHiRange, voxeland.createRange, voxeland.guiDistancesMax); DrawRange("High Detail", ref voxeland.voxelHiRange, 0.01f, voxeland.voxelLoRange, voxeland.guiDistancesMax); DrawRange("Collision", ref voxeland.collisionRange, 0.01f, voxeland.voxelLoRange, voxeland.guiDistancesMax); DrawRange("Objects", ref voxeland.objectsRange, 0.01f, voxeland.createRange, voxeland.guiDistancesMax); DrawRange("Grass", ref voxeland.grassRange, 0.01f, voxeland.voxelLoRange, voxeland.guiDistancesMax); DrawRange("Remove", ref voxeland.voxelRemoveRange, voxeland.voxelLoRange, voxeland.createRange, voxeland.guiDistancesMax); layout.Par(5); layout.Label("Sculpt Areas"); DrawRange("Generate", ref voxeland.areaGenerateRange, 0.01f, voxeland.areaRemoveRange, voxeland.areaRemoveRange); DrawRange("Remove", ref voxeland.areaRemoveRange, voxeland.areaGenerateRange, voxeland.areaRemoveRange, voxeland.areaRemoveRange); } else { layout.fieldSize = 0.8f; DrawRange("Voxel Mesh", ref voxeland.voxelLoRange, 0.01f, 300, 300); DrawRange("Objects", ref voxeland.objectsRange, 0.01f, 300, 300); layout.Par(5); DrawRange("Collision", ref voxeland.collisionRange, 0.01f, voxeland.voxelLoRange, voxeland.guiDistancesMax); DrawRange("Grass", ref voxeland.grassRange, 0.01f, voxeland.voxelLoRange, voxeland.guiDistancesMax); DrawRange("High Detail", ref voxeland.voxelHiRange, 0.01f, voxeland.voxelLoRange, voxeland.guiDistancesMax); voxeland.createRange = Mathf.Max(voxeland.voxelLoRange, voxeland.objectsRange); voxeland.removeRange = voxeland.createRange + voxeland.chunkSize*2+1; voxeland.voxelRemoveRange = voxeland.voxelLoRange + voxeland.chunkSize*2+1; voxeland.areaGenerateRange = voxeland.createRange + voxeland.data.areaSize; voxeland.areaRemoveRange = voxeland.areaGenerateRange + voxeland.data.areaSize*2; } layout.Toggle(ref voxeland.guiDistancesFullControl, "Advanced"); layout.fieldSize = 0.5f; } if (layout.change) voxeland.ForceUpdate(); layout.change = prevChange; layout.Foreground(anchor); } #endregion #region Settings layout.Par(8); layout.Foldout(ref voxeland.guiSettings, "Settings"); if (voxeland.guiSettings) { Rect anchor = layout.lastRect; layout.margin += 5; layout.rightMargin += 5; layout.fieldSize = 0.4f; //data label layout.Par(5); voxeland.data = layout.ScriptableAssetField(voxeland.data, construct:null, savePath:null, fieldSize:0.8f); //margins layout.Par(5); layout.Field(ref voxeland.meshMargin, "Mesh Margin"); layout.Field(ref voxeland.ambientMargin, "Ambient Margin"); layout.Field(ref voxeland.ambientFade, "Ambient Fade", min:0, max:1); layout.Field(ref voxeland.normalsSmooth, "Smooth Normals", min:0, max:5); layout.Field(ref voxeland.relaxStrength, "Relax Strength", min:0, max:3); layout.Field(ref voxeland.relaxIterations, "Relax Iterations", min:0, max:10); if (voxeland.relaxIterations > voxeland.meshMargin) { layout.Par(30); layout.Label("Consider using Mesh Margin value higher than Relax Iterations to avoid visible seams between chunks.", rect:layout.Inset(), helpbox:true); } layout.Field(ref voxeland.channelEncoding, "Mesh Channel Encoding"); layout.Field(ref voxeland.useAmbient, "Use Ambient"); layout.Field(ref voxeland.playmodeEdit, "Edit in Playmode"); //threads layout.Par(5); layout.Field(ref ThreadWorker.multithreading, "Multithreading"); if (ThreadWorker.multithreading) { layout.Par(); layout.Field(ref ThreadWorker.maxThreads, "Max Threads", rect:layout.Inset(0.75f), fieldSize:0.2f, disabled:ThreadWorker.autoMaxThreads); layout.Toggle(ref ThreadWorker.autoMaxThreads, "Auto",rect:layout.Inset(0.25f)); } else layout.Field(ref ThreadWorker.maxThreads, "Max Coroutines"); layout.Field(ref ThreadWorker.maxApplyTime, "Max Apply Time"); //other layout.Par(5); layout.Field(ref voxeland.guiLockSelection, "Lock Selection"); layout.Field(ref voxeland.guiHideWireframe, "Hide Frame"); if (layout.lastChange) voxeland.transform.ToggleDisplayWireframe(!voxeland.guiHideWireframe); layout.Field(ref voxeland.hideColliderWire, "Hide Collider Wire"); layout.Field(ref voxeland.brush.maxExtent, "Max Brush Size"); if (voxeland.brush.maxExtent>8) { layout.Par(30); layout.Label("Large brush extent can slow down Blob Brush display", layout.Inset(), helpbox:true); } layout.Par(5); layout.Field(ref voxeland.saveMeshes, "Save Meshes with Scene"); layout.Field(ref voxeland.saveNonpinnedAreas, "Save Non-pinned Areas"); layout.Par(5); layout.Field(ref voxeland.chunkName, "Default Chunk Name"); layout.Field(ref voxeland.copyLayersTags, "Copy Layers and Tags to Chunk"); layout.Field(ref voxeland.copyComponents, "Copy Components to Chunk"); //horizon layout.Par(10); layout.Par(0,padding:0); layout.Inset(); Rect internalAnchor = layout.lastRect; bool useHorizon = layout.Toggle(voxeland.horizon!=null, "Horizon Mesh"); if (useHorizon && voxeland.horizon==null) { voxeland.horizon = Horizon.Create(voxeland); voxeland.horizon.meshRenderer.sharedMaterial = voxeland.farMaterial; voxeland.landTypes.ApplyToMaterial(voxeland.farMaterial, horizon:true); } if (!useHorizon && voxeland.horizon!=null) GameObject.DestroyImmediate(voxeland.horizon.gameObject); if (voxeland.horizon!=null) { voxeland.horizon.meshFilter.sharedMesh = layout.Field(voxeland.horizon.meshFilter.sharedMesh, "Mesh"); layout.Field(ref voxeland.horizon.meshSize, "Mesh Bounding Box Size"); layout.Field(ref voxeland.horizon.scale, "Scale"); layout.Field(ref voxeland.horizon.textureResolutions, "Texture Resolution"); } else { layout.Field<Mesh>(null, "Mesh", disabled:true); layout.Field(60, "Mesh Bounding Box Size", disabled:true); layout.Field(1, "Scale", disabled:true); layout.Field(512, "Texture Resolution", disabled:true); } layout.Foreground(internalAnchor); //floaty origin solution layout.Par(10); layout.Par(0,padding:0); layout.Inset(); internalAnchor = layout.lastRect; layout.Toggle(ref voxeland.shift, "Shift World (Floating Point Solution)"); layout.Field(ref voxeland.shiftThreshold, "Shift Threshold", disabled:!voxeland.shift); layout.Foreground(internalAnchor); //debug BuildTargetGroup buildGroup = EditorUserBuildSettings.selectedBuildTargetGroup; string defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildGroup); bool debug = false; if (defineSymbols.Contains("WDEBUG;") || defineSymbols.EndsWith("WDEBUG")) debug = true; layout.Par(10); layout.Toggle(ref debug, "Debug (Requires re-compile)"); if (layout.lastChange) { if (debug) { defineSymbols += (defineSymbols.Length!=0? ";" : "") + "WDEBUG"; } else { defineSymbols = defineSymbols.Replace("WDEBUG",""); defineSymbols = defineSymbols.Replace(";;", ";"); } PlayerSettings.SetScriptingDefineSymbolsForGroup(buildGroup, defineSymbols); } layout.margin -= 5; layout.rightMargin -= 5; layout.Foreground(anchor); } #endregion #region Material layout.Par(8); layout.Foldout(ref voxeland.guiMaterial, "Materials"); if (voxeland.guiMaterial) { Rect anchor = layout.lastRect; layout.margin += 10; layout.fieldSize = 0.5f; layout.AssetNewSaveField(ref voxeland.material, "Land", saveFilename:"Land", saveType:"mat", create:Voxeland.GetDefaultLandMaterial); layout.AssetNewSaveField(ref voxeland.farMaterial, "Horizon", saveFilename:"Horizon", saveType:"mat", create:Voxeland.GetDefaultFarMaterial); layout.AssetNewSaveField(ref voxeland.grassMaterial, "Grass", saveFilename:"Grass.mat", saveType:"mat", create:Voxeland.GetDefaultGrassMaterial); if (voxeland.highlight!=null) layout.AssetNewSaveField(ref voxeland.highlight.material, "Highlight", saveFilename:"Highlight.mat", saveType:"mat", create:Voxeland.GetDefaultHighlightMaterial); else layout.Field<Material>(null, "Highlight", disabled:true); layout.margin -= 10; layout.Foreground(anchor); //if (voxeland.guiMaterial) layout.Par(3); } #endregion #region Generate layout.Par(8); layout.Foldout(ref voxeland.guiGenerate, "Generate"); if (voxeland.guiGenerate) { Rect anchor = layout.lastRect; layout.margin += 10; if (voxeland.data == null) layout.Label("No proper Voxeland data to generate"); else { Generator generator = voxeland.data.generator; bool change = layout.change; layout.change = false; layout.Field(ref generator.generatorType, "Generator Type"); //gathering block names if (blockNames == null || blockNames.Length != voxeland.landTypes.array.Length+2) blockNames = new string[voxeland.landTypes.array.Length+2]; for (int i=0; i<voxeland.landTypes.array.Length; i++) blockNames[i] = voxeland.landTypes.array[i].name; blockNames[blockNames.Length-1] = "Empty"; if (objectNames == null || objectNames.Length != voxeland.objectsTypes.array.Length+2) objectNames = new string[voxeland.objectsTypes.array.Length+2]; for (int i=0; i<voxeland.objectsTypes.array.Length; i++) objectNames[i] = voxeland.objectsTypes.array[i].name; objectNames[objectNames.Length-1] = "Empty"; if (grassNames == null || grassNames.Length != voxeland.grassTypes.array.Length+2) grassNames = new string[voxeland.grassTypes.array.Length+2]; for (int i=0; i<voxeland.grassTypes.array.Length; i++) grassNames[i] = voxeland.grassTypes.array[i].name; grassNames[grassNames.Length-1] = "Empty"; layout.Par(10); if (generator.generatorType == Generator.GeneratorType.Planar) { generator.planarGen.OnGUI(layout, blockNames); } if (generator.generatorType == Generator.GeneratorType.Noise) { generator.noiseGen.OnGUI(layout, blockNames, "Noise"); generator.curveGen.OnGUI(layout, blockNames); generator.slopeGen.OnGUI(layout, blockNames); generator.cavityGen.OnGUI(layout, blockNames); generator.blurGen.OnGUI(layout, blockNames); generator.stainsGen.OnGUI(layout, blockNames); generator.noiseGenB.OnGUI(layout, blockNames, "Bedrock (Noise)"); generator.scatterGen.OnGUI(layout, objectNames, blockNames); //grass generator.grassGens.grassNames = grassNames; generator.grassGens.landNames = blockNames; layout.LayerButtons(generator.grassGens, generator.grassGens.gens.Length, "Grass Generators:", addBeforeSelected:true); layout.margin += 3; layout.rightMargin += 1; //right margin is 3 by default layout.Par(3); for (int num=0; num<generator.grassGens.gens.Length; num++) layout.Layer(generator.grassGens, num); layout.Par(3); layout.margin -= 3; layout.rightMargin -= 1; } else if (generator.generatorType == Generator.GeneratorType.MapMagic) { #if MAPMAGIC MapMagic.VoxelandOutput.voxeland = voxeland; MapMagic.VoxelandGrassOutput.voxeland = voxeland; MapMagic.VoxelandObjectsOutput.voxeland = voxeland; //data field layout.Par(5); layout.fieldSize = 0.7f; //generator.mapMagicGens = layout.ScriptableAssetField(generator.mapMagicGens, construct:MapMagic.GeneratorsAsset.DefaultVoxeland, savePath: null); generator.mapMagicGens = layout.ScriptableAssetField(generator.mapMagicGens, construct:MapMagic.Graph.DefaultVoxeland, savePath: null); if (layout.lastChange) MapMagic.MapMagicWindow.Show(generator.mapMagicGens, voxeland, forceOpen:false, asBiome:false); //show editor button layout.Par(5); layout.Par(22); if (layout.Button("Show Editor", rect:layout.Inset(1f), disabled:generator.mapMagicGens==null)) MapMagic.MapMagicWindow.Show(generator.mapMagicGens, voxeland, forceOpen:true); #else layout.Par(40); layout.Label("MapMagic World Generator does not seems to be installed. If you sure that you have it try restarting Unity to add it's define symbol.", rect:layout.Inset(), helpbox:true); #endif } else if (generator.generatorType == Generator.GeneratorType.Heightmap) { generator.standaloneHeightGen.OnGUI(layout, blockNames); } if (generator.generatorType != Generator.GeneratorType.Planar) { layout.Par(10); layout.Field(ref generator.seed, "Seed"); if (layout.lastChange) generator.change = true; #if MAPMAGIC if (layout.lastChange) voxeland.ClearResults(); #endif layout.Field(ref generator.heightFactor, "Height"); if (layout.lastChange) generator.change = true; layout.Toggle(ref generator.saveResults, "Save Interim Results"); layout.Toggle(ref generator.instantGenerate,"Instant Generate"); //layout.Toggle(ref generator.forceGenerateChangedAreas, "Force Generate Changed Areas"); layout.Toggle(ref generator.polish, "Polish"); //layout.Toggle(ref generator.leaveDemoUntouched, "Leave Demo Untouched"); layout.Par(); layout.Toggle(ref generator.removeThinLayers, "Remove Thin Layers", rect:layout.Inset(0.8f)); layout.Field(ref generator.minLayerThickness, rect:layout.Inset(0.2f)); if (layout.change) voxeland.Refresh(); layout.change = change; } layout.Par(5); string readyIcon = "Voxeland_Success"; int readyAnimFrames = 0; if (ThreadWorker.IsWorking("VoxelandGenerate")) { readyIcon = "Voxeland_Loading"; readyAnimFrames=12; Repaint(); } layout.Par(24); if (layout.Button("Generate", rect:layout.Inset(), icon:readyIcon, iconAnimFrames:readyAnimFrames)) voxeland.Refresh(); if (layout.Button("Force Re-Generate") && EditorUtility.DisplayDialog("Re-Generate", "This will remove all of the custom changes made in your DATA file. Are you sure you wish to continue?", "Re-Generate", "Cancel")) voxeland.Refresh(force:true); } layout.margin -= 10; layout.Foreground(anchor); } #endregion #region About layout.Par(8); layout.Foldout(ref voxeland.guiAbout, "About"); if (voxeland.guiAbout) { Rect anchor = layout.lastRect; Rect savedCursor = layout.cursor; layout.margin = 20; layout.Par(100, padding:0); layout.Icon("VoxelandIcon", layout.Inset(50,padding:0)); layout.cursor = savedCursor; layout.margin = 80; string versionName = Voxeland.version.ToString(); versionName = versionName[0]+"."+versionName[1]+"."+versionName[2]; layout.Label("Voxeland " + versionName); layout.Label("by Denis Pahunov"); layout.Par(10); layout.Label(" - Wiki", url:"https://gitlab.com/denispahunov/voxeland/wikis/home"); layout.Label(" - Forums", url:"https://forum.unity3d.com/threads/voxeland-voxel-terrain-tool.187741/"); layout.Label(" - Issues / Ideas", url:"https://gitlab.com/denispahunov/voxeland/issues"); /*layout.Par(10); layout.Label("Other Products:"); layout.Par(5); layout.Label("MapMagic", url:"https://gitlab.com/denispahunov/voxeland/wikis/home"); layout.Label("Node based infinite terrain generator");*/ layout.Foreground(anchor); } #endregion Layout.SetInspectorRect(layout.field); }
public void SwitchLayers(int num1, int num2) { ArrayTools.Switch(gens, num1, num2); }
public void RemoveLayer(int num) { ArrayTools.RemoveAt(ref gens, num); }
public void AddLayer(int num) { ArrayTools.Insert(ref gens, num, new GrassGenerator()); }
static public void ErosionIteration(Matrix heights, Matrix erosion, Matrix sedimentSum, CoordRect area = new CoordRect(), float erosionDurability = 0.9f, float erosionAmount = 1f, float sedimentAmount = 0.5f, int erosionFluidityIterations = 3, float ruffle = 0.1f, Matrix torrents = null, Matrix sediments = null, int[] stepsArray = null, int[] heightsInt = null, int[] order = null) { if (area.isZero) { area = heights.rect; } int count = heights.count; #region Creating order array int steps = 1000000; //creating int-type copy of heights if (heightsInt == null) { heightsInt = new int[count]; } for (int i = 0; i < heights.count; i++) { heightsInt[i] = (int)(Mathf.Clamp01(heights.array[i]) * steps); //TODO replace fn call } //order array if (order == null) { order = new int[count]; } order = ArrayTools.Order(heightsInt, order: order, max: heights.count, stepsArray: stepsArray); /*if (order==null) order = new int[count]; * for (int i=0; i<order.Length; i++) order[i] = i; * float[] refHeights = new float[heights.array.Length]; * Array.Copy(heights.array, refHeights, heights.array.Length); * Array.Sort(refHeights, order);*/ //setting out-of-area order num to negative for (int j = 0; j < heights.count; j++) { int pos = order[j]; Coord coord = heights.rect.CoordByNum(pos); if (!area.CheckInRangeAndBounds(coord)) { order[j] = -1; } } #endregion #region Creating torrents if (torrents == null) { torrents = new Matrix(heights.rect); } torrents.ChangeRect(heights.rect); torrents.Fill(1f); //casting initial rain for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } /* * MooreCross height = new MooreCross(heights, pos); //moore * MooreCross torrent = new MooreCross(torrents, pos); //moore * if (torrent.c > 2000000000) torrent.c = 2000000000; * * //creating torrents * MooreCross delta = new MooreCross(height); //moore * delta.SubtractInverse(height.c); * delta.ClampPositive(); * * delta.Percent(); //every side now determines a percent - how many water should go to it * delta.Multiply(torrent.c); * torrent.Add(delta); */ //getting height values float[] m = heights.array; int i = pos; int sizeX = heights.rect.size.x; float h = m[i]; float hx = m[i - 1]; float hX = m[i + 1]; float hz = m[i - sizeX]; float hZ = m[i + sizeX]; float hxz = m[i - 1 - sizeX]; float hXz = m[i + 1 - sizeX]; float hxZ = m[i - 1 + sizeX]; float hXZ = m[i + 1 + sizeX]; //creating delta float d = h - h; float dx = h - hx; float dX = h - hX; float dz = h - hz; float dZ = h - hZ; float dxz = h - hxz; float dXz = h - hXz; float dxZ = h - hxZ; float dXZ = h - hXZ; //ignoring negative delta values d = d > 0? d : 0; dx = dx > 0? dx : 0; dX = dX > 0? dX : 0; dz = dz > 0? dz : 0; dZ = dZ > 0? dZ : 0; dxz = dxz > 0? dxz : 0; dXz = dXz > 0? dXz : 0; dxZ = dxZ > 0? dxZ : 0; dXZ = dXZ > 0? dXZ : 0; //finding percents float p = 0, px = 0, pX = 0, pz = 0, pZ = 0, pxz = 0, pXz = 0, pxZ = 0, pXZ = 0; float s = d + dx + dX + dz + dZ + dxz + dXz + dxZ + dXZ; if (s > 0.00001f) { p = d / s; px = dx / s; pX = dX / s; pz = dz / s; pZ = dZ / s; pxz = dxz / s; pXz = dXz / s; pxZ = dxZ / s; pXZ = dXZ / s; } //getting central torrent (and clamping it) float t = torrents.array[i]; if (t > 2000000000) { t = 2000000000; } //spreading central torrent according percents delta. And adding to torrents array m = torrents.array; m[i] += t * p; m[i - 1] += t * px; m[i + 1] += t * pX; m[i - sizeX] += t * pz; m[i + sizeX] += t * pZ; m[i - 1 - sizeX] += t * pxz; m[i + 1 - sizeX] += t * pXz; m[i - 1 + sizeX] += t * pxZ; m[i + 1 + sizeX] += t * pXZ; } #endregion #region Erosion if (sediments == null) { sediments = new Matrix(heights.rect); } else { sediments.ChangeRect(heights.rect); } sediments.Clear(); for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } /* * Cross height = new Cross(heights, pos); * Cross torrent = new Cross(torrents, pos); * Cross sediment = new Cross(sediments, pos); * * //erosion * float erodeLine = (height.c + height.min)/2f; //halfway between current and maximum height * * if (height.c > erodeLine) //raising soil if column is higher than eroded column * { * float raised = height.c - erodeLine; * raised = Mathf.Min(raised, raised*(torrent.c-1) * (1-erosionDurability)); //could not raise more soil than height-minHeight. //torrents always have 1 or more * raised *= erosionAmount; * * heights.array[pos] -= raised; //raising soil * height.c -= raised; * sediments.array[pos] += raised * sedimentAmount; //and saving raised to sediment * sediment.c += raised * sedimentAmount; * * if (paintErosion != null) paintErosion.array[pos] += raised * mapsFactor; //and writing to ref * } */ //getting height values float[] m = heights.array; int i = pos; int sizeX = heights.rect.size.x; float h = m[i]; float hx = m[i - 1]; float hX = m[i + 1]; float hz = m[i - sizeX]; float hZ = m[i + sizeX]; //height minimum float h_min = h; if (hx < h_min) { h_min = hx; } if (hX < h_min) { h_min = hX; } if (hz < h_min) { h_min = hz; } if (hZ < h_min) { h_min = hZ; } //erosion line float erodeLine = (h + h_min) / 2f; //halfway between current and maximum height if (h < erodeLine) { continue; } //raising soil float raised = h - erodeLine; float maxRaised = raised * (torrents.array[pos] - 1) * (1 - erosionDurability); if (raised > maxRaised) { raised = maxRaised; } raised *= erosionAmount; //saving arrays heights.array[pos] -= raised; sediments.array[pos] += raised * sedimentAmount; //sedimentSum.array[pos] += sediments.array[pos] * 10; if (erosion != null) { erosion.array[pos] += raised; //and writing to ref } } #endregion #region Settling sediment for (int l = 0; l < erosionFluidityIterations; l++) { for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } //getting height values float[] m = heights.array; int sizeX = heights.rect.size.x; float h = m[pos]; float hx = m[pos - 1]; float hX = m[pos + 1]; float hz = m[pos - sizeX]; float hZ = m[pos + sizeX]; //getting sediment values m = sediments.array; float s = m[pos]; float sx = m[pos - 1]; float sX = m[pos + 1]; float sz = m[pos - sizeX]; float sZ = m[pos + sizeX]; //sediment sum float sum = s + sx + sX + sz + sZ; if (sum < 0.00001f) { continue; } //pouring sum to all cells float sedimentFifth = sum / 5; s = sedimentFifth; sx = sedimentFifth; sX = sedimentFifth; sz = sedimentFifth; sZ = sedimentFifth; //levelling //for (int i=0; i<2; i++) //{ //x line float avg = (h + s + sx + hx) / 2; if (h + s > hx + sx) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sx += transfer; } else { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; s += transfer; } avg = (hx + sx + sX + hX) / 2; if (hx + sx > hX + sX) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sX += transfer; } else { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sx += transfer; } avg = (h + s + sX + hX) / 2; if (h + s > hX + sX) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sX += transfer; } else { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; s += transfer; } //z line avg = (h + s + sz + hz) / 2; if (h + s > hz + sz) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; s += transfer; } avg = (hZ + sZ + sz + hz) / 2; if (hZ + sZ > hz + sz) { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sZ += transfer; } avg = (h + s + sz + hz) / 2; if (h + s > hz + sz) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; s += transfer; } //side pairs avg = (hx + sx + sz + hz) / 2; if (hx + sx > hz + sz) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sx += transfer; } avg = (hX + sX + sZ + hZ) / 2; if (hX + sX > hZ + sZ) { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sZ += transfer; } else { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sX += transfer; } avg = (hx + sx + sZ + hZ) / 2; if (hx + sx > hZ + sZ) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sZ += transfer; } else { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sx += transfer; } avg = (hX + sX + sz + hz) / 2; if (hX + sX > hz + sz) { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sX += transfer; } //} //to matrix m = sediments.array; m[pos] = s; m[pos - 1] = sx; m[pos + 1] = sX; m[pos - sizeX] = sz; m[pos + sizeX] = sZ; if (sedimentSum != null) { m = sedimentSum.array; m[pos] += s; m[pos - 1] += sx; m[pos + 1] += sX; m[pos - sizeX] += sz; m[pos + sizeX] += sZ; } } } #endregion #region Writing sediments back to height, adding smooth and ruffle int seed = 12345; for (int j = heights.array.Length - 1; j >= 0; j--) { //writing heights heights.array[j] += sediments.array[j]; seed = 214013 * seed + 2531011; float random = ((seed >> 16) & 0x7FFF) / 32768f; int pos = order[j]; if (pos < 0) { continue; } float[] m = heights.array; int sizeX = heights.rect.size.x; float h = m[pos]; float hx = m[pos - 1]; float hX = m[pos + 1]; float hz = m[pos - sizeX]; float hZ = m[pos + sizeX]; //smoothing sediments a bit float s = sediments.array[pos]; if (s > 0.0001f) { float smooth = s / 2f; if (smooth > 0.75f) { smooth = 0.75f; } heights.array[pos] = h * (1 - smooth) + (hx + hX + hz + hZ) / 4f * smooth; } else { float maxHeight = hx; if (hX > maxHeight) { maxHeight = hX; } if (hz > maxHeight) { maxHeight = hz; } if (hZ > maxHeight) { maxHeight = hZ; } float minHeight = hx; if (hX < minHeight) { minHeight = hX; } if (hz < minHeight) { minHeight = hz; } if (hZ < minHeight) { minHeight = hZ; } float randomHeight = random * (maxHeight - minHeight) + minHeight; heights.array[pos] = heights.array[pos] * (1 - ruffle) + randomHeight * ruffle; } //Cross height = new Cross(heights, pos); //float maxAround = Mathf.Max(heights.array[pos-1], heights.array[pos+1], heights.array[pos-heights.rect.size.x], heights.array[pos+heights.rect.size.x]); //heights.array[pos] = Mathf.Min(heights.array[pos], maxAround); //heights.array[pos] = Mathf.Min(height.c, height.maxAround); //heights.array[pos] = Mathf.Min(height.c, height.avgAround)*0.5f + height.c*0.5f; //float maxHeight = height.maxAround; //float minHeight = height.minAround; //float randomHeight = random*(maxHeight-minHeight) + minHeight; //heights.array[pos] = heights.array[pos]*(1-ruffle) + randomHeight*ruffle; } #endregion } //erosion iteration
public static void SetUserData(this UnityEditor.AssetImporter importer, string param, string[] data, bool reload = false) { char endline = '\n'; //';' string userData = importer.userData; string[] userDataSplit = userData.Split('\n', ';'); //preparing new data line if (data == null) { data = new string[0]; } string newDataString = param + ":" + data.ToStringMemberwise(separator: ","); //param line number (-1 if not found) int numInSplit = -1; for (int i = 0; i < userDataSplit.Length; i++) { if (userDataSplit[i].StartsWith(param + ":")) { numInSplit = i; } } //erasing empty data if (numInSplit >= 0 && data.Length == 0) { ArrayTools.RemoveAt(ref userDataSplit, numInSplit); } //replacing line if (numInSplit >= 0 && data.Length != 0) { userDataSplit[numInSplit] = newDataString; } //adding new line if (numInSplit == -1 && data.Length != 0) { ArrayTools.Add(ref userDataSplit, newDataString); } //to string string newUserData = ""; for (int i = 0; i < userDataSplit.Length; i++) { if (userDataSplit[i].Length == 0) { continue; } newUserData += userDataSplit[i]; if (i != userDataSplit.Length - 1) { newUserData += endline; } } //writing if (newUserData != userData) { importer.userData = newUserData; UnityEditor.EditorUtility.SetDirty(importer); UnityEditor.AssetDatabase.WriteImportSettingsIfDirty(importer.assetPath); if (reload) { UnityEditor.AssetDatabase.Refresh(); } } }