private BiomeCenter GenerateBiomeCenter(SectionCoord coord) { BiomeCenter center = new BiomeCenter(); center.coord = coord; NotRandom.RNG rng = new NotRandom.RNG(NotRandom.Hash2Int(seedHash, center.coord.GetHashCode())); float nx = center.coord.x * biomeCenterSpacing + ((rng.Value() * maxBiomeCenterOffset * 2) - maxBiomeCenterOffset); float nz = center.coord.z * biomeCenterSpacing + ((rng.Value() * maxBiomeCenterOffset * 2) - maxBiomeCenterOffset); center.center = new Vector3(nx, 1f, nz); int index = (int)(rng.ValueUInt() % totalBiomeFrequency); for (int i = 0; i < biomes.Count; i++) { if (index >= 0 && index < biomes[i].relativeFrequency) { center.biome = biomes[i]; break; } index -= biomes[i].relativeFrequency; } return(center); }
private void CalculateBiomeBounds(SectionCoord coord) { BiomeCenter target = SafeGetBiomeCenter(coord); if (target.boundsCalculated) { return; } List <BiomeCenter> neighbors = new List <BiomeCenter>(); List <SectionCoord> coords; Dictionary <SectionCoord, Plane> properBounds = new Dictionary <SectionCoord, Plane>(); List <Plane> weakBounds = new List <Plane>(); Plane plane; Vector3 self = target.center; Vector3 other, middle; coords = SectionsInRadius(coord, 2.75f); for (int i = 1; i < coords.Count; i++) { neighbors.Add(SafeGetBiomeCenter(coords[i])); } for (int i = 0; i < neighbors.Count; i++) { other = neighbors[i].center; middle = (self + other) / 2f; if (neighbors[i].boundsCalculated) { plane = neighbors[i].properBounds[coord].flipped; properBounds.Add(neighbors[i].coord, plane); } else { plane = new Plane((self - other).normalized, middle); properBounds.Add(neighbors[i].coord, plane); } weakBounds.Add(new Plane(plane.normal, middle - plane.normal * (biomeBlend / 2f))); } SimplifyConvexPlanes(weakBounds, self); lock (target) { if (!target.boundsCalculated) { target.properBounds = properBounds; target.weakBounds = weakBounds; target.boundsCalculated = true; } } }
public List <BiomeStrength> GetBiomes(Vector3 vLoc) { List <BiomeStrength> output = new List <BiomeStrength>(biomes.Count); Vector3 loc = new Vector3(vLoc.x, 0f, vLoc.z); Vector3 biomeLoc = loc / biomeCenterSpacing; SectionCoord coord = new SectionCoord(Mathf.RoundToInt(biomeLoc.x), Mathf.RoundToInt(biomeLoc.z)); BiomeCenter center = SafeGetBiomeCenter(coord); float weakDist, dist, totalStrength; if (!center.boundsCalculated) { CalculateBiomeBounds(coord); } weakDist = Mathf.Infinity; for (int k = 0; weakDist > biomeBlend && k < center.weakBounds.Count; k++) { dist = center.weakBounds[k].GetDistanceToPoint(loc); if (dist < weakDist) { weakDist = dist; } } if (weakDist > biomeBlend) { output.Add(new BiomeStrength(center.biome, 1f)); return(output); } List <SectionCoord> coords = SectionsInRadius(coord, 2.75f); for (int i = 0; i < coords.Count; i++) { center = SafeGetBiomeCenter(coords[i]); if (!center.boundsCalculated) { CalculateBiomeBounds(coords[i]); } weakDist = Mathf.Infinity; for (int k = 0; weakDist >= 0.0f && k < center.weakBounds.Count; k++) { dist = center.weakBounds[k].GetDistanceToPoint(loc); if (dist < weakDist) { weakDist = dist; } } if (weakDist > biomeBlend) { output.Clear(); output.Add(new BiomeStrength(center.biome, 1f)); return(output); } if (weakDist >= 0.0f) { int j = 0; for (; j < output.Count; j++) { if (output[j].biome == center.biome) { output[j].strength += (weakDist / biomeBlend); break; } } if (j == output.Count) { output.Add(new BiomeStrength(center.biome, weakDist / biomeBlend)); } } } totalStrength = 0f; for (int i = 0; i < output.Count; i++) { output[i].strength = Mathf.Pow(Mathf.Clamp01(output[i].strength), 2f); totalStrength += output[i].strength; } for (int i = 0; i < output.Count; i++) { output[i].strength /= totalStrength; } return(output); }
private IEnumerator GenerateSection_CR(SectionCoord coord) { TerrainSection sec; if (terrains.TryGetValue(coord, out sec) && sec != null && sec.terrain != null) { if (numGenThreads > 0) { numGenThreads--; } yield break; } if (sec == null) { sec = new TerrainSection(coord); } float[,] heightmap = null; float[,,] alphamaps = null; int bx, bz; float height; Vector3 targLoc; GameObject go; BiomeData bd; List <SectionCoord> biomeCenters; List <Biome> containedBiomes = null; List <DetailPrototypeData> detailPrototypeDatas = null; List <int[, ]> detailMaps = null; List <TreePrototypeData> treePrototypeDatas = null; List <TreeInstance> treeInstances = null; Thread heightThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Heightmap", "" + coord.x + ":" + coord.z); #endif heightmap = GenerateHeightmap(coord); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); Thread alphaThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Alphamap", "" + coord.x + ":" + coord.z); #endif alphamaps = GenerateAlphamaps(coord, out containedBiomes); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); Thread detailThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Detailmap", "" + coord.x + ":" + coord.z); #endif detailMaps = GenerateDetailMaps(coord, out detailPrototypeDatas); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); Thread treeThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Treemap", "" + coord.x + ":" + coord.z); #endif treeInstances = GenerateTreeInstances(coord, out treePrototypeDatas); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); yield return(null); treeThread.Start(); yield return(null); heightThread.Start(); yield return(null); alphaThread.Start(); yield return(null); detailThread.Start(); yield return(new WaitUntil(() => (heightmap != null && alphamaps != null && detailMaps != null && treeInstances != null && !loadingSection))); TerrainLayer[] terrainLayers = new TerrainLayer[containedBiomes.Count]; loadingSection = true; sectionLoading = coord; TerrainData data = new TerrainData(); data.heightmapResolution = genSettings.heightMapRes; yield return(null); data.alphamapResolution = genSettings.alphaMapRes; data.SetDetailResolution(genSettings.detailMapRes, genSettings.detailMapResPerPatch); data.size = new Vector3(genSettings.length, genSettings.height, genSettings.length); yield return(null); data.SetHeights(0, 0, heightmap); yield return(null); for (int i = 0; i < containedBiomes.Count; i++) { terrainLayers[i] = containedBiomes[i].terrainLayer; } DetailPrototype[] detailPrototypes = null; if (detailPrototypeDatas.Count > 0) { detailPrototypes = new DetailPrototype[detailPrototypeDatas.Count]; } for (int i = 0; i < detailPrototypeDatas.Count; i++) { DetailPrototype dp = detailPrototypes[i] = new DetailPrototype(); DetailPrototypeData dpd = detailPrototypeDatas[i]; dp.bendFactor = dpd.bendFactor; dp.dryColor = dpd.dryColor; dp.healthyColor = dpd.healthyColor; dp.maxHeight = dpd.maxHeight; dp.maxWidth = dpd.maxWidth; dp.minHeight = dpd.minHeight; dp.minWidth = dpd.minWidth; dp.noiseSpread = dpd.noiseSpread; if (dpd.prototype != null) { dp.prototype = dpd.prototype; dp.usePrototypeMesh = true; } else { dp.prototypeTexture = dpd.prototypeTexture; dp.usePrototypeMesh = false; } dp.renderMode = dpd.renderMode; } yield return(null); data.terrainLayers = terrainLayers; data.SetAlphamaps(0, 0, alphamaps); yield return(null); TreePrototype[] treePrototypes = null; if (treePrototypeDatas.Count > 0) { treePrototypes = new TreePrototype[treePrototypeDatas.Count]; } for (int i = 0; i < treePrototypeDatas.Count; i++) { TreePrototype tp = treePrototypes[i] = new TreePrototype(); tp.bendFactor = treePrototypeDatas[i].bendFactor; tp.prefab = treePrototypeDatas[i].prefab; } yield return(null); if (detailPrototypes != null) { data.detailPrototypes = detailPrototypes; yield return(null); for (int i = 0; i < detailMaps.Count; i++) { data.SetDetailLayer(0, 0, i, detailMaps[i]); } yield return(null); } if (treePrototypes != null) { data.treePrototypes = treePrototypes; yield return(null); data.SetTreeInstances(treeInstances.ToArray(), true); } yield return(null); data.RefreshPrototypes(); yield return(null); GameObject obj = Terrain.CreateTerrainGameObject(data); sec.terrain = obj.GetComponent <Terrain>(); sec.terrain.treeBillboardDistance = 150; sec.terrain.materialTemplate = terrainMaterial; sec.terrain.allowAutoConnect = true; obj.transform.position = new Vector3(coord.x * genSettings.length - genSettings.length / 2, 0f, coord.z * genSettings.length - genSettings.length / 2); yield return(null); sec.terrain.Flush(); yield return(null); bx = Mathf.RoundToInt((coord.x * genSettings.length) / biomeCenterSpacing); bz = Mathf.RoundToInt((coord.z * genSettings.length) / biomeCenterSpacing); biomeCenters = SectionsInRadius(new SectionCoord(bx, bx), 2); for (int i = 0; i < biomeCenters.Count; i++) { BiomeCenter center = SafeGetBiomeCenter(biomeCenters[i]); height = sec.terrain.SampleHeight(center.center); targLoc = new Vector3(center.center.x, height, center.center.z + sec.terrain.GetPosition().y); if (sec.terrain.terrainData.bounds.Contains(targLoc - sec.terrain.transform.position)) { if (center.biome.ambientPrefab != null) { go = Instantiate(center.biome.ambientPrefab, targLoc, Quaternion.identity, sec.terrain.transform); } else { go = new GameObject(); go.transform.position = targLoc; go.transform.parent = sec.terrain.transform; } bd = go.AddComponent <TerrainManager.BiomeData>(); bd.biome = center.biome; bd.center = targLoc; bd.boundaries = center.properBounds.Values.ToList(); SimplifyConvexPlanes(bd.boundaries, bd.center); } } yield return(null); terrains.Add(coord, sec); if (numGenThreads > 0) { numGenThreads--; } generating.Remove(coord); if (coord.Equals(sectionLoading)) { loadingSection = false; } }