Как правильно рассчитать окклюзию окружающей среды (AO) на угол для сетки вокселей ⇐ C#

Место общения программистов C#
Anonymous
Как правильно рассчитать окклюзию окружающей среды (AO) на угол для сетки вокселей

Сообщение Anonymous »

Я работаю над двигателем вокселя в C#, где я строю кусок сетки лицом к лицу. Каждое лицо вокселя представляет собой четверку с 4 вершинами, и я хочу реализовать окклюзию окружающей среды (AO), чтобы затемнить вершины на основе окружающих блоков, чтобы дать более плавный эффект освещения. < /P>

Код: Выделить всё

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

Вернуться в «C#»