/// <summary> /// The two parameters are the normalised (0->1) elevation and moisture values. /// </summary> /// <param name="elevationPercentage"></param> /// <param name="moisturePercentage"></param> /// <returns></returns> public int GetBiomeID(float elevationPercentage, float moisturePercentage) { //Simple linear search through elevation zones StartEndRange moisturelevels = new StartEndRange() { start = 0, end = 0 }; for (int i = 0; i < allElevationZones.Length; i++) { var zone = allElevationZones[i]; moisturelevels = zone.moistureLevels; if (elevationPercentage < zone.maxElevationPercentage) { break; } } //Simple linear search through moisture levels int biomeID = 0; for (int i = moisturelevels.start; i < moisturelevels.end; i++) { var moistureDef = allMoistureDefs[i]; biomeID = moistureDef.biomeID; if (moisturePercentage < moistureDef.maxMoisturePercentage) { break; } } return(biomeID); }
public static NativeVoxelTypeDatabase FromTypeData(List <VoxelTypeData> typeData) { List <float> zIndicesPerFaceList = new List <float>(); List <StartEndRange> voxelTypeToZIndicesRangeMapList = new List <StartEndRange>(); List <bool> voxelTypeToIsPassableMapList = new List <bool>(); //AIR voxelTypeToZIndicesRangeMapList.Add(new StartEndRange()); voxelTypeToIsPassableMapList.Add(true); for (int i = 1; i < typeData.Count; i++) { StartEndRange range = new StartEndRange(); range.start = zIndicesPerFaceList.Count; var zIndices = typeData[i].zIndicesPerFace; zIndicesPerFaceList.AddRange(zIndices); range.end = zIndicesPerFaceList.Count; voxelTypeToZIndicesRangeMapList.Add(range); voxelTypeToIsPassableMapList.Add(typeData[i].definition.isPassable); } NativeVoxelTypeDatabase database = new NativeVoxelTypeDatabase(); database.zIndicesPerFace = new NativeArray <float>(zIndicesPerFaceList.ToArray(), Allocator.Persistent); database.voxelTypeToZIndicesRangeMap = new NativeArray <StartEndRange>(voxelTypeToZIndicesRangeMapList.ToArray(), Allocator.Persistent); database.voxelTypeToIsPassableMap = new NativeArray <bool>(voxelTypeToIsPassableMapList.ToArray(), Allocator.Persistent); return(database); }
/// <summary> /// Generate the database from a list of type data /// </summary> public static NativeMeshDatabase FromTypeData(List <VoxelTypeData> typeData) { List <Node> allMeshNodesList = new List <Node>(); List <StartEndRange> nodesUsedByFacesList = new List <StartEndRange>(); List <int> allRelativeTrianglesList = new List <int>(); List <StartEndRange> relativeTrianglesByFacesList = new List <StartEndRange>(); List <bool> isFaceSolidList = new List <bool>(); List <StartEndRange> meshTypeRangesList = new List <StartEndRange>(); List <int> voxelTypeToMeshTypeMapList = new List <int>(); List <ushort> voxelTypeToMaterialIDMapList = new List <ushort>(); List <bool> meshIdToIncludeBackfacesMapList = new List <bool>(); Dictionary <SOMeshDefinition, int> uniqueMeshIDs = new Dictionary <SOMeshDefinition, int>(); //AIR voxelTypeToMeshTypeMapList.Add(0); voxelTypeToMaterialIDMapList.Add(0); for (ushort voxelId = 1; voxelId < typeData.Count; voxelId++) { var item = typeData[voxelId]; var SODef = item.definition.meshDefinition; if (!uniqueMeshIDs.TryGetValue(SODef, out var meshID)) { //New Unique mesh defintion meshID = meshTypeRangesList.Count; uniqueMeshIDs.Add(SODef, meshID); StartEndRange meshTypeRange = new StartEndRange(); meshTypeRange.start = nodesUsedByFacesList.Count; Flatten(SODef, allMeshNodesList, nodesUsedByFacesList, allRelativeTrianglesList, relativeTrianglesByFacesList, isFaceSolidList); meshTypeRange.end = nodesUsedByFacesList.Count; meshTypeRangesList.Add(meshTypeRange); meshIdToIncludeBackfacesMapList.Add(SODef.includeBackfaces); } voxelTypeToMeshTypeMapList.Add(meshID); voxelTypeToMaterialIDMapList.Add(item.materialID); } NativeMeshDatabase nativeMeshDatabase = new NativeMeshDatabase(); nativeMeshDatabase.allMeshNodes = new NativeArray <Node>(allMeshNodesList.ToArray(), Allocator.Persistent); nativeMeshDatabase.nodesUsedByFaces = new NativeArray <StartEndRange>(nodesUsedByFacesList.ToArray(), Allocator.Persistent); nativeMeshDatabase.allRelativeTriangles = new NativeArray <int>(allRelativeTrianglesList.ToArray(), Allocator.Persistent); nativeMeshDatabase.relativeTrianglesByFaces = new NativeArray <StartEndRange>(relativeTrianglesByFacesList.ToArray(), Allocator.Persistent); nativeMeshDatabase.isFaceSolid = new NativeArray <bool>(isFaceSolidList.ToArray(), Allocator.Persistent); nativeMeshDatabase.meshTypeRanges = new NativeArray <StartEndRange>(meshTypeRangesList.ToArray(), Allocator.Persistent); nativeMeshDatabase.voxelTypeToMeshTypeMap = new NativeArray <int>(voxelTypeToMeshTypeMapList.ToArray(), Allocator.Persistent); nativeMeshDatabase.voxelTypeToMaterialIDMap = new NativeArray <ushort>(voxelTypeToMaterialIDMapList.ToArray(), Allocator.Persistent); nativeMeshDatabase.meshIdToIncludeBackfacesMap = meshIdToIncludeBackfacesMapList.ToArray().ToNative(Allocator.Persistent); return(nativeMeshDatabase); }
public static IEnumerable <Vector3Int> AllPositionsOnChunkBorder(Direction dir, Vector3Int chunkDimensions) { StartEndRange xRange = new StartEndRange() { start = 0, end = chunkDimensions.x }; StartEndRange yRange = new StartEndRange() { start = 0, end = chunkDimensions.y }; StartEndRange zRange = new StartEndRange() { start = 0, end = chunkDimensions.z }; switch (dir) { case Direction.up: yRange.start = yRange.end - 1; break; case Direction.down: yRange.end = yRange.start + 1; break; case Direction.north: zRange.start = zRange.end - 1; break; case Direction.south: zRange.end = zRange.start + 1; break; case Direction.east: xRange.start = xRange.end - 1; break; case Direction.west: xRange.end = xRange.start + 1; break; default: throw new ArgumentException($"direction {dir} was not recognised"); } for (int z = zRange.start; z < zRange.end; z++) { for (int y = yRange.start; y < yRange.end; y++) { for (int x = xRange.start; x < xRange.end; x++) { yield return(new Vector3Int(x, y, z)); } } } }
/// <summary> /// Flatten a mesh definition into the working lists /// </summary> /// <param name="def"></param> /// <param name="allMeshNodesList"></param> /// <param name="nodesUsedByFacesList"></param> /// <param name="allRelativeTrianglesList"></param> /// <param name="relativeTrianglesByFacesList"></param> /// <param name="isFaceSolidList"></param> private static void Flatten(SOMeshDefinition def, List <Node> allMeshNodesList, List <StartEndRange> nodesUsedByFacesList, List <int> allRelativeTrianglesList, List <StartEndRange> relativeTrianglesByFacesList, List <bool> isFaceSolidList ) { for (int i = 0; i < def.Faces.Length; i++) { var faceDef = def.Faces[i]; isFaceSolidList.Add(faceDef.isSolid); StartEndRange nodesUsedIndexers = new StartEndRange(); nodesUsedIndexers.start = allMeshNodesList.Count; //Add all used nodes for (int j = 0; j < faceDef.UsedVertices.Length; j++) { Node node = new Node() { vertex = def.AllVertices[faceDef.UsedVertices[j]], uv = def.AllUvs[faceDef.UsedUvs[j]], normal = def.AllNormals[faceDef.UsedNormals[j]] }; allMeshNodesList.Add(node); } nodesUsedIndexers.end = allMeshNodesList.Count; nodesUsedByFacesList.Add(nodesUsedIndexers); StartEndRange trianglesIndexers = new StartEndRange(); trianglesIndexers.start = allRelativeTrianglesList.Count; //Add all relative triangles for (int j = 0; j < faceDef.Triangles.Length; j++) { allRelativeTrianglesList.Add(faceDef.Triangles[j]); } trianglesIndexers.end = allRelativeTrianglesList.Count; relativeTrianglesByFacesList.Add(trianglesIndexers); } }
public NativeBiomeDatabase ConfigToNative(SOBiomeConfiguration config, VoxelTypeManager typeManager) { List <NativeVoxelRange> allLayersList = new List <NativeVoxelRange>(); List <StartEndRange> biomeLayersList = new List <StartEndRange>(); List <NativeBiomeMoistureDefinition> allMoistureDefsList = new List <NativeBiomeMoistureDefinition>(); List <NativeElevationZone> allElevationZonesList = new List <NativeElevationZone>(); foreach (var elevationEntry in config.elevationLowToHigh) { NativeElevationZone elevationZone = new NativeElevationZone(); elevationZone.maxElevationPercentage = elevationEntry.max; elevationZone.moistureLevels = new StartEndRange() { start = allMoistureDefsList.Count }; foreach (var moistureEntry in elevationEntry.moistureLevelsLowToHigh) { NativeBiomeMoistureDefinition moistureDef = new NativeBiomeMoistureDefinition(); moistureDef.maxMoisturePercentage = moistureEntry.max; if (!biomeIds.TryGetValue(moistureEntry.biomeDefinition, out var id)) { //Create new biome data id = biomeLayersList.Count; biomeIds.Add(moistureEntry.biomeDefinition, id); biomeDefinitionsById.Add(moistureEntry.biomeDefinition); Assert.IsTrue(moistureEntry.biomeDefinition.topLayers.Count > 0, $"All biome definitions must have at least one layer,{moistureEntry.biomeDefinition.name} does not"); StartEndRange layersForThisBiome = new StartEndRange() { start = allLayersList.Count }; foreach (var layer in moistureEntry.biomeDefinition.topLayers) { NativeVoxelRange nativeLayer = new NativeVoxelRange(); nativeLayer.depth = layer.depth; nativeLayer.voxelID = typeManager.GetId(layer.voxelType); allLayersList.Add(nativeLayer); } layersForThisBiome.end = allLayersList.Count; biomeLayersList.Add(layersForThisBiome); } moistureDef.biomeID = id; allMoistureDefsList.Add(moistureDef); } elevationZone.moistureLevels.end = allMoistureDefsList.Count; allElevationZonesList.Add(elevationZone); } NativeBiomeDatabase biomeDatabase = new NativeBiomeDatabase(); VoxelTypeID defaultVoxelType = new VoxelTypeID(VoxelTypeID.AIR_ID); if (config.defaultVoxelType != null) { defaultVoxelType = typeManager.GetId(config.defaultVoxelType); } biomeDatabase.defaultVoxelType = defaultVoxelType; biomeDatabase.allLayers = new NativeArray <NativeVoxelRange>(allLayersList.ToArray(), Allocator.Persistent); biomeDatabase.biomeLayers = new NativeArray <StartEndRange>(biomeLayersList.ToArray(), Allocator.Persistent); biomeDatabase.allMoistureDefs = new NativeArray <NativeBiomeMoistureDefinition>(allMoistureDefsList.ToArray(), Allocator.Persistent); biomeDatabase.allElevationZones = new NativeArray <NativeElevationZone>(allElevationZonesList.ToArray(), Allocator.Persistent); return(biomeDatabase); }
/// <summary> /// Compute lighting contributions from the borders of all (valid) neighbouring chunks /// </summary> private void CheckBoundaries() { for (int i = 0; i < data.directionVectors.Length; i++) { Direction dir = (Direction)i; if (data.directionsValid[(int)dir]) { var offset = data.directionVectors[i]; StartEndRange xRange = new StartEndRange() { start = 0, end = data.dimensions.x }; StartEndRange yRange = new StartEndRange() { start = 0, end = data.dimensions.y }; StartEndRange zRange = new StartEndRange() { start = 0, end = data.dimensions.z }; switch (dir) { case Direction.up: yRange.start = yRange.end - 1; break; case Direction.down: yRange.end = yRange.start + 1; break; case Direction.north: zRange.start = zRange.end - 1; break; case Direction.south: zRange.end = zRange.start + 1; break; case Direction.east: xRange.start = xRange.end - 1; break; case Direction.west: xRange.end = xRange.start + 1; break; default: throw new ArgumentException($"direction {dir} was not recognised"); } for (int z = zRange.start; z < zRange.end; z++) { for (int y = yRange.start; y < yRange.end; y++) { for (int x = xRange.start; x < xRange.end; x++) { var localPos = new int3(x, y, z); var localFlat = MultiIndexToFlat(localPos, dx, dxdy); var localLv = data.lights[localFlat]; var neighPos = localPos + offset; var neighLv = GetLightValue(neighPos, data.lights, data.dimensions, data.neighbourData); var voxel = data.voxels[localFlat]; var absorption = data.voxelTypeToAbsorptionMap[voxel]; //Check dynamic propagation if (neighLv.Dynamic > 1) { var next = neighLv.Dynamic - absorption; if (next > localLv.Dynamic) { localLv.Dynamic = next; dynamicPropagationQueue.Enqueue(localPos); } } //Check sun propagation if (neighLv.Sun > 1) { var sunlight = neighLv.Sun; if (absorption < LightValue.MaxIntensity && sunlight > 1) { if ((offset.y == 1) && absorption == 1 && sunlight == LightValue.MaxIntensity) { //Do nothing, sunlight preserved going downwards } else { sunlight -= absorption; } if (sunlight > localLv.Sun) { localLv.Sun = sunlight; sunlightPropagationQueue.Enqueue(localPos); } } } data.lights[localFlat] = localLv; } } } } } }
public NativeArray <LightValue> BorderToNativeLight(Direction dir, Allocator allocator = Allocator.Persistent) { StartEndRange xRange = new StartEndRange() { start = 0, end = Dimensions.x }; StartEndRange yRange = new StartEndRange() { start = 0, end = Dimensions.y }; StartEndRange zRange = new StartEndRange() { start = 0, end = Dimensions.z }; switch (dir) { case Direction.up: yRange.start = yRange.end - 1; break; case Direction.down: yRange.end = yRange.start + 1; break; case Direction.north: zRange.start = zRange.end - 1; break; case Direction.south: zRange.end = zRange.start + 1; break; case Direction.east: xRange.start = xRange.end - 1; break; case Direction.west: xRange.end = xRange.start + 1; break; default: throw new ArgumentException($"direction {dir} was not recognised"); } NativeArray <LightValue> lightData = new NativeArray <LightValue>(xRange.Length * yRange.Length * zRange.Length, allocator); int i = 0; for (int z = zRange.start; z < zRange.end; z++) { for (int y = yRange.start; y < yRange.end; y++) { for (int x = xRange.start; x < xRange.end; x++) { lightData[i] = lightChunk[x, y, z]; i++; } } } return(lightData); }