mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-15 18:45:23 -04:00
More work on experimental occlusion culling.
This commit is contained in:
parent
7a87906dad
commit
d0445ba54d
@ -5,88 +5,85 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
public partial class ChunkMeshBuilder {
|
public partial class ChunkMeshBuilder {
|
||||||
|
|
||||||
unsafe void FloodFill( byte* chunkPtr, int startIndex ) {
|
unsafe int ComputeOcclusion() {
|
||||||
int* stack = stackalloc int[chunkSize3];
|
int* didFlags = stackalloc int[chunkSize2];
|
||||||
ushort* didFlags = stackalloc ushort[chunkSize2];
|
OpenTK.MemUtils.memset( (IntPtr)didFlags, 0x00, 0, chunkSize2 * sizeof( int ) );
|
||||||
OpenTK.MemUtils.memset( (IntPtr)didFlags, 0x00, 0, chunkSize2 * 2 );
|
int* stack = stackalloc int[chunkSize3 * 4];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
bool solidX = true, solidY = true, solidZ = true;
|
||||||
|
for( int y = 0; y < 16; y++ ) {
|
||||||
|
for( int z = 0; z < 16; z++ ) {
|
||||||
|
int flagIndex = (y << 4) | z;
|
||||||
|
int chunkIndex = (y + 1) * extChunkSize2 + (z + 1) * extChunkSize + (0 + 1);
|
||||||
|
for( int x = 0; x < 16; x++ ) {
|
||||||
|
byte block = chunk[chunkIndex];
|
||||||
|
if( info.IsOpaque[block] ) {
|
||||||
|
didFlags[flagIndex] |= (1 << x);
|
||||||
|
} else {
|
||||||
|
FloodFill( didFlags, stack, i, ref solidX, ref solidY, ref solidZ );
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
chunkIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (solidX ? 0x1 : 0) | (solidZ ? 0x2 : 0) | (solidY ? 0x4 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe void FloodFill( int* didFlags, int* stack, int startIndex,
|
||||||
|
ref bool solidX, ref bool solidY, ref bool solidZ ) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
stack[index++] = startIndex;
|
stack[index++] = startIndex;
|
||||||
|
bool tX0 = false, tX1 = false, tY0 = false,
|
||||||
|
tY1 = false, tZ0 = false, tZ1 = false;
|
||||||
|
|
||||||
while( index > 0 ) {
|
while( index > 0 ) {
|
||||||
int bIndex = stack[index--];
|
int bIndex = stack[--index];
|
||||||
int x = (bIndex & 0x0F);
|
int x = (bIndex & 0x0F);
|
||||||
int z = ((bIndex >> 4) & 0x0F );
|
int z = ((bIndex >> 4) & 0x0F );
|
||||||
int y = ((bIndex >> 8) & 0x0F);
|
int y = ((bIndex >> 8) & 0x0F);
|
||||||
|
int flagIndex = (y << 4) | z;
|
||||||
|
didFlags[flagIndex] |= (1 << x);
|
||||||
|
|
||||||
int chunkIndex = (y + 1) * extChunkSize2 + (z + 1) * extChunkSize + (x + 1);
|
int chunkIndex = (y + 1) * extChunkSize2 + (z + 1) * extChunkSize + (x + 1);
|
||||||
byte block = chunkPtr[chunkIndex];
|
byte block = chunk[chunkIndex];
|
||||||
if( !info.IsOpaque[block] ) {
|
if( !info.IsOpaque[block] ) {
|
||||||
if( x < 15 ) stack[index++] = (y << 8) | (z << 4) | (x + 1);
|
if( x == 0 )
|
||||||
if( x > 0 ) stack[index++] = (y << 8) | (z << 4) | (x - 1);
|
tX0 = true;
|
||||||
if( z < 15 ) stack[index++] = (y << 8) | ((z + 1) << 4) | x;
|
else if( (didFlags[flagIndex] & (1 << (x - 1))) == 0 )
|
||||||
if( z > 0 ) stack[index++] = (y << 8) | ((z - 1) << 4) | x;
|
stack[index++] = (y << 8) | (z << 4) | (x - 1);
|
||||||
if( y < 15 ) stack[index++] = ((y + 1) << 8) | (z << 4) | x;
|
|
||||||
if( y > 0 ) stack[index++] = ((y - 1) << 8) | (z << 4) | x;
|
if( x == 15 )
|
||||||
|
tX1 = true;
|
||||||
|
else if( (didFlags[flagIndex] & (1 << (x + 1))) == 0 )
|
||||||
|
stack[index++] = (y << 8) | (z << 4) | (x + 1);
|
||||||
|
|
||||||
|
if( z == 0 )
|
||||||
|
tZ0 = true;
|
||||||
|
else if( (didFlags[flagIndex - 1] & (1 << x)) == 0 )
|
||||||
|
stack[index++] = (y << 8) | ((z - 1) << 4) | x;
|
||||||
|
|
||||||
|
if( z == 15 )
|
||||||
|
tZ1 = true;
|
||||||
|
else if( (didFlags[flagIndex + 1] & (1 << x)) == 0 )
|
||||||
|
stack[index++] = (y << 8) | ((z + 1) << 4) | x;
|
||||||
|
|
||||||
|
if( y == 0 )
|
||||||
|
tY0 = true;
|
||||||
|
else if( (didFlags[flagIndex - 16] & (1 << x)) == 0 )
|
||||||
|
stack[index++] = ((y - 1) << 8) | (z << 4) | x;
|
||||||
|
|
||||||
|
if( y == 15 )
|
||||||
|
tY1 = true;
|
||||||
|
else if( (didFlags[flagIndex + 16] & (1 << x)) == 0 )
|
||||||
|
stack[index++] = ((y + 1) << 8) | (z << 4) | x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( tX0 && tX1 ) solidX = false;
|
||||||
|
if( tY0 && tY1 ) solidY = false;
|
||||||
|
if( tZ0 && tZ1 ) solidZ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move to maprenderer
|
|
||||||
/*void SimpleOcclusionCulling() {
|
|
||||||
Vector3 p = game.LocalPlayer.EyePosition;
|
|
||||||
for( int i = 0; i < chunks.Length; i++ ) {
|
|
||||||
ChunkInfo chunk = chunks[i];
|
|
||||||
chunk.Visible = true;
|
|
||||||
int cx = chunk.CentreX >> 4;
|
|
||||||
int cy = chunk.CentreY >> 4;
|
|
||||||
int cz = chunk.CentreZ >> 4;
|
|
||||||
|
|
||||||
int x1 = chunk.CentreX - 8, x2 = chunk.CentreX + 8;
|
|
||||||
int y1 = chunk.CentreY - 8, y2 = chunk.CentreY + 8;
|
|
||||||
int z1 = chunk.CentreZ - 8, z2 = chunk.CentreZ + 8;
|
|
||||||
float minDist = float.PositiveInfinity;
|
|
||||||
int xOffset = -1, yOffset = 0, zOffset = 0;
|
|
||||||
|
|
||||||
// TODO: two axes with same distance
|
|
||||||
minDist = DistToRecSquared( p, x1, y1, z1, x1, y2, z2 ); // left
|
|
||||||
float rightDist = DistToRecSquared( p, x2, y1, z1, x2, y2, z2 );
|
|
||||||
if( rightDist < minDist ) {
|
|
||||||
minDist = rightDist; xOffset = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float frontDist = DistToRecSquared( p, x1, y1, z1, x2, y2, z1 );
|
|
||||||
if( frontDist < minDist ) {
|
|
||||||
minDist = frontDist; xOffset = 0; zOffset = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float backDist = DistToRecSquared( p, x1, y1, z2, x2, y2, z2 );
|
|
||||||
if( backDist < minDist ) {
|
|
||||||
minDist = backDist; xOffset = 0; zOffset = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float bottomDist = DistToRecSquared( p, x1, y1, z1, x2, y1, z2 );
|
|
||||||
if( bottomDist < minDist ) {
|
|
||||||
minDist = bottomDist; xOffset = 0; zOffset = 0; yOffset = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float topDist = DistToRecSquared( p, x1, y2, z1, x2, y2, z2 );
|
|
||||||
if( topDist < minDist ) {
|
|
||||||
minDist = topDist; xOffset = 0; zOffset = 0; yOffset = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( (cx + xOffset) >= 0 && (cy + yOffset) >= 0 && (cz + zOffset) >= 0 &&
|
|
||||||
(cx + xOffset) < width && (cy + yOffset) < height && (cz + zOffset) < length ) {
|
|
||||||
chunk.Visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chunks[0].Visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float DistToRecSquared( Vector3 p, int x1, int y1, int z1, int x2, int y2, int z2 ) {
|
|
||||||
float dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
|
|
||||||
float dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
|
||||||
float dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
|
||||||
return dx * dx + dy * dy + dz * dz;
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -101,7 +101,8 @@ namespace ClassicalSharp {
|
|||||||
return allAir || allSolid;
|
return allAir || allSolid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetDrawInfo( int x, int y, int z, ref ChunkPartInfo[] normalParts, ref ChunkPartInfo[] translucentParts ) {
|
public void GetDrawInfo( int x, int y, int z, ref ChunkPartInfo[] normalParts,
|
||||||
|
ref ChunkPartInfo[] translucentParts, ref byte occlusionFlags ) {
|
||||||
if( !BuildChunk( x, y, z ) )
|
if( !BuildChunk( x, y, z ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -109,6 +110,8 @@ namespace ClassicalSharp {
|
|||||||
SetPartInfo( drawInfoNormal[i], i, ref normalParts );
|
SetPartInfo( drawInfoNormal[i], i, ref normalParts );
|
||||||
SetPartInfo( drawInfoTranslucent[i], i, ref translucentParts );
|
SetPartInfo( drawInfoTranslucent[i], i, ref translucentParts );
|
||||||
}
|
}
|
||||||
|
if( normalParts != null || translucentParts != null )
|
||||||
|
occlusionFlags = 0;//(byte)ComputeOcclusion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderTile( int chunkIndex, int xx, int yy, int zz, int x, int y, int z ) {
|
public void RenderTile( int chunkIndex, int xx, int yy, int zz, int x, int y, int z ) {
|
||||||
@ -156,6 +159,7 @@ namespace ClassicalSharp {
|
|||||||
int xMax = Math.Min( width, x1 + chunkSize );
|
int xMax = Math.Min( width, x1 + chunkSize );
|
||||||
int yMax = Math.Min( height, y1 + chunkSize );
|
int yMax = Math.Min( height, y1 + chunkSize );
|
||||||
int zMax = Math.Min( length, z1 + chunkSize );
|
int zMax = Math.Min( length, z1 + chunkSize );
|
||||||
|
|
||||||
for( int y = y1, yy = 0; y < yMax; y++, yy++ ) {
|
for( int y = y1, yy = 0; y < yMax; y++, yy++ ) {
|
||||||
for( int z = z1, zz = 0; z < zMax; z++, zz++ ) {
|
for( int z = z1, zz = 0; z < zMax; z++, zz++ ) {
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ namespace ClassicalSharp {
|
|||||||
public bool Visible = true;
|
public bool Visible = true;
|
||||||
public bool Empty = false;
|
public bool Empty = false;
|
||||||
public bool DrawLeft, DrawRight, DrawFront, DrawBack, DrawBottom, DrawTop;
|
public bool DrawLeft, DrawRight, DrawFront, DrawBack, DrawBottom, DrawTop;
|
||||||
|
public byte OcclusionFlags;
|
||||||
|
|
||||||
public ChunkPartInfo[] NormalParts;
|
public ChunkPartInfo[] NormalParts;
|
||||||
public ChunkPartInfo[] TranslucentParts;
|
public ChunkPartInfo[] TranslucentParts;
|
||||||
@ -130,6 +131,7 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
void DeleteChunk( ChunkInfo info ) {
|
void DeleteChunk( ChunkInfo info ) {
|
||||||
info.Empty = false;
|
info.Empty = false;
|
||||||
|
info.OcclusionFlags = 0;
|
||||||
DeleteData( ref info.NormalParts );
|
DeleteData( ref info.NormalParts );
|
||||||
DeleteData( ref info.TranslucentParts );
|
DeleteData( ref info.TranslucentParts );
|
||||||
}
|
}
|
||||||
@ -272,10 +274,10 @@ namespace ClassicalSharp {
|
|||||||
if( inRange && chunksUpdatedThisFrame < chunksTarget ) {
|
if( inRange && chunksUpdatedThisFrame < chunksTarget ) {
|
||||||
game.ChunkUpdates++;
|
game.ChunkUpdates++;
|
||||||
builder.GetDrawInfo( info.CentreX - 8, info.CentreY - 8, info.CentreZ - 8,
|
builder.GetDrawInfo( info.CentreX - 8, info.CentreY - 8, info.CentreZ - 8,
|
||||||
ref info.NormalParts, ref info.TranslucentParts );
|
ref info.NormalParts, ref info.TranslucentParts, ref info.OcclusionFlags );
|
||||||
if( info.NormalParts == null && info.TranslucentParts == null ) {
|
|
||||||
|
if( info.NormalParts == null && info.TranslucentParts == null )
|
||||||
info.Empty = true;
|
info.Empty = true;
|
||||||
}
|
|
||||||
chunksUpdatedThisFrame++;
|
chunksUpdatedThisFrame++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,5 +331,68 @@ namespace ClassicalSharp {
|
|||||||
api.AlphaBlending = false;
|
api.AlphaBlending = false;
|
||||||
api.Texturing = false;
|
api.Texturing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimpleOcclusionCulling() { // TODO: broken
|
||||||
|
Vector3 p = game.LocalPlayer.EyePosition;
|
||||||
|
for( int i = 0; i < chunks.Length; i++ ) {
|
||||||
|
ChunkInfo chunk = chunks[i];
|
||||||
|
chunk.Visible = true;
|
||||||
|
int cx = chunk.CentreX >> 4;
|
||||||
|
int cy = chunk.CentreY >> 4;
|
||||||
|
int cz = chunk.CentreZ >> 4;
|
||||||
|
|
||||||
|
int x1 = chunk.CentreX - 8, x2 = chunk.CentreX + 8;
|
||||||
|
int y1 = chunk.CentreY - 8, y2 = chunk.CentreY + 8;
|
||||||
|
int z1 = chunk.CentreZ - 8, z2 = chunk.CentreZ + 8;
|
||||||
|
float minDist = float.PositiveInfinity;
|
||||||
|
int xOffset = -1, yOffset = 0, zOffset = 0;
|
||||||
|
int flags = 0x1;
|
||||||
|
|
||||||
|
// TODO: two axes with same distance
|
||||||
|
minDist = DistToRecSquared( p, x1, y1, z1, x1, y2, z2 ); // left
|
||||||
|
float rightDist = DistToRecSquared( p, x2, y1, z1, x2, y2, z2 );
|
||||||
|
if( rightDist < minDist ) {
|
||||||
|
minDist = rightDist; xOffset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float frontDist = DistToRecSquared( p, x1, y1, z1, x2, y2, z1 );
|
||||||
|
if( frontDist < minDist ) {
|
||||||
|
minDist = frontDist; xOffset = 0; zOffset = -1; flags = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float backDist = DistToRecSquared( p, x1, y1, z2, x2, y2, z2 );
|
||||||
|
if( backDist < minDist ) {
|
||||||
|
minDist = backDist; xOffset = 0; zOffset = 1; flags = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float bottomDist = DistToRecSquared( p, x1, y1, z1, x2, y1, z2 );
|
||||||
|
if( bottomDist < minDist ) {
|
||||||
|
minDist = bottomDist; xOffset = 0; zOffset = 0; yOffset = -1; flags = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
float topDist = DistToRecSquared( p, x1, y2, z1, x2, y2, z2 );
|
||||||
|
if( topDist < minDist ) {
|
||||||
|
minDist = topDist; xOffset = 0; zOffset = 0; yOffset = -1; flags = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (cx + xOffset) >= 0 && (cy + yOffset) >= 0 && (cz + zOffset) >= 0 &&
|
||||||
|
(cx + xOffset) < chunksX && (cy + yOffset) < chunksY && (cz + zOffset) < chunksZ ) {
|
||||||
|
cx += xOffset; cy += yOffset; cz += zOffset;
|
||||||
|
ChunkInfo neighbour = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||||
|
if( (neighbour.OcclusionFlags & flags) != 0 ) {
|
||||||
|
Console.WriteLine( "HIDE" );
|
||||||
|
chunks[i].Visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chunks[0].Visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float DistToRecSquared( Vector3 p, int x1, int y1, int z1, int x2, int y2, int z2 ) {
|
||||||
|
float dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
|
||||||
|
float dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
||||||
|
float dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
||||||
|
return dx * dx + dy * dy + dz * dz;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user