public void ThreadProc(System.Object stateInfo) { DataForTask dataForTask = stateInfo as DataForTask; // Extract height samples for all chunks float baseHeight, noiseHeight; float x1, x2, x3, x4; int dim = dataForTask.HeightmapDimension; float div = dataForTask.div; float[,] baseHeightValue = dataForTask.baseHeightValue; byte[,] lhm = dataForTask.lhm; float[,] noiseHeightMultiplierMap = dataForTask.noiseHeightMultiplierMap; float extraNoiseScaleBasedOnClimate = dataForTask.extraNoiseScaleBasedOnClimate; // split the work between different tasks running in different threads (thread n computes data elements n, n + numTasks, n + numTasks*2, ...) for (int y = dataForTask.currentTask; y < dim; y += dataForTask.numTasks) { for (int x = 0; x < dim; x++) { float rx = (float)x / div; float ry = (float)y / div; int ix = Mathf.FloorToInt(rx); int iy = Mathf.FloorToInt(ry); float sfracx = (float)x / (float)(dim - 1); float sfracy = (float)y / (float)(dim - 1); float fracx = (float)(x - ix * div) / div; float fracy = (float)(y - iy * div) / div; float scaledHeight = 0; // Bicubic sample small height map for base terrain elevation x1 = TerrainHelper.CubicInterpolator(baseHeightValue[0, 3], baseHeightValue[1, 3], baseHeightValue[2, 3], baseHeightValue[3, 3], sfracx); x2 = TerrainHelper.CubicInterpolator(baseHeightValue[0, 2], baseHeightValue[1, 2], baseHeightValue[2, 2], baseHeightValue[3, 2], sfracx); x3 = TerrainHelper.CubicInterpolator(baseHeightValue[0, 1], baseHeightValue[1, 1], baseHeightValue[2, 1], baseHeightValue[3, 1], sfracx); x4 = TerrainHelper.CubicInterpolator(baseHeightValue[0, 0], baseHeightValue[1, 0], baseHeightValue[2, 0], baseHeightValue[3, 0], sfracx); baseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy); scaledHeight += baseHeight * baseHeightScale; // Bicubic sample large height map for noise mask over terrain features x1 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 0], lhm[ix + 1, iy + 0], lhm[ix + 2, iy + 0], lhm[ix + 3, iy + 0], fracx); x2 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 1], lhm[ix + 1, iy + 1], lhm[ix + 2, iy + 1], lhm[ix + 3, iy + 1], fracx); x3 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 2], lhm[ix + 1, iy + 2], lhm[ix + 2, iy + 2], lhm[ix + 3, iy + 2], fracx); x4 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 3], lhm[ix + 1, iy + 3], lhm[ix + 2, iy + 3], lhm[ix + 3, iy + 3], fracx); noiseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, fracy); x1 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 3], noiseHeightMultiplierMap[1, 3], noiseHeightMultiplierMap[2, 3], noiseHeightMultiplierMap[3, 3], sfracx); x2 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 2], noiseHeightMultiplierMap[1, 2], noiseHeightMultiplierMap[2, 2], noiseHeightMultiplierMap[3, 2], sfracx); x3 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 1], noiseHeightMultiplierMap[1, 1], noiseHeightMultiplierMap[2, 1], noiseHeightMultiplierMap[3, 1], sfracx); x4 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 0], noiseHeightMultiplierMap[1, 0], noiseHeightMultiplierMap[2, 0], noiseHeightMultiplierMap[3, 0], sfracx); float noiseHeightMultiplier = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy); scaledHeight += noiseHeight * noiseHeightMultiplier; // Additional noise mask for small terrain features at ground level // small terrain features' height scale should depend on climate of map pixel float extraNoiseScale = extraNoiseScaleBasedOnClimate; // prevent seams between different climate map pixels if (x <= 0 || y <= 0 || x >= dim - 1 || y >= dim - 1) { extraNoiseScale = defaultExtraNoiseScale; } int noisex = dataForTask.mapPixel.mapPixelX * (dataForTask.HeightmapDimension - 1) + x; int noisey = (MapsFile.MaxMapPixelY - dataForTask.mapPixel.mapPixelY) * (dataForTask.HeightmapDimension - 1) + y; float lowFreq = TerrainHelper.GetNoise(noisex, noisey, 0.3f, 0.5f, 0.5f, 1); float highFreq = TerrainHelper.GetNoise(noisex, noisey, 0.9f, 0.5f, 0.5f, 1); scaledHeight += (lowFreq * highFreq) * extraNoiseScale; // Clamp lower values to ocean elevation if (scaledHeight < scaledOceanElevation) { scaledHeight = scaledOceanElevation; } // Set sample float height = Mathf.Clamp01(scaledHeight / dataForTask.MaxTerrainHeight); dataForTask.mapPixel.heightmapSamples[y, x] = height; } } _doneEvent.Set(); }
public void Execute(int index) { // Use cols=x and rows=y for height data int x = JobA.Col(index, hDim); int y = JobA.Row(index, hDim); float rx = (float)x / div; float ry = (float)y / div; int ix = Mathf.FloorToInt(rx); int iy = Mathf.FloorToInt(ry); float sfracx = (float)x / (float)(hDim - 1); float sfracy = (float)y / (float)(hDim - 1); float fracx = (float)(x - ix * div) / div; float fracy = (float)(y - iy * div) / div; float scaledHeight = 0; // Bicubic sample small height map for base terrain elevation x1 = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 3, sd)], baseHeightValue[JobA.Idx(1, 3, sd)], baseHeightValue[JobA.Idx(2, 3, sd)], baseHeightValue[JobA.Idx(3, 3, sd)], sfracx); x2 = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 2, sd)], baseHeightValue[JobA.Idx(1, 2, sd)], baseHeightValue[JobA.Idx(2, 2, sd)], baseHeightValue[JobA.Idx(3, 2, sd)], sfracx); x3 = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 1, sd)], baseHeightValue[JobA.Idx(1, 1, sd)], baseHeightValue[JobA.Idx(2, 1, sd)], baseHeightValue[JobA.Idx(3, 1, sd)], sfracx); x4 = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 0, sd)], baseHeightValue[JobA.Idx(1, 0, sd)], baseHeightValue[JobA.Idx(2, 0, sd)], baseHeightValue[JobA.Idx(3, 0, sd)], sfracx); baseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy); scaledHeight += baseHeight * baseHeightScale; // Bicubic sample large height map for noise mask over terrain features x1 = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 0, ld)], lhm[JobA.Idx(ix + 1, iy + 0, ld)], lhm[JobA.Idx(ix + 2, iy + 0, ld)], lhm[JobA.Idx(ix + 3, iy + 0, ld)], fracx); x2 = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 1, ld)], lhm[JobA.Idx(ix + 1, iy + 1, ld)], lhm[JobA.Idx(ix + 2, iy + 1, ld)], lhm[JobA.Idx(ix + 3, iy + 1, ld)], fracx); x3 = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 2, ld)], lhm[JobA.Idx(ix + 1, iy + 2, ld)], lhm[JobA.Idx(ix + 2, iy + 2, ld)], lhm[JobA.Idx(ix + 3, iy + 2, ld)], fracx); x4 = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 3, ld)], lhm[JobA.Idx(ix + 1, iy + 3, ld)], lhm[JobA.Idx(ix + 2, iy + 3, ld)], lhm[JobA.Idx(ix + 3, iy + 3, ld)], fracx); noiseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, fracy); x1 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 3, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 3, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 3, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 3, sd)], sfracx); x2 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 2, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 2, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 2, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 2, sd)], sfracx); x3 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 1, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 1, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 1, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 1, sd)], sfracx); x4 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 0, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 0, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 0, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 0, sd)], sfracx); float noiseHeightMultiplier = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy); scaledHeight += noiseHeight * noiseHeightMultiplier; // Additional noise mask for small terrain features at ground level // small terrain features' height scale should depend on climate of map pixel float extraNoiseScale = extraNoiseScaleBasedOnClimate; // prevent seams between different climate map pixels if (x <= 0 || y <= 0 || x >= hDim - 1 || y >= hDim - 1) { extraNoiseScale = defaultExtraNoiseScale; } int noisex = mapPixelX * (hDim - 1) + x; int noisey = (MapsFile.MaxMapPixelY - mapPixelY) * (hDim - 1) + y; float lowFreq = TerrainHelper.GetNoise(noisex, noisey, 0.3f, 0.5f, 0.5f, 1); float highFreq = TerrainHelper.GetNoise(noisex, noisey, 0.9f, 0.5f, 0.5f, 1); scaledHeight += (lowFreq * highFreq) * extraNoiseScale; // Clamp lower values to ocean elevation if (scaledHeight < scaledOceanElevation) { scaledHeight = scaledOceanElevation; } // Set sample float height = Mathf.Clamp01(scaledHeight / maxTerrainHeight); heightmapData[index] = height; }
public override void GenerateSamples(ref MapPixelData mapPixel) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; // Create samples arrays mapPixel.tilemapSamples = new TilemapSample[MapsFile.WorldMapTileDim, MapsFile.WorldMapTileDim]; mapPixel.heightmapSamples = new float[HeightmapDimension, HeightmapDimension]; // Divisor ensures continuous 0-1 range of tile samples float div = (float)(HeightmapDimension - 1) / 3f; // Read neighbouring height samples for this map pixel int mx = mapPixel.mapPixelX; int my = mapPixel.mapPixelY; byte[,] shm = dfUnity.ContentReader.WoodsFileReader.GetHeightMapValuesRange(mx - 2, my - 2, 4); byte[,] lhm = dfUnity.ContentReader.WoodsFileReader.GetLargeHeightMapValuesRange(mx - 1, my, 3); float[,] multiplierValue = new float[4, 4]; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue)); int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue)); multiplierValue[x, y] = ImprovedWorldTerrain.computeHeightMultiplier(mapPixelX, mapPixelY); } } // Extract height samples for all chunks float averageHeight = 0; float maxHeight = float.MinValue; float baseHeight, noiseHeight; float x1, x2, x3, x4; int dim = HeightmapDimension; //mapPixel.heightmapSamples = new float[dim, dim]; for (int y = 0; y < dim; y++) { for (int x = 0; x < dim; x++) { float rx = (float)x / div; float ry = (float)y / div; int ix = Mathf.FloorToInt(rx); int iy = Mathf.FloorToInt(ry); float sfracx = (float)x / (float)(dim - 1); float sfracy = (float)y / (float)(dim - 1); float fracx = (float)(x - ix * div) / div; float fracy = (float)(y - iy * div) / div; float scaledHeight = 0; // Bicubic sample small height map for base terrain elevation x1 = TerrainHelper.CubicInterpolator(shm[0, 3] * multiplierValue[0, 3], shm[1, 3] * multiplierValue[1, 3], shm[2, 3] * multiplierValue[2, 3], shm[3, 3] * multiplierValue[3, 3], sfracx); x2 = TerrainHelper.CubicInterpolator(shm[0, 2] * multiplierValue[0, 2], shm[1, 2] * multiplierValue[1, 2], shm[2, 2] * multiplierValue[2, 2], shm[3, 2] * multiplierValue[3, 2], sfracx); x3 = TerrainHelper.CubicInterpolator(shm[0, 1] * multiplierValue[0, 1], shm[1, 1] * multiplierValue[1, 1], shm[2, 1] * multiplierValue[2, 1], shm[3, 1] * multiplierValue[3, 1], sfracx); x4 = TerrainHelper.CubicInterpolator(shm[0, 0] * multiplierValue[0, 0], shm[1, 0] * multiplierValue[1, 0], shm[2, 0] * multiplierValue[2, 0], shm[3, 0] * multiplierValue[3, 0], sfracx); baseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy); scaledHeight += baseHeight * baseHeightScale; // Bicubic sample large height map for noise mask over terrain features x1 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 0], lhm[ix + 1, iy + 0], lhm[ix + 2, iy + 0], lhm[ix + 3, iy + 0], fracx); x2 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 1], lhm[ix + 1, iy + 1], lhm[ix + 2, iy + 1], lhm[ix + 3, iy + 1], fracx); x3 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 2], lhm[ix + 1, iy + 2], lhm[ix + 2, iy + 2], lhm[ix + 3, iy + 2], fracx); x4 = TerrainHelper.CubicInterpolator(lhm[ix, iy + 3], lhm[ix + 1, iy + 3], lhm[ix + 2, iy + 3], lhm[ix + 3, iy + 3], fracx); noiseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, fracy); scaledHeight += noiseHeight * noiseMapScale; // Additional noise mask for small terrain features at ground level int noisex = mapPixel.mapPixelX * (HeightmapDimension - 1) + x; int noisey = (MapsFile.MaxMapPixelY - mapPixel.mapPixelY) * (HeightmapDimension - 1) + y; float lowFreq = TerrainHelper.GetNoise(noisex, noisey, 0.3f, 0.5f, 0.5f, 1); float highFreq = TerrainHelper.GetNoise(noisex, noisey, 0.9f, 0.5f, 0.5f, 1); scaledHeight += (lowFreq * highFreq) * extraNoiseScale; // Clamp lower values to ocean elevation if (scaledHeight < scaledOceanElevation) { scaledHeight = scaledOceanElevation; } // Accumulate average height averageHeight += scaledHeight; // Get max height if (scaledHeight > maxHeight) { maxHeight = scaledHeight; } // Set sample float height = Mathf.Clamp01(scaledHeight / MaxTerrainHeight); mapPixel.heightmapSamples[y, x] = height; } } // Average and max heights are passed back for locations mapPixel.averageHeight = (averageHeight /= (float)(dim * dim)) / MaxTerrainHeight; mapPixel.maxHeight = maxHeight / MaxTerrainHeight; }