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