private static int GetVoxelVertexExploredNeighbors(VoxelHandle V, Geo.TemplateFace Face, SliceCache Cache) { var exploredVerts = 0; if (V.IsExplored) { exploredVerts = 4; } else { for (int faceVertex = 0; faceVertex < Face.Mesh.VertexCount; ++faceVertex) { var cacheKey = SliceCache.GetCacheKey(V, Face.Mesh.Verticies[faceVertex].LogicalVertex); var anyNeighborExplored = true; if (!Cache.ExploredCache.TryGetValue(cacheKey, out anyNeighborExplored)) { anyNeighborExplored = VoxelHelpers.EnumerateVertexNeighbors2D(V.Coordinate, Face.Mesh.Verticies[faceVertex].LogicalVertex) .Select(c => new VoxelHandle(V.Chunk.Manager, c)) .Any(n => n.IsValid && n.IsExplored); Cache.ExploredCache.Add(cacheKey, anyNeighborExplored); } if (anyNeighborExplored) { exploredVerts += 1; } } } return(exploredVerts); }
public static VertexColorInfo CalculateVertexLight(VoxelHandle Vox, VoxelVertex Vertex, ChunkManager Chunks, SliceCache Cache) { var r = new VertexColorInfo(); var cacheKey = SliceCache.GetCacheKey(Vox, Vertex); if (!Cache.LightCache.TryGetValue(cacheKey, out r)) { r = CalculateVertexLight(Vox, Vertex, Chunks); Cache.LightCache.Add(cacheKey, r); } return(r); }
private static void GenerateSliceGeometry( RawPrimitive Into, VoxelChunk Chunk, int LocalY, TerrainTileSheet TileSheet, WorldManager World, SliceCache Cache) { for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x) { for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z) { GenerateVoxelGeometry(Into, VoxelHandle.UnsafeCreateLocalHandle(Chunk, new LocalVoxelCoordinate(x, LocalY, z)), TileSheet, World, Cache); } } }
private static void GenerateHangingCornerFringe( RawPrimitive Into, Geo.TemplateFace Face, TerrainTileSheet TileSheet, SliceCache Cache, GrassType decalType, Geo.TemplateCorner Corner, Vector3 Sag) { var vertex = Cache.FaceGeometry[Corner.Vertex]; Cache.TempVerticies[0] = new ExtendedVertex( vertex.Position, vertex.Color, vertex.VertColor, TileSheet.MapTileUVs(new Vector2(0.0f, 0.0f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2])); Cache.TempVerticies[1] = new ExtendedVertex( Cache.EdgeFringeTempVerticies[Corner.EdgeA].Set ? Cache.EdgeFringeTempVerticies[Corner.EdgeA].End : (vertex.Position + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeA].Orientation).AsVector3() * 0.5f + Sag), vertex.Color, vertex.VertColor, TileSheet.MapTileUVs(new Vector2(0.5f, 0.0f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2])); Cache.TempVerticies[2] = new ExtendedVertex( vertex.Position + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeA].Orientation).AsVector3() * 0.5f + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeB].Orientation).AsVector3() * 0.5f + Sag, vertex.Color, vertex.VertColor, TileSheet.MapTileUVs(new Vector2(0.5f, 0.5f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2])); Cache.TempVerticies[3] = new ExtendedVertex( Cache.EdgeFringeTempVerticies[Corner.EdgeB].Set ? Cache.EdgeFringeTempVerticies[Corner.EdgeB].Start : (vertex.Position + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeB].Orientation).AsVector3() * 0.5f + Sag), vertex.Color, vertex.VertColor, TileSheet.MapTileUVs(new Vector2(0.0f, 0.5f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2])); AddQuad(Into, Cache.TempVerticies, QuadIndicies); }
public static void GenerateFaceGeometry( RawPrimitive Into, VoxelHandle Voxel, Geo.TemplateFace Face, TerrainTileSheet TileSheet, WorldManager World, SliceCache Cache) { if (Face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, Face, World.ChunkManager, out var neighbor)) { return; } if (Face.Orientation == FaceOrientation.Top) { if (Voxel.GrassType != 0) { var decalType = Library.GetGrassType(Voxel.GrassType); PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, decalType.Tile, true, 0.0f); GenerateGrassFringe(Into, Voxel, Face, TileSheet, Cache, decalType); } else { PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, SelectTile(Voxel.Type, Face.Orientation), true, 0.0f); } AddQuad(Into, Cache.FaceGeometry, QuadIndicies); if (Voxel.DecalType != 0) { var decalType = Library.GetDecalType(Voxel.DecalType); PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, decalType.Tile, true, 0.02f); AddQuad(Into, Cache.FaceGeometry, QuadIndicies); } } else { PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, SelectTile(Voxel.Type, Face.Orientation), true, 0.0f); AddQuad(Into, Cache.FaceGeometry, QuadIndicies); } }
public static void GenerateVoxelGeometry( RawPrimitive Into, VoxelHandle Voxel, TerrainTileSheet TileSheet, WorldManager World, SliceCache Cache) { BuildDesignationGeometry(Into, Voxel, Cache, TileSheet, World); if (Voxel.IsEmpty && Voxel.IsExplored) { return; } var templateSolid = TemplateSolidLibrary.GetTemplateSolid(Voxel.Type.TemplateSolid); foreach (var face in templateSolid.Faces) { GenerateFaceGeometry(Into, Voxel, face, TileSheet, World, Cache); } }
private static void GenerateEdgeFringe( RawPrimitive Into, Geo.TemplateFace Face, int EdgeIndex, TerrainTileSheet TileSheet, SliceCache Cache, GrassType decalType, Vector3 Sag, float Scale) { var start = Cache.FaceGeometry[Face.Edges[EdgeIndex].Start]; var end = Cache.FaceGeometry[Face.Edges[EdgeIndex].End]; Cache.EdgeFringeTempVerticies[EdgeIndex].Set = true; Cache.TempVerticies[0] = new ExtendedVertex( start.Position, start.Color, start.VertColor, TileSheet.MapTileUVs(new Vector2(0.0f, 0.0f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0])); Cache.TempVerticies[1] = new ExtendedVertex( end.Position, end.Color, end.VertColor, TileSheet.MapTileUVs(new Vector2(1.0f, 0.0f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0])); Cache.EdgeFringeTempVerticies[EdgeIndex].End = end.Position + OrientationHelper.GetFaceNeighborOffset(Face.Edges[EdgeIndex].Orientation).AsVector3() * Scale + Sag; Cache.TempVerticies[2] = new ExtendedVertex( Cache.EdgeFringeTempVerticies[EdgeIndex].End, end.Color, end.VertColor, TileSheet.MapTileUVs(new Vector2(1.0f, 0.5f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0])); Cache.EdgeFringeTempVerticies[EdgeIndex].Start = start.Position + OrientationHelper.GetFaceNeighborOffset(Face.Edges[EdgeIndex].Orientation).AsVector3() * Scale + Sag; Cache.TempVerticies[3] = new ExtendedVertex( Cache.EdgeFringeTempVerticies[EdgeIndex].Start, start.Color, start.VertColor, TileSheet.MapTileUVs(new Vector2(0.0f, 0.5f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0])); AddQuad(Into, Cache.TempVerticies, QuadIndicies); }
private static void GenerateGrassFringe(RawPrimitive Into, VoxelHandle Voxel, Geo.TemplateFace Face, TerrainTileSheet TileSheet, SliceCache Cache, GrassType decalType) { for (var i = 0; i < 4; ++i) { Cache.EdgeFringeTempVerticies[i].Set = false; } if (Face.Edges != null) { for (var e = 0; e < Face.Edges.Length; ++e) { var fringeNeighbor = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[e].Orientation)); if (fringeNeighbor.IsValid) { if (fringeNeighbor.IsEmpty) { GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, -0.5f, 0.0f), 0.5f); } else { var above = VoxelHelpers.GetVoxelAbove(fringeNeighbor); if (above.IsValid && !above.IsEmpty) { GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, 0.5f, 0.0f), -0.1f); } else if (fringeNeighbor.GrassType == 0 || (fringeNeighbor.GrassType != Voxel.GrassType && Library.GetGrassType(fringeNeighbor.GrassType).FringePrecedence < decalType.FringePrecedence)) { GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, 0.2f, 0.0f), 0.5f); } } } } } if (Face.Corners != null) { for (var c = 0; c < Face.Corners.Length; ++c) { var cornerNeighbor = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeA].Orientation) + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeB].Orientation)); var manhattanA = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeA].Orientation)); var manhattanB = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeB].Orientation)); if (manhattanA.IsValid && !manhattanA.IsEmpty && manhattanA.GrassType == Voxel.GrassType) { continue; } if (manhattanB.IsValid && !manhattanB.IsEmpty && manhattanB.GrassType == Voxel.GrassType) { continue; } if (cornerNeighbor.IsValid) { if (cornerNeighbor.IsEmpty) // Todo: Do not generate fringe if horizontal neighbors are occupied. // Todo: Also - needs to use corners set by edge fringe when they are at different heights. Maybe specify which edges the corner is in between? { GenerateHangingCornerFringe(Into, Face, TileSheet, Cache, decalType, Face.Corners[c], new Vector3(0.0f, -0.5f, 0.0f)); } else { var above = VoxelHelpers.GetVoxelAbove(cornerNeighbor); if (above.IsValid && !above.IsEmpty) { } else if (cornerNeighbor.GrassType == 0 || (cornerNeighbor.GrassType != Voxel.GrassType && Library.GetGrassType(cornerNeighbor.GrassType).FringePrecedence < decalType.FringePrecedence)) { GenerateHangingCornerFringe(Into, Face, TileSheet, Cache, decalType, Face.Corners[c], new Vector3(0.0f, 0.1f, 0.0f)); } } } } } }
private static void PrepVerticies( WorldManager World, VoxelHandle Voxel, Geo.TemplateFace Face, SliceCache Cache, int ExploredVertexCount, TerrainTileSheet TileSheet, Point Tile, bool ApplyLighting, float explodeOffset) { for (var vertex = 0; vertex < Face.Mesh.VertexCount; ++vertex) // Blows up if face has more than 4 verticies. { var lighting = new VertexLighting.VertexColorInfo { AmbientColor = 255, DynamicColor = 255, SunColor = 255 }; if (ApplyLighting) { lighting = VertexLighting.CalculateVertexLight(Voxel, Face.Mesh.Verticies[vertex].LogicalVertex, World.ChunkManager, Cache); } var slopeOffset = Vector3.Zero; if (Face.Mesh.Verticies[vertex].ApplySlope && ShouldSlope(Face.Mesh.Verticies[vertex].LogicalVertex, Voxel)) { slopeOffset = new Vector3(0.0f, -0.5f, 0.0f); } var voxelPosition = Face.Mesh.Verticies[vertex].Position + slopeOffset + Voxel.WorldPosition; voxelPosition += VertexNoise.GetNoiseVectorFromRepeatingTexture(voxelPosition); voxelPosition += explodeOffset * OrientationHelper.GetFaceNeighborOffset(Face.Orientation).AsVector3(); if (ExploredVertexCount == 0) { Cache.FaceGeometry[vertex] = new ExtendedVertex { Position = voxelPosition, TextureCoordinate = TileSheet.MapTileUVs(Face.Mesh.Verticies[vertex].TextureCoordinate, BlackTile), TextureBounds = TileSheet.GetTileBounds(BlackTile), VertColor = new Color(0.0f, 0.0f, 0.0f, 1.0f), Color = new Color(0.0f, 0.0f, 0.0f, 1.0f) }; } else { var anyNeighborExplored = true; if (!Cache.ExploredCache.TryGetValue(SliceCache.GetCacheKey(Voxel, Face.Mesh.Verticies[vertex].LogicalVertex), out anyNeighborExplored)) { anyNeighborExplored = true; } Cache.FaceGeometry[vertex] = new ExtendedVertex { Position = voxelPosition, TextureCoordinate = TileSheet.MapTileUVs(Face.Mesh.Verticies[vertex].TextureCoordinate, Tile), TextureBounds = TileSheet.GetTileBounds(Tile), VertColor = anyNeighborExplored ? new Color(1.0f, 1.0f, 1.0f, 1.0f) : new Color(0.0f, 0.0f, 0.0f, 1.0f), Color = lighting.AsColor() }; } } }
public static GeometricPrimitive CreateFromChunk(VoxelChunk Chunk, WorldManager World) { DebugHelper.AssertNotNull(Chunk); DebugHelper.AssertNotNull(World); var sliceStack = new List <RawPrimitive>(); var sliceCache = new SliceCache(); int maxViewingLevel = World.Renderer.PersistentSettings.MaxViewingLevel; var terrainTileSheet = new TerrainTileSheet(512, 512, 32, 32); for (var localY = 0; localY < maxViewingLevel - Chunk.Origin.Y && localY < VoxelConstants.ChunkSizeY; ++localY) { RawPrimitive sliceGeometry = null; sliceCache.ClearSliceCache(); lock (Chunk.Data.SliceCache) { var cachedSlice = Chunk.Data.SliceCache[localY]; if (cachedSlice != null) { sliceStack.Add(cachedSlice); // Todo: Get rid of the raw primitive / geometric primitive bullshit entirely if (GameSettings.Current.GrassMotes) { Chunk.RebuildMoteLayerIfNull(localY); } continue; } sliceGeometry = new RawPrimitive(); Chunk.Data.SliceCache[localY] = sliceGeometry; } if (GameSettings.Current.CalculateRamps) { PrecomputeVoxelSlopesSlice(World.ChunkManager, Chunk, localY); } if (GameSettings.Current.GrassMotes) { Chunk.RebuildMoteLayer(localY); } DebugHelper.AssertNotNull(sliceGeometry); GenerateSliceGeometry(sliceGeometry, Chunk, localY, terrainTileSheet, World, sliceCache); sliceStack.Add(sliceGeometry); } var chunkGeo = RawPrimitive.Concat(sliceStack); var r = new GeometricPrimitive(); r.Vertices = chunkGeo.Vertices; r.VertexCount = chunkGeo.VertexCount; r.Indexes = chunkGeo.Indexes.Select(c => (ushort)c).ToArray(); r.IndexCount = chunkGeo.IndexCount; return(r); }
private static void BuildDesignationGeometry( RawPrimitive Into, VoxelHandle Voxel, SliceCache Cache, TerrainTileSheet TileSheet, WorldManager World) { // Todo: Store designations per chunk. foreach (var designation in World.PersistentData.Designations.EnumerateDesignations(Voxel).ToList()) { if ((designation.Type & World.Renderer.PersistentSettings.VisibleTypes) != designation.Type) // If hidden by player, do not draw. { return; } var designationProperties = Library.GetDesignationTypeProperties(designation.Type).Value; var designationVisible = false; if (designationProperties.DrawType == DesignationDrawType.PreviewVoxel) { designationVisible = Voxel.Coordinate.Y < World.Renderer.PersistentSettings.MaxViewingLevel; } else { designationVisible = VoxelHelpers.DoesVoxelHaveVisibleSurface(World, Voxel); } if (designationVisible && Library.GetVoxelPrimitive(Library.DesignationVoxelType).HasValue(out BoxPrimitive designationPrimitive)) { switch (designationProperties.DrawType) { case DesignationDrawType.FullBox: { var solid = TemplateSolidLibrary.GetTemplateSolid(Voxel.Type.TemplateSolid); for (var f = 0; f < solid.Faces.Count; ++f) { var face = solid.Faces[f]; if (face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, face, World.ChunkManager, out var neighbor)) { continue; } PrepVerticies(World, Voxel, face, Cache, GetVoxelVertexExploredNeighbors(Voxel, face, Cache), TileSheet, new Point(0, 0), false, 0.02f); SetVertexTint(Cache.FaceGeometry, designationProperties.Color); AddQuad(Into, Cache.FaceGeometry, QuadIndicies); } } break; case DesignationDrawType.TopBox: { var solid = TemplateSolidLibrary.GetTemplateSolid(Voxel.Type.TemplateSolid); for (var f = 0; f < solid.Faces.Count; ++f) { var face = solid.Faces[f]; if (face.Orientation != FaceOrientation.Top) { continue; } if (face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, face, World.ChunkManager, out var neighbor)) { continue; } PrepVerticies(World, Voxel, face, Cache, GetVoxelVertexExploredNeighbors(Voxel, face, Cache), TileSheet, new Point(0, 0), false, 0.02f); SetVertexTint(Cache.FaceGeometry, designationProperties.Color); AddQuad(Into, Cache.FaceGeometry, QuadIndicies); } } break; case DesignationDrawType.PreviewVoxel: { if (Library.GetVoxelType(designation.Tag.ToString()).HasValue(out VoxelType voxelType)) { var solid = TemplateSolidLibrary.GetTemplateSolid(voxelType.TemplateSolid); for (var f = 0; f < solid.Faces.Count; ++f) { var face = solid.Faces[f]; if (face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, face, World.ChunkManager, out var neighbor)) { continue; } PrepVerticies(World, Voxel, face, Cache, GetVoxelVertexExploredNeighbors(Voxel, face, Cache), TileSheet, SelectTile(voxelType, face.Orientation), false, 0.0f); SetVertexTint(Cache.FaceGeometry, designationProperties.Color); AddQuad(Into, Cache.FaceGeometry, QuadIndicies); } } } break; } } } }