public static FinalizeAction finalizeAction = Finalize; //class identified for FinalizeData public static void Finalize(TileData data, StopToken stop) { //blending all biomes in data.height matrix if (data.heights == null || data.heights.rect.size != data.area.full.rect.size || data.heights.worldPos != data.area.full.worldPos || data.heights.worldSize != data.area.full.worldSize) { data.heights = new MatrixWorld(data.area.full.rect, data.area.full.worldPos, data.area.full.worldSize, data.globals.height); } data.heights.worldSize.y = data.globals.height; data.heights.Fill(0); foreach ((HeightOutput200 output, MatrixWorld product, MatrixWorld biomeMask) in data.finalize.ProductSets <HeightOutput200, MatrixWorld, MatrixWorld>(finalizeAction, data.subDatas)) { if (stop != null && stop.stop) { return; } for (int a = 0; a < data.heights.arr.Length; a++) { float val = product.arr[a]; float biomeVal = biomeMask != null ? biomeMask.arr[a] : 1; data.heights.arr[a] += val * biomeVal; } } //creating upscaled/blurred height matrix Interpolation interpolation = data.globals.heightInterpolation; Matrix matrix = GetInterpolated(data.heights, interpolation); //determining resolutions int upscale = matrix.rect.size.x / data.heights.rect.size.x; int margins = data.area.Margins * upscale; int res = matrix.rect.size.x - margins * 2; int splitSize = data.globals.heightSplit; int numSplits = res / splitSize; if (res % splitSize != 0) { numSplits++; } //getting apply data ApplyType applyType = data.isDraft ? data.globals.heightDraftApply : data.globals.heightMainApply; IApplyData applyData; if (applyType == ApplyType.SetHeights) { float[,] heights2Dfull = new float[res, res]; matrix.ExportHeights(heights2Dfull, matrix.rect.offset + margins); applyData = new ApplySetData() { heights2D = heights2Dfull, height = data.globals.height }; } else if (applyType == ApplyType.SetHeightsDelayLOD) { float[][,] height2DSplits = new float[numSplits][, ]; int offset = 0; for (int i = 0; i < numSplits; i++) { int spaceLeft = res - offset; int currSplitSize = Mathf.Min(splitSize, res - offset); float[,] heights2D = new float[currSplitSize, res]; Coord heights2Dcoord = new Coord( matrix.rect.offset.x + margins, matrix.rect.offset.z + margins + offset); matrix.ExportHeights(heights2D, heights2Dcoord); height2DSplits[i] = heights2D; offset += currSplitSize; } applyData = new ApplySplitData() { heights2DSplits = height2DSplits, height = data.globals.height }; } #if UNITY_2019_1_OR_NEWER else //if TextureToHeightmap { byte[] bytes = new byte[res * res * 4]; matrix.ExportRawFloat(bytes, matrix.rect.offset + margins, new Coord(res, res), mult: 0.5f); //not coord(margins) since matrix rect has -margins offset //somehow requires halved values applyData = new ApplyTexData() { res = res, margins = margins, splitSize = splitSize, height = data.globals.height, texBytes = bytes }; }
public static FinalizeAction finalizeAction = Finalize; //class identified for FinalizeData public static void Finalize(TileData data, StopToken stop) { //blending all biomes in data.height matrix if (data.heights == null || data.heights.rect.size != data.area.full.rect.size || data.heights.worldPos != (Vector3)data.area.full.worldPos || data.heights.worldSize != (Vector3)data.area.full.worldSize) { data.heights = new MatrixWorld(data.area.full.rect, data.area.full.worldPos, data.area.full.worldSize, data.globals.height); } data.heights.worldSize.y = data.globals.height; data.heights.Fill(0); foreach ((HeightOutput200 output, MatrixWorld product, MatrixWorld biomeMask) in data.Outputs <HeightOutput200, MatrixWorld, MatrixWorld> (typeof(HeightOutput200), inSubs:true)) { if (data.heights == null) //height output not generated or received null result { return; } for (int a = 0; a < data.heights.arr.Length; a++) { if (stop != null && stop.stop) { return; } float val = product.arr[a]; float biomeVal = biomeMask != null ? biomeMask.arr[a] : 1; data.heights.arr[a] += val * biomeVal; } } //determining resolutions if (stop != null && stop.stop) { return; } Interpolation interpolation = data.globals.heightInterpolation; int upscale = GetUpscale(interpolation); int margins = data.area.Margins; int matrixRes = (data.heights.rect.size.x - margins * 2 - 1) * upscale + margins * 2 * upscale + 1; //creating upscaled/blurred height matrix if (stop != null && stop.stop) { return; } Matrix matrix; switch (interpolation) { default: matrix = data.heights; break; case Interpolation.Smooth: matrix = new Matrix(data.heights); MatrixOps.GaussianBlur(matrix, 0.5f); break; //case Interpolation.Scale2X: // matrix = new Matrix( new CoordRect(data.heights.rect.offset, new Coord(matrixRes)) ); // MatrixOps.UpscaleFast(data.heights, matrix); // MatrixOps.GaussianBlur(matrix, 0.5f); //upscaleFast interpolates linear, so each new vert is exactly between the old ones // break; //nah, summary effect is better with classic resize case Interpolation.Scale4X: case Interpolation.Scale2X: matrix = new Matrix(new CoordRect(data.heights.rect.offset, new Coord(matrixRes))); MatrixOps.Resize(data.heights, matrix); break; } //clamping heights to 0-1 (otherwise culing issues can occur) matrix.Clamp01(); //2Darray resolution and int arrRes = matrix.rect.size.x - margins * upscale * 2; //splits number (used for SetHeightsDelayLOD and Texture) int splitSize = data.globals.heightSplit; int numSplits = arrRes / splitSize; if (arrRes % splitSize != 0) { numSplits++; } //getting apply data ApplyType applyType = data.isDraft ? data.globals.heightDraftApply : data.globals.heightMainApply; IApplyData applyData; if (applyType == ApplyType.SetHeights) { float[,] heights2Dfull = new float[arrRes, arrRes]; matrix.ExportHeights(heights2Dfull, matrix.rect.offset + margins * upscale); applyData = new ApplySetData() { heights2D = heights2Dfull, height = data.globals.height }; } else if (applyType == ApplyType.SetHeightsDelayLOD) { float[][,] height2DSplits = new float[numSplits][, ]; int offset = 0; for (int i = 0; i < numSplits; i++) { int spaceLeft = arrRes - offset; int currSplitSize = Mathf.Min(splitSize, arrRes - offset); float[,] heights2D = new float[currSplitSize, arrRes]; Coord heights2Dcoord = new Coord( matrix.rect.offset.x + margins * upscale, matrix.rect.offset.z + margins * upscale + offset); matrix.ExportHeights(heights2D, heights2Dcoord); height2DSplits[i] = heights2D; offset += currSplitSize; } applyData = new ApplySplitData() { heights2DSplits = height2DSplits, height = data.globals.height }; } #if UNITY_2019_1_OR_NEWER else //if TextureToHeightmap { byte[] bytes = new byte[arrRes * arrRes * 4]; float ushortEpsilon = 1f / 65535; //since setheights is using not full ushort range, but range-1 matrix.ExportRawFloat(bytes, matrix.rect.offset + margins * upscale, new Coord(arrRes, arrRes), mult: 0.5f - ushortEpsilon); //not coord(margins) since matrix rect has -margins offset //somehow requires halved values applyData = new ApplyTexData() { res = arrRes, margins = margins, splitSize = splitSize, height = data.globals.height, texBytes = bytes }; }