Fixed negative chunks invisible
This commit is contained in:
@@ -48,6 +48,8 @@ namespace Voxel
|
||||
|
||||
public new void Tick()
|
||||
{
|
||||
_world.UpdateChunkLoading(Position);
|
||||
|
||||
previousPosition = Position;
|
||||
|
||||
float forwards = 0;
|
||||
|
||||
@@ -14,8 +14,8 @@ internal class Program
|
||||
|
||||
Console.WriteLine("Generating map...");
|
||||
|
||||
int worldSizeX = 8;
|
||||
int worldSizeY = 8;
|
||||
int worldSizeX = 2;
|
||||
int worldSizeY = 2;
|
||||
|
||||
float maxI = worldSizeX * worldSizeY;
|
||||
int i = 0;
|
||||
|
||||
@@ -61,11 +61,12 @@ namespace Voxel
|
||||
if (_world == null) return;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
foreach (Chunk chunk in _world.GetAllChunks())
|
||||
{
|
||||
ChunkMesh chunkMesh = chunk.GetChunkMesh();
|
||||
|
||||
if (chunkMesh.NeedsUpdate)
|
||||
if (chunkMesh.NeedsUpdate) // always true
|
||||
{
|
||||
byte[] data = chunkMesh.GetPackedData();
|
||||
GL.BufferSubData(BufferTarget.ShaderStorageBuffer, (IntPtr)offset * 8, chunkMesh.Size * 8, data);
|
||||
|
||||
@@ -10,16 +10,23 @@ uniform vec3 cameraPosition;
|
||||
|
||||
void main()
|
||||
{
|
||||
float fogEnd = 512;
|
||||
float fogStart = 32;
|
||||
|
||||
float dist = length(cameraPosition - fragPos);
|
||||
float fogFactor = (fogEnd - dist) / (fogEnd - fogStart);
|
||||
fogFactor = clamp(fogFactor, 0, 1);
|
||||
|
||||
vec4 fogColor = vec4(0.8,0.8,0.8,1);
|
||||
vec4 texColor = texture(uTexture, fragUV) * lighting;
|
||||
vec4 color = mix(fogColor, texColor, fogFactor);
|
||||
|
||||
FragColor = vec4(color.rgb, texColor.a);
|
||||
// Use squared distance
|
||||
vec3 delta = cameraPosition - fragPos;
|
||||
float distSq = dot(delta, delta);
|
||||
|
||||
// Precomputed fog parameters
|
||||
const float fogEndSq = 16384.0; // 128^2
|
||||
const float fogStartSq = 1024.0; // 32^2
|
||||
const float fogRangeInv = 1.0 / (fogEndSq - fogStartSq);
|
||||
|
||||
float fogFactor = (fogEndSq - distSq) * fogRangeInv;
|
||||
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||
|
||||
// Texture and lighting
|
||||
vec4 texColor = texture(uTexture, fragUV);
|
||||
texColor.rgb *= lighting;
|
||||
|
||||
// Fog blend
|
||||
const vec3 fogColor = vec3(0.8, 0.8, 0.8);
|
||||
FragColor = vec4(mix(fogColor, texColor.rgb, fogFactor), texColor.a);
|
||||
}
|
||||
@@ -82,7 +82,7 @@ void main()
|
||||
uint faceIndex = gl_VertexID / 6u;
|
||||
uint vertIndex = gl_VertexID % 6u;
|
||||
|
||||
uint start = faceIndex * 2u; // 2 byte per face
|
||||
uint start = faceIndex * 2u; // 2 uint per face
|
||||
|
||||
uint u0 = faces[start]; // data in uint 0
|
||||
uint u1 = faces[start + 1]; // data in uint 1
|
||||
@@ -95,7 +95,8 @@ void main()
|
||||
uint texture = u1 & 0xFFu;
|
||||
uint lightLevel = (u1 >> 8) & 0xFFu;
|
||||
|
||||
vec3 basePos = vec3(x + chunkX * 16, y, z + chunkY * 16);
|
||||
vec3 basePos = vec3(x, y, z) + vec3(chunkX, 0, chunkY) * 16.0;
|
||||
|
||||
vec4 worldPos = vec4(basePos + offsets[facing][vertIndex], 1.0);
|
||||
float light = float(lightLevel) / 255.0; // use later for caves and stuff
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Voxel
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
|
||||
CursorState = CursorState.Grabbed;
|
||||
//VSync = VSyncMode.On;
|
||||
VSync = VSyncMode.On;
|
||||
|
||||
Camera.UpdateSize(Width, Height);
|
||||
}
|
||||
|
||||
111
World.cs
111
World.cs
@@ -8,6 +8,9 @@ namespace Voxel
|
||||
{
|
||||
private Dictionary<(int, int), Chunk> _chunks;
|
||||
|
||||
private (int x, int z) _lastCenter = (0, 0);
|
||||
private int _loadDistance = 4;
|
||||
|
||||
private static readonly Dictionary<Orientation, (int x, int y)> _neighborOffsets = new()
|
||||
{
|
||||
{ Orientation.West, (1, 0) },
|
||||
@@ -33,6 +36,7 @@ namespace Voxel
|
||||
|
||||
UpdateNeighboringChunks(chunk);
|
||||
chunk.UpdateChunkMesh();
|
||||
Renderer.MarkBuffersDirty();
|
||||
}
|
||||
|
||||
public void RemoveChunk(int chunkX, int chunkZ)
|
||||
@@ -52,6 +56,63 @@ namespace Voxel
|
||||
}
|
||||
}
|
||||
|
||||
public new void UpdateChunkLoading(Vector3 playerPosition)
|
||||
{
|
||||
int centerX = (int)Math.Floor(playerPosition.X / Chunk.Size);
|
||||
int centerZ = (int)Math.Floor(playerPosition.Z / Chunk.Size);
|
||||
|
||||
// Quick check - skip if still in same chunk
|
||||
if (centerX == _lastCenter.x && centerZ == _lastCenter.z)
|
||||
return;
|
||||
|
||||
_lastCenter = (centerX, centerZ);
|
||||
|
||||
// Calculate bounds
|
||||
int minX = centerX - _loadDistance;
|
||||
int maxX = centerX + _loadDistance;
|
||||
int minZ = centerZ - _loadDistance;
|
||||
int maxZ = centerZ + _loadDistance;
|
||||
|
||||
// Unload chunks outside range
|
||||
UnloadDistantChunks(minX, maxX, minZ, maxZ);
|
||||
|
||||
// Load chunks inside range
|
||||
LoadChunksInRange(minX, maxX, minZ, maxZ);
|
||||
}
|
||||
|
||||
private void UnloadDistantChunks(int minX, int maxX, int minZ, int maxZ)
|
||||
{
|
||||
var chunksToRemove = new List<(int, int)>();
|
||||
|
||||
foreach (var (chunkX, chunkZ) in _chunks.Keys)
|
||||
{
|
||||
if (chunkX < minX || chunkX > maxX || chunkZ < minZ || chunkZ > maxZ)
|
||||
{
|
||||
chunksToRemove.Add((chunkX, chunkZ));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var chunkPos in chunksToRemove)
|
||||
{
|
||||
RemoveChunk(chunkPos.Item1, chunkPos.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadChunksInRange(int minX, int maxX, int minZ, int maxZ)
|
||||
{
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int z = minZ; z <= maxZ; z++)
|
||||
{
|
||||
if (!_chunks.ContainsKey((x, z)))
|
||||
{
|
||||
Chunk chunk = new Chunk(x, z);
|
||||
AddChunk(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateNeighboringChunks(Chunk chunk)
|
||||
{
|
||||
chunk.Neighbors[Orientation.West] = null;
|
||||
@@ -87,39 +148,21 @@ namespace Voxel
|
||||
|
||||
public Blocks GetBlock(int worldX, int worldY, int worldZ)
|
||||
{
|
||||
int chunkX = worldX / Chunk.Size;
|
||||
int chunkZ = worldZ / Chunk.Size;
|
||||
var (chunkX, chunkZ, localX, localZ) = WorldToChunkCoords(worldX, worldZ);
|
||||
|
||||
Chunk chunk = GetChunk(chunkX, chunkZ);
|
||||
if (chunk == null) return 0; // air if chunk not loaded
|
||||
|
||||
int localX = worldX % Chunk.Size;
|
||||
int localZ = worldZ % Chunk.Size;
|
||||
|
||||
return chunk.GetBlock(localX, worldY, localZ);
|
||||
}
|
||||
|
||||
List<Orientation> GetEdgeOrientations(int localX, int localZ, int size)
|
||||
{
|
||||
var orientations = new List<Orientation>();
|
||||
|
||||
if (localX == size - 1) orientations.Add(Orientation.West);
|
||||
if (localX == 0) orientations.Add(Orientation.East);
|
||||
if (localZ == size - 1) orientations.Add(Orientation.North);
|
||||
if (localZ == 0) orientations.Add(Orientation.South);
|
||||
|
||||
return orientations;
|
||||
}
|
||||
|
||||
public void SetBlock(int worldX, int worldY, int worldZ, Blocks block)
|
||||
{
|
||||
int chunkX = worldX / Chunk.Size;
|
||||
int chunkZ = worldZ / Chunk.Size;
|
||||
var (chunkX, chunkZ, localX, localZ) = WorldToChunkCoords(worldX, worldZ);
|
||||
|
||||
Chunk chunk = GetChunk(chunkX, chunkZ);
|
||||
if (chunk == null) return;
|
||||
|
||||
int localX = worldX % Chunk.Size;
|
||||
int localZ = worldZ % Chunk.Size;
|
||||
|
||||
chunk.SetBlock(localX, worldY, localZ, block);
|
||||
|
||||
if (block == Blocks.Air && ((localX == Chunk.Size - 1 || localX == 0) || (localZ == Chunk.Size - 1 || localZ == 0)))
|
||||
@@ -134,6 +177,30 @@ namespace Voxel
|
||||
}
|
||||
}
|
||||
|
||||
public static (int chunkX, int chunkZ, int localX, int localZ) WorldToChunkCoords(int worldX, int worldZ)
|
||||
{
|
||||
int chunkX = worldX >= 0 ? worldX / Chunk.Size : (worldX + 1) / Chunk.Size - 1;
|
||||
int chunkZ = worldZ >= 0 ? worldZ / Chunk.Size : (worldZ + 1) / Chunk.Size - 1;
|
||||
|
||||
int localX = ((worldX % Chunk.Size) + Chunk.Size) % Chunk.Size;
|
||||
int localZ = ((worldZ % Chunk.Size) + Chunk.Size) % Chunk.Size;
|
||||
|
||||
return (chunkX, chunkZ, localX, localZ);
|
||||
}
|
||||
|
||||
|
||||
List<Orientation> GetEdgeOrientations(int localX, int localZ, int size)
|
||||
{
|
||||
var orientations = new List<Orientation>();
|
||||
|
||||
if (localX == size - 1) orientations.Add(Orientation.West);
|
||||
if (localX == 0) orientations.Add(Orientation.East);
|
||||
if (localZ == size - 1) orientations.Add(Orientation.North);
|
||||
if (localZ == 0) orientations.Add(Orientation.South);
|
||||
|
||||
return orientations;
|
||||
}
|
||||
|
||||
public IEnumerable<(Orientation orientation, Chunk neighbor)> GetChunkNeighbors(Chunk chunk)
|
||||
{
|
||||
int chunkX = chunk.X;
|
||||
|
||||
Reference in New Issue
Block a user