Avoid rendering unseen blocks at chunk boundaries
This commit is contained in:
parent
94b8e2e355
commit
2d0ce96cc0
@ -250,6 +250,26 @@ namespace TrueCraft.API
|
||||
/// </summary>
|
||||
public static readonly Coordinates2D Right = new Coordinates2D(1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// A trio of 3D coordinates facing to the east.
|
||||
/// </summary>
|
||||
public static readonly Coordinates2D East = new Coordinates2D(1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// A trio of 3D coordinates facing to the west.
|
||||
/// </summary>
|
||||
public static readonly Coordinates2D West = new Coordinates2D(-1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// A trio of 3D coordinates facing to the north.
|
||||
/// </summary>
|
||||
public static readonly Coordinates2D North = new Coordinates2D(0, -1);
|
||||
|
||||
/// <summary>
|
||||
/// A trio of 3D coordinates facing to the south.
|
||||
/// </summary>
|
||||
public static readonly Coordinates2D South = new Coordinates2D(0, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
|
@ -51,7 +51,8 @@ namespace TrueCraft.Client.Rendering
|
||||
for (int _side = 0; _side < 6; _side++)
|
||||
{
|
||||
var side = (CubeFace)_side;
|
||||
var quad = CreateQuad(side, offset, texture, textureIndex % texture.Length, indiciesOffset, out _indicies, color);
|
||||
var quad = CreateQuad(side, offset, texture, textureIndex % texture.Length, indiciesOffset,
|
||||
out _indicies, color);
|
||||
Array.Copy(quad, 0, verticies, _side * 4, 4);
|
||||
Array.Copy(_indicies, 0, indicies, _side * 6, 6);
|
||||
textureIndex += 4;
|
||||
@ -59,8 +60,8 @@ namespace TrueCraft.Client.Rendering
|
||||
return verticies;
|
||||
}
|
||||
|
||||
protected static VertexPositionNormalColorTexture[] CreateQuad(CubeFace face, Vector3 offset, Vector2[] texture, int textureOffset,
|
||||
int indiciesOffset, out int[] indicies, Color color)
|
||||
protected static VertexPositionNormalColorTexture[] CreateQuad(CubeFace face, Vector3 offset,
|
||||
Vector2[] texture, int textureOffset, int indiciesOffset, out int[] indicies, Color color)
|
||||
{
|
||||
indicies = new[] { 0, 1, 3, 1, 2, 3 };
|
||||
for (int i = 0; i < indicies.Length; i++)
|
||||
|
@ -39,12 +39,14 @@ namespace TrueCraft.Client.Rendering
|
||||
}
|
||||
}
|
||||
|
||||
private ReadOnlyWorld World { get; set; }
|
||||
private TrueCraftGame Game { get; set; }
|
||||
private IBlockRepository BlockRepository { get; set; }
|
||||
|
||||
public ChunkRenderer(TrueCraftGame game, IBlockRepository blockRepository)
|
||||
public ChunkRenderer(ReadOnlyWorld world, TrueCraftGame game, IBlockRepository blockRepository)
|
||||
: base()
|
||||
{
|
||||
World = world;
|
||||
BlockRepository = blockRepository;
|
||||
Game = game;
|
||||
}
|
||||
@ -59,10 +61,20 @@ namespace TrueCraft.Client.Rendering
|
||||
Coordinates3D.West
|
||||
};
|
||||
|
||||
private static readonly VisibleFaces[] AdjacentCoordFaces =
|
||||
{
|
||||
VisibleFaces.Bottom,
|
||||
VisibleFaces.Top,
|
||||
VisibleFaces.South,
|
||||
VisibleFaces.North,
|
||||
VisibleFaces.West,
|
||||
VisibleFaces.East
|
||||
};
|
||||
|
||||
protected override bool TryRender(ReadOnlyChunk item, out Mesh result)
|
||||
{
|
||||
var state = new RenderState();
|
||||
ProcessChunk(item, state);
|
||||
ProcessChunk(World, item, state);
|
||||
|
||||
result = new ChunkMesh(item, Game, state.Verticies.ToArray(),
|
||||
state.OpaqueIndicies.ToArray(), state.TransparentIndicies.ToArray());
|
||||
@ -70,15 +82,125 @@ namespace TrueCraft.Client.Rendering
|
||||
return (result != null);
|
||||
}
|
||||
|
||||
private class RenderState
|
||||
[Flags]
|
||||
public enum VisibleFaces
|
||||
{
|
||||
public readonly List<VertexPositionNormalColorTexture> Verticies = new List<VertexPositionNormalColorTexture>();
|
||||
public readonly List<int> OpaqueIndicies = new List<int>();
|
||||
public readonly List<int> TransparentIndicies = new List<int>();
|
||||
public readonly HashSet<Coordinates3D> DrawableCoordinates = new HashSet<Coordinates3D>();
|
||||
None = 0,
|
||||
North = 1,
|
||||
South = 2,
|
||||
East = 4,
|
||||
West = 8,
|
||||
Top = 16,
|
||||
Bottom = 32,
|
||||
All = North | South | East | West | Top | Bottom
|
||||
}
|
||||
|
||||
private void ProcessChunk(ReadOnlyChunk chunk, RenderState state)
|
||||
private class RenderState
|
||||
{
|
||||
public readonly List<VertexPositionNormalColorTexture> Verticies
|
||||
= new List<VertexPositionNormalColorTexture>();
|
||||
public readonly List<int> OpaqueIndicies = new List<int>();
|
||||
public readonly List<int> TransparentIndicies = new List<int>();
|
||||
public readonly Dictionary<Coordinates3D, VisibleFaces> DrawableCoordinates
|
||||
= new Dictionary<Coordinates3D, VisibleFaces>();
|
||||
}
|
||||
|
||||
private void AddBottomBlock(Coordinates3D coords, RenderState state, ReadOnlyChunk chunk)
|
||||
{
|
||||
var desiredFaces = VisibleFaces.None;
|
||||
if (coords.X == 0)
|
||||
desiredFaces |= VisibleFaces.West;
|
||||
else if (coords.X == Chunk.Width - 1)
|
||||
desiredFaces |= VisibleFaces.East;
|
||||
if (coords.Z == 0)
|
||||
desiredFaces |= VisibleFaces.North;
|
||||
else if (coords.Z == Chunk.Depth - 1)
|
||||
desiredFaces |= VisibleFaces.South;
|
||||
if (coords.Y == 0)
|
||||
desiredFaces |= VisibleFaces.Bottom;
|
||||
else if (coords.Y == Chunk.Depth - 1)
|
||||
desiredFaces |= VisibleFaces.Top;
|
||||
|
||||
VisibleFaces faces;
|
||||
state.DrawableCoordinates.TryGetValue(coords, out faces);
|
||||
faces |= desiredFaces;
|
||||
state.DrawableCoordinates[coords] = desiredFaces;
|
||||
}
|
||||
|
||||
private void AddAdjacentBlocks(Coordinates3D coords, RenderState state, ReadOnlyChunk chunk)
|
||||
{
|
||||
// Add adjacent blocks
|
||||
for (int i = 0; i < AdjacentCoordinates.Length; i++)
|
||||
{
|
||||
var next = coords + AdjacentCoordinates[i];
|
||||
if (next.X < 0 || next.X >= Chunk.Width
|
||||
|| next.Y < 0 || next.Y >= Chunk.Height
|
||||
|| next.Z < 0 || next.Z >= Chunk.Depth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (chunk.GetBlockId(next) != 0)
|
||||
{
|
||||
VisibleFaces faces;
|
||||
state.DrawableCoordinates.TryGetValue(next, out faces);
|
||||
faces |= AdjacentCoordFaces[i];
|
||||
state.DrawableCoordinates[next] = faces;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFacesFromAdjacent(Coordinates3D adjacent, ReadOnlyChunk chunk,
|
||||
VisibleFaces mod, ref VisibleFaces faces)
|
||||
{
|
||||
if (chunk == null)
|
||||
return;
|
||||
var provider = BlockRepository.GetBlockProvider(chunk.GetBlockId(adjacent));
|
||||
if (!provider.Opaque)
|
||||
faces |= mod;
|
||||
}
|
||||
|
||||
private void AddChunkBoundaryBlocks(Coordinates3D coords, RenderState state, ReadOnlyChunk chunk)
|
||||
{
|
||||
VisibleFaces faces;
|
||||
if (!state.DrawableCoordinates.TryGetValue(coords, out faces))
|
||||
faces = VisibleFaces.None;
|
||||
VisibleFaces oldFaces = faces;
|
||||
|
||||
if (coords.X == 0)
|
||||
{
|
||||
var adjacent = coords;
|
||||
adjacent.X = Chunk.Width - 1;
|
||||
var nextChunk = World.GetChunk(chunk.Chunk.Coordinates + Coordinates2D.West);
|
||||
UpdateFacesFromAdjacent(adjacent, nextChunk, VisibleFaces.West, ref faces);
|
||||
}
|
||||
else if (coords.X == Chunk.Width - 1)
|
||||
{
|
||||
var adjacent = coords;
|
||||
adjacent.X = 0;
|
||||
var nextChunk = World.GetChunk(chunk.Chunk.Coordinates + Coordinates2D.East);
|
||||
UpdateFacesFromAdjacent(adjacent, nextChunk, VisibleFaces.East, ref faces);
|
||||
}
|
||||
|
||||
if (coords.Z == 0)
|
||||
{
|
||||
var adjacent = coords;
|
||||
adjacent.Z = Chunk.Depth - 1;
|
||||
var nextChunk = World.GetChunk(chunk.Chunk.Coordinates + Coordinates2D.North);
|
||||
UpdateFacesFromAdjacent(adjacent, nextChunk, VisibleFaces.North, ref faces);
|
||||
}
|
||||
else if (coords.Z == Chunk.Depth - 1)
|
||||
{
|
||||
var adjacent = coords;
|
||||
adjacent.Z = 0;
|
||||
var nextChunk = World.GetChunk(chunk.Chunk.Coordinates + Coordinates2D.South);
|
||||
UpdateFacesFromAdjacent(adjacent, nextChunk, VisibleFaces.South, ref faces);
|
||||
}
|
||||
|
||||
if (oldFaces != faces)
|
||||
state.DrawableCoordinates[coords] = faces;
|
||||
}
|
||||
|
||||
private void ProcessChunk(ReadOnlyWorld world, ReadOnlyChunk chunk, RenderState state)
|
||||
{
|
||||
state.Verticies.Clear();
|
||||
state.OpaqueIndicies.Clear();
|
||||
@ -94,26 +216,16 @@ namespace TrueCraft.Client.Rendering
|
||||
var coords = new Coordinates3D(x, y, z);
|
||||
var id = chunk.GetBlockId(coords);
|
||||
var provider = BlockRepository.GetBlockProvider(id);
|
||||
if (id != 0 && (coords.X == 0 || coords.X == Chunk.Width - 1
|
||||
|| coords.Y == 0 || coords.Y == Chunk.Height - 1
|
||||
|| coords.Z == 0 || coords.Z == Chunk.Depth - 1))
|
||||
{
|
||||
state.DrawableCoordinates.Add(coords);
|
||||
}
|
||||
if (id != 0 && coords.Y == 0)
|
||||
AddBottomBlock(coords, state, chunk);
|
||||
if (!provider.Opaque)
|
||||
AddAdjacentBlocks(coords, state, chunk);
|
||||
else
|
||||
{
|
||||
// Add adjacent blocks
|
||||
foreach (var a in AdjacentCoordinates)
|
||||
if (coords.X == 0 || coords.X == Chunk.Width - 1 ||
|
||||
coords.Z == 0 || coords.Z == Chunk.Depth - 1)
|
||||
{
|
||||
var next = coords + a;
|
||||
if (next.X < 0 || next.X >= Chunk.Width
|
||||
|| next.Y < 0 || next.Y >= Chunk.Height
|
||||
|| next.Z < 0 || next.Z >= Chunk.Depth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (chunk.GetBlockId(next) != 0)
|
||||
state.DrawableCoordinates.Add(next);
|
||||
AddChunkBoundaryBlocks(coords, state, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,13 +236,14 @@ namespace TrueCraft.Client.Rendering
|
||||
{
|
||||
var coords = enumerator.Current;
|
||||
enumerator.MoveNext();
|
||||
var c = coords.Key;
|
||||
var descriptor = new BlockDescriptor
|
||||
{
|
||||
ID = chunk.GetBlockId(coords),
|
||||
Metadata = chunk.GetMetadata(coords),
|
||||
BlockLight = chunk.GetBlockLight(coords),
|
||||
SkyLight = chunk.GetSkyLight(coords),
|
||||
Coordinates = coords,
|
||||
ID = chunk.GetBlockId(coords.Key),
|
||||
Metadata = chunk.GetMetadata(coords.Key),
|
||||
BlockLight = chunk.GetBlockLight(coords.Key),
|
||||
SkyLight = chunk.GetSkyLight(coords.Key),
|
||||
Coordinates = coords.Key,
|
||||
Chunk = chunk.Chunk
|
||||
};
|
||||
var provider = BlockRepository.GetBlockProvider(descriptor.ID);
|
||||
@ -138,7 +251,7 @@ namespace TrueCraft.Client.Rendering
|
||||
{
|
||||
int[] i;
|
||||
var v = BlockRenderer.RenderBlock(provider, descriptor,
|
||||
new Vector3(chunk.X * Chunk.Width + coords.X, coords.Y, chunk.Z * Chunk.Depth + coords.Z),
|
||||
new Vector3(chunk.X * Chunk.Width + c.X, c.Y, chunk.Z * Chunk.Depth + c.Z),
|
||||
state.Verticies.Count, out i);
|
||||
state.Verticies.AddRange(v);
|
||||
state.OpaqueIndicies.AddRange(i);
|
||||
@ -147,7 +260,7 @@ namespace TrueCraft.Client.Rendering
|
||||
{
|
||||
int[] i;
|
||||
var v = BlockRenderer.RenderBlock(provider, descriptor,
|
||||
new Vector3(chunk.X * Chunk.Width + coords.X, coords.Y, chunk.Z * Chunk.Depth + coords.Z),
|
||||
new Vector3(chunk.X * Chunk.Width + c.X, c.Y, chunk.Z * Chunk.Depth + c.Z),
|
||||
state.Verticies.Count, out i);
|
||||
state.Verticies.AddRange(v);
|
||||
state.TransparentIndicies.AddRange(i);
|
||||
|
@ -47,18 +47,15 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<Commandlineparameters>localhost TestUser</Commandlineparameters>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<DebugType>
|
||||
</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Optimized Debug|AnyCPU' ">
|
||||
<DebugType>
|
||||
@ -68,6 +65,9 @@
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Optimized Debug|x86' ">
|
||||
<Optimize>false</Optimize>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Ionic.Zip.Reduced">
|
||||
<HintPath>..\lib\Ionic.Zip.Reduced.dll</HintPath>
|
||||
@ -190,7 +190,7 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\terrain.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Content\Fonts\Pixel_Bold.fnt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
@ -78,7 +78,7 @@ namespace TrueCraft.Client
|
||||
Interfaces = new List<IGameInterface>();
|
||||
SpriteBatch = new SpriteBatch(GraphicsDevice);
|
||||
base.Initialize(); // (calls LoadContent)
|
||||
ChunkConverter = new ChunkRenderer(this, Client.World.World.BlockRepository);
|
||||
ChunkConverter = new ChunkRenderer(Client.World, this, Client.World.World.BlockRepository);
|
||||
Client.ChunkLoaded += (sender, e) => ChunkConverter.Enqueue(e.Chunk);
|
||||
//Client.ChunkModified += (sender, e) => ChunkConverter.Enqueue(e.Chunk, true);
|
||||
ChunkConverter.MeshCompleted += ChunkConverter_MeshGenerated;
|
||||
@ -302,7 +302,7 @@ namespace TrueCraft.Client
|
||||
Mouse.SetPosition(centerX, centerY);
|
||||
|
||||
var look = new Vector2((centerX - e.X), (centerY - e.Y))
|
||||
* (float)(GameTime.ElapsedGameTime.TotalSeconds * 70);
|
||||
* (float)(GameTime.ElapsedGameTime.TotalSeconds * 90);
|
||||
|
||||
Client.Yaw += look.X;
|
||||
Client.Pitch += look.Y;
|
||||
|
Reference in New Issue
Block a user