Код: Выделить всё
using System;
using System.Collections.Generic;
using System.Numerics;
using VoxleEngine.Graphics;
namespace VoxleEngine.World;
public static class ChunkMeshBuilder
{
private static readonly Vector3[] FaceDirections =
{
new Vector3(0, 0, -1), // Back (Z-)
new Vector3(0, 0, 1), // Front (Z+)
new Vector3(0, -1, 0), // Bottom (Y-)
new Vector3(0, 1, 0), // Top (Y+)
new Vector3(1, 0, 0), // Right (X+)
new Vector3(-1, 0, 0), // Left (X-)
};
// Each face: 4 vertices, ordered CCW when looking at the face from outside
private static readonly Vector3[][] FaceVertexPositions =
{
// Back (Z-) face - CCW from outside looking at -Z
new Vector3[]
{
new(0, 1, 0), // top-left
new(1, 1, 0), // top-right
new(1, 0, 0), // bottom-right
new(0, 0, 0), // bottom-left
},
// Front (Z+) face - CCW from outside looking at +Z
new Vector3[]
{
new(0, 0, 1), // bottom-left
new(1, 0, 1), // bottom-right
new(1, 1, 1), // top-right
new(0, 1, 1), // top-left
},
// Bottom (Y-) face - CCW looking down (Y-)
new Vector3[]
{
new(0, 0, 0), // back-left
new(1, 0, 0), // back-right
new(1, 0, 1), // front-right
new(0, 0, 1), // front-left
},
// Top (Y+) face - CCW looking up (Y+)
new Vector3[]
{
new(0, 1, 1), // front-left
new(1, 1, 1), // front-right
new(1, 1, 0), // back-right
new(0, 1, 0), // back-left
},
// Right (X+) face - CCW looking from +X
new Vector3[]
{
new(1, 1, 0), // top-back
new(1, 1, 1), // top-front
new(1, 0, 1), // bottom-front
new(1, 0, 0), // bottom-back
},
// Left (X-) face - CCW looking from -X
new Vector3[]
{
new(0, 1, 1), // top-front
new(0, 1, 0), // top-back
new(0, 0, 0), // bottom-back
new(0, 0, 1), // bottom-front
},
};
// UVs per face - only flip the faces that are actually upside down
private static readonly Vector2[][] FaceUVs =
{
// Back face - normal UV (appears correct)
new Vector2[]
{
new(0, 1), // top-left
new(1, 1), // top-right
new(1, 0), // bottom-right
new(0, 0), // bottom-left
},
// Front face - flip V (was upside down)
new Vector2[]
{
new(0, 0), // bottom-left
new(1, 0), // bottom-right
new(1, 1), // top-right
new(0, 1), // top-left
},
// Bottom face - flip V (was upside down)
new Vector2[]
{
new(0, 0),
new(1, 0),
new(1, 1),
new(0, 1),
},
// Top face - normal UV (appears correct)
new Vector2[]
{
new(0, 1),
new(1, 1),
new(1, 0),
new(0, 0),
},
// Right face - normal UV (test if this one is correct)
new Vector2[]
{
new(0, 1),
new(1, 1),
new(1, 0),
new(0, 0),
},
// Left face - normal UV (test if this one is correct)
new Vector2[]
{
new(0, 1),
new(1, 1),
new(1, 0),
new(0, 0),
},
};
private static readonly uint[] FaceIndices = { 0, 1, 2, 2, 3, 0 }; // two triangles per quad
public static bool IsVoid(World world, int wx, int wy, int wz)
{
int cx = wx / Chunk.ChunkSize;
int cy = wy / Chunk.ChunkSize;
int cz = wz / Chunk.ChunkSize;
Chunk chunk = world.GetChunk(cx, cy, cz);
if (chunk == null)
return true; // treat missing chunks as void
int lx = wx % Chunk.ChunkSize;
int ly = wy % Chunk.ChunkSize;
int lz = wz % Chunk.ChunkSize;
Block block = chunk.GetBlock(lx, ly, lz);
return block.Type == BlockType.Air;
}
private static float CalculateAO(int wx, int wy, int wz, World world)
{
return 1.0f;
}
public static Mesh BuildMesh(World world, Chunk chunk)
{
List vertices = new();
List indices = new();
uint indexOffset = 0;
Color color = Color.White; // or your block color logic
for (int x = 0; x < Chunk.ChunkSize; x++)
{
for (int y = 0; y < Chunk.ChunkSize; y++)
{
for (int z = 0; z < Chunk.ChunkSize; z++)
{
Block block = chunk.GetBlock(x, y, z);
if (block.Type == BlockType.Air)
continue;
for (int face = 0; face < 6; face++)
{
Vector3 dir = FaceDirections[face];
int wx = (int)chunk.Position.X * Chunk.ChunkSize + x;
int wy = (int)chunk.Position.Y * Chunk.ChunkSize + y;
int wz = (int)chunk.Position.Z * Chunk.ChunkSize + z;
int nwx = wx + (int)dir.X;
int nwy = wy + (int)dir.Y;
int nwz = wz + (int)dir.Z;
// Skip if neighbor is solid
if (!IsVoid(world, nwx, nwy, nwz))
continue;
// Add vertices for this face
Vector3[] posOffsets = FaceVertexPositions[face];
for (int i = 0; i < 4; i++)
{
Vector3 pos = new Vector3(x, y, z) + posOffsets[i];
vertices.Add(pos.X);
vertices.Add(pos.Y);
vertices.Add(pos.Z);
// Normal (face direction)
vertices.Add(dir.X);
vertices.Add(dir.Y);
vertices.Add(dir.Z);
// Color (white or your block color)
vertices.Add(color.R);
vertices.Add(color.G);
vertices.Add(color.B);
// AO - set to 1 for now (no ambient occlusion)
float ao = CalculateAO(wx, wy, wz, world);
vertices.Add(ao);
// UV
Vector2 uv = FaceUVs[face][i];
vertices.Add(uv.X);
vertices.Add(uv.Y);
// Texture index for this face (you should implement this method)
int textureIndex = block.GetTextureIndexForFace(face);
vertices.Add(textureIndex);
}
// Add indices for two triangles of the face
foreach (var index in FaceIndices)
{
indices.Add(indexOffset + index);
}
indexOffset += 4;
}
}
}
}
VertexAttribute[] layout = new VertexAttribute[]
{
new(3, VertexAttributeType.Float), // Position
new(3, VertexAttributeType.Float), // Normal
new(3, VertexAttributeType.Float), // Color
new(1, VertexAttributeType.Float), // AO
new(2, VertexAttributeType.Float), // UV
new(1, VertexAttributeType.Float), // Texture index
};
return new Mesh(vertices.ToArray(), indices.ToArray(), layout);
}
}
Подробнее здесь: https://stackoverflow.com/questions/796 ... -mesh-face