what if minecraft ran on the GPU exclusively? glad you asked! because now it can
This commit is contained in:
parent
fa7bf893e7
commit
bf9af81f38
41 changed files with 2433 additions and 34 deletions
|
|
@ -0,0 +1,236 @@
|
||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||||
|
|
||||||
|
const int CHUNK_SIZE = 16;
|
||||||
|
const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
const int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
|
||||||
|
const uint FLOATS_PER_VERTEX = 14u;
|
||||||
|
const uint VERTICES_PER_FACE = 4u;
|
||||||
|
const uint INDICES_PER_FACE = 6u;
|
||||||
|
|
||||||
|
const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * 12);
|
||||||
|
const uint MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * VERTICES_PER_FACE;
|
||||||
|
const uint MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * INDICES_PER_FACE;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) readonly buffer VoxelData {
|
||||||
|
uint voxels[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer VertexBuffer {
|
||||||
|
float vertices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) buffer IndexBuffer {
|
||||||
|
uint indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3) buffer DrawCommand {
|
||||||
|
uint indexCount;
|
||||||
|
uint instanceCount;
|
||||||
|
uint firstIndex;
|
||||||
|
int vertexOffset;
|
||||||
|
uint firstInstance;
|
||||||
|
} drawCmd;
|
||||||
|
|
||||||
|
layout(std430, binding = 4) buffer Counters {
|
||||||
|
uint vertexCount;
|
||||||
|
uint indexCount;
|
||||||
|
} counters;
|
||||||
|
|
||||||
|
layout(push_constant) uniform ChunkInfo {
|
||||||
|
ivec3 chunkPos;
|
||||||
|
int padding0;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint flatten(ivec3 pos) {
|
||||||
|
return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getVoxel(ivec3 pos) {
|
||||||
|
if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0;
|
||||||
|
if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0;
|
||||||
|
if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0;
|
||||||
|
|
||||||
|
return voxels[flatten(pos)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeVertex(uint vertexIndex,vec3 position,vec3 normal,
|
||||||
|
vec3 tangent,vec3 bitangent,vec2 uv) {
|
||||||
|
uint base = vertexIndex * FLOATS_PER_VERTEX;
|
||||||
|
|
||||||
|
vertices[base + 0u] = position.x;
|
||||||
|
vertices[base + 1u] = position.y;
|
||||||
|
vertices[base + 2u] = position.z;
|
||||||
|
|
||||||
|
vertices[base + 3u] = normal.x;
|
||||||
|
vertices[base + 4u] = normal.y;
|
||||||
|
vertices[base + 5u] = normal.z;
|
||||||
|
|
||||||
|
vertices[base + 6u] = tangent.x;
|
||||||
|
vertices[base + 7u] = tangent.y;
|
||||||
|
vertices[base + 8u] = tangent.z;
|
||||||
|
|
||||||
|
vertices[base + 9u] = bitangent.x;
|
||||||
|
vertices[base + 10u] = bitangent.y;
|
||||||
|
vertices[base + 11u] = bitangent.z;
|
||||||
|
|
||||||
|
vertices[base + 12u] = uv.x;
|
||||||
|
vertices[base + 13u] = uv.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitFace(ivec3 voxelPos, int faceIndex) {
|
||||||
|
uint baseVertex = atomicAdd(counters.vertexCount, VERTICES_PER_FACE);
|
||||||
|
uint baseIndex = atomicAdd(counters.indexCount, INDICES_PER_FACE);
|
||||||
|
|
||||||
|
if (baseVertex + VERTICES_PER_FACE > MAX_VERTICES ||
|
||||||
|
baseIndex + INDICES_PER_FACE > MAX_INDICES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 p = vec3(chunkPos * CHUNK_SIZE + voxelPos);
|
||||||
|
|
||||||
|
vec3 normal;
|
||||||
|
vec3 tangent;
|
||||||
|
vec3 bitangent;
|
||||||
|
|
||||||
|
|
||||||
|
vec3 v0;
|
||||||
|
vec3 v1;
|
||||||
|
vec3 v2;
|
||||||
|
vec3 v3;
|
||||||
|
|
||||||
|
vec2 uv0;
|
||||||
|
vec2 uv1;
|
||||||
|
vec2 uv2;
|
||||||
|
vec2 uv3;
|
||||||
|
|
||||||
|
if (faceIndex == 0) {
|
||||||
|
// Top +Y
|
||||||
|
normal = vec3(0.0, 1.0, 0.0);
|
||||||
|
tangent = vec3(1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 1.0, 0.0);
|
||||||
|
v1 = p + vec3(0.0, 1.0, 1.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(1.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
|
||||||
|
uv0 = vec2(0.0, 0.5);
|
||||||
|
uv1 = vec2(0.0, 1.0);
|
||||||
|
uv2 = vec2(0.5, 1.0);
|
||||||
|
uv3 = vec2(0.5, 0.5);
|
||||||
|
} else if (faceIndex == 1) {
|
||||||
|
// Bottom -Y
|
||||||
|
normal = vec3(0.0, -1.0, 0.0);
|
||||||
|
tangent = vec3(1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(1.0, 0.0, 0.0);
|
||||||
|
v2 = p + vec3(1.0, 0.0, 1.0);
|
||||||
|
v3 = p + vec3(0.0, 0.0, 1.0);
|
||||||
|
uv0 = vec2(0.5, 0.0);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(1.0, 0.5);
|
||||||
|
uv3 = vec2(1.0, 0.0);
|
||||||
|
} else if (faceIndex == 2) {
|
||||||
|
// Right +X
|
||||||
|
normal = vec3(1.0, 0.0, 0.0);
|
||||||
|
tangent = vec3(0.0, 0.0, -1.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(1.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(1.0, 1.0, 0.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(1.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
uv0 = vec2(0.0, 0.0);
|
||||||
|
uv3 = vec2(0.0, 0.5);
|
||||||
|
uv2 = vec2(0.5, 0.5);
|
||||||
|
uv1 = vec2(0.5, 0.0);
|
||||||
|
} else if (faceIndex == 3) {
|
||||||
|
// Left -X
|
||||||
|
normal = vec3(-1.0, 0.0, 0.0);
|
||||||
|
tangent = vec3(0.0, 0.0, 1.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(0.0, 0.0, 1.0);
|
||||||
|
v2 = p + vec3(0.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
uv0 = vec2(0.0, 0.0);
|
||||||
|
uv1 = vec2(0.0, 0.5);
|
||||||
|
uv2 = vec2(0.5, 0.5);
|
||||||
|
uv3 = vec2(0.5, 0.0);
|
||||||
|
} else if (faceIndex == 4) {
|
||||||
|
// Front +Z
|
||||||
|
normal = vec3(0.0, 0.0, 1.0);
|
||||||
|
tangent = vec3(1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 1.0);
|
||||||
|
v1 = p + vec3(1.0, 0.0, 1.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(0.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
uv0 = vec2(0.0, 0.0);
|
||||||
|
uv1 = vec2(0.0, 0.5);
|
||||||
|
uv2 = vec2(0.5, 0.5);
|
||||||
|
uv3 = vec2(0.5, 0.0);
|
||||||
|
} else {
|
||||||
|
// Back -Z
|
||||||
|
normal = vec3(0.0, 0.0, -1.0);
|
||||||
|
tangent = vec3(-1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(0.0, 1.0, 0.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 0.0);
|
||||||
|
v3 = p + vec3(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
uv0 = vec2(0.0, 0.0);
|
||||||
|
uv1 = vec2(0.0, 0.5);
|
||||||
|
uv2 = vec2(0.5, 0.5);
|
||||||
|
uv3 = vec2(0.5, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeVertex(baseVertex + 0u, v0, normal, tangent, bitangent, uv0);
|
||||||
|
writeVertex(baseVertex + 1u, v1, normal, tangent, bitangent, uv1);
|
||||||
|
writeVertex(baseVertex + 2u, v2, normal, tangent, bitangent, uv2);
|
||||||
|
writeVertex(baseVertex + 3u, v3, normal, tangent, bitangent, uv3);
|
||||||
|
|
||||||
|
indices[baseIndex + 0u] = baseVertex + 0u;
|
||||||
|
indices[baseIndex + 1u] = baseVertex + 1u;
|
||||||
|
indices[baseIndex + 2u] = baseVertex + 2u;
|
||||||
|
|
||||||
|
indices[baseIndex + 3u] = baseVertex + 0u;
|
||||||
|
indices[baseIndex + 4u] = baseVertex + 2u;
|
||||||
|
indices[baseIndex + 5u] = baseVertex + 3u;
|
||||||
|
|
||||||
|
atomicAdd(drawCmd.indexCount, INDICES_PER_FACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
|
||||||
|
|
||||||
|
if (pos.x >= CHUNK_SIZE || pos.y >= CHUNK_SIZE || pos.z >= CHUNK_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint current = getVoxel(pos);
|
||||||
|
|
||||||
|
if (current == 0u) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u) emitFace(pos, 0);
|
||||||
|
if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1);
|
||||||
|
if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2);
|
||||||
|
if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3);
|
||||||
|
if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4);
|
||||||
|
if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,285 @@
|
||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||||
|
|
||||||
|
const int CHUNK_SIZE = 16;
|
||||||
|
const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
const int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
|
||||||
|
const uint FLOATS_PER_VERTEX = 14u;
|
||||||
|
const uint VERTICES_PER_FACE = 4u;
|
||||||
|
const uint INDICES_PER_FACE = 6u;
|
||||||
|
|
||||||
|
const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * 12);
|
||||||
|
const uint MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * VERTICES_PER_FACE;
|
||||||
|
const uint MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * INDICES_PER_FACE;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) readonly buffer VoxelData {
|
||||||
|
uint voxels[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer VertexBuffer {
|
||||||
|
float vertices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) buffer IndexBuffer {
|
||||||
|
uint indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawCommand {
|
||||||
|
uint indexCount;
|
||||||
|
uint instanceCount;
|
||||||
|
uint firstIndex;
|
||||||
|
int vertexOffset;
|
||||||
|
uint firstInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3) buffer DrawCommands {
|
||||||
|
DrawCommand drawCmds[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(push_constant) uniform ChunkInfo {
|
||||||
|
ivec3 chunkPos;
|
||||||
|
int slot;
|
||||||
|
uint vertexFloatOffset;
|
||||||
|
uint indexOffset;
|
||||||
|
uint indirectCommandIndex;
|
||||||
|
uint padding0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
layout(std430, binding = 4) buffer Counters {
|
||||||
|
uint vertexCount;
|
||||||
|
uint indexCount;
|
||||||
|
} counters;
|
||||||
|
|
||||||
|
|
||||||
|
uint flatten(ivec3 pos) {
|
||||||
|
return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getVoxel(ivec3 pos) {
|
||||||
|
if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0;
|
||||||
|
if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0;
|
||||||
|
if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0;
|
||||||
|
|
||||||
|
return voxels[flatten(pos)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeVertex(uint vertexIndex, vec3 position, vec3 normal, vec3 tangent, vec3 bitangent, vec2 uv) {
|
||||||
|
uint base = vertexFloatOffset + vertexIndex * FLOATS_PER_VERTEX;
|
||||||
|
|
||||||
|
vertices[base + 0u] = position.x;
|
||||||
|
vertices[base + 1u] = position.y;
|
||||||
|
vertices[base + 2u] = position.z;
|
||||||
|
|
||||||
|
vertices[base + 3u] = normal.x;
|
||||||
|
vertices[base + 4u] = normal.y;
|
||||||
|
vertices[base + 5u] = normal.z;
|
||||||
|
|
||||||
|
vertices[base + 6u] = tangent.x;
|
||||||
|
vertices[base + 7u] = tangent.y;
|
||||||
|
vertices[base + 8u] = tangent.z;
|
||||||
|
|
||||||
|
vertices[base + 9u] = bitangent.x;
|
||||||
|
vertices[base + 10u] = bitangent.y;
|
||||||
|
vertices[base + 11u] = bitangent.z;
|
||||||
|
|
||||||
|
vertices[base + 12u] = uv.x;
|
||||||
|
vertices[base + 13u] = uv.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitFace(ivec3 voxelPos, int faceIndex, uint VoxelType) {
|
||||||
|
uint localBaseVertex = atomicAdd(counters.vertexCount, VERTICES_PER_FACE);
|
||||||
|
uint localBaseIndex = atomicAdd(counters.indexCount, INDICES_PER_FACE);
|
||||||
|
|
||||||
|
if (localBaseVertex + VERTICES_PER_FACE > MAX_VERTICES ||
|
||||||
|
localBaseIndex + INDICES_PER_FACE > MAX_INDICES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint baseVertex = localBaseVertex;
|
||||||
|
uint baseIndex = indexOffset + localBaseIndex;
|
||||||
|
|
||||||
|
vec3 p = vec3(chunkPos * CHUNK_SIZE + voxelPos);
|
||||||
|
|
||||||
|
vec3 normal;
|
||||||
|
vec3 tangent;
|
||||||
|
vec3 bitangent;
|
||||||
|
|
||||||
|
|
||||||
|
vec3 v0;
|
||||||
|
vec3 v1;
|
||||||
|
vec3 v2;
|
||||||
|
vec3 v3;
|
||||||
|
|
||||||
|
vec2 uv0;
|
||||||
|
vec2 uv1;
|
||||||
|
vec2 uv2;
|
||||||
|
vec2 uv3;
|
||||||
|
|
||||||
|
if (faceIndex == 0) {
|
||||||
|
// Top +Y
|
||||||
|
normal = vec3(0.0, 1.0, 0.0);
|
||||||
|
tangent = vec3(1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 1.0, 0.0);
|
||||||
|
v1 = p + vec3(0.0, 1.0, 1.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(1.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
if(VoxelType == 1) {
|
||||||
|
uv0 = vec2(0.0, 0.5);
|
||||||
|
uv1 = vec2(0.0, 1.0);
|
||||||
|
uv2 = vec2(0.5, 1.0);
|
||||||
|
uv3 = vec2(0.5, 0.5);
|
||||||
|
} else{
|
||||||
|
uv0 = vec2(0.5, 0.0);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(1.0, 0.5);
|
||||||
|
uv3 = vec2(1.0, 0.0);
|
||||||
|
}
|
||||||
|
} else if (faceIndex == 1) {
|
||||||
|
// Bottom -Y
|
||||||
|
normal = vec3(0.0, -1.0, 0.0);
|
||||||
|
tangent = vec3(1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(1.0, 0.0, 0.0);
|
||||||
|
v2 = p + vec3(1.0, 0.0, 1.0);
|
||||||
|
v3 = p + vec3(0.0, 0.0, 1.0);
|
||||||
|
uv0 = vec2(0.5, 0.0);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(1.0, 0.5);
|
||||||
|
uv3 = vec2(1.0, 0.0);
|
||||||
|
} else if (faceIndex == 2) {
|
||||||
|
// Right +X
|
||||||
|
normal = vec3(1.0, 0.0, 0.0);
|
||||||
|
tangent = vec3(0.0, 0.0, -1.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(1.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(1.0, 1.0, 0.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(1.0, 0.0, 1.0);
|
||||||
|
if(VoxelType == 1) {
|
||||||
|
|
||||||
|
uv2 = vec2(0.0, 0.0);
|
||||||
|
uv3 = vec2(0.0, 0.5);
|
||||||
|
uv0 = vec2(0.5, 0.5);
|
||||||
|
uv1 = vec2(0.5, 0.0);
|
||||||
|
} else{
|
||||||
|
uv0 = vec2(0.5, 0.0);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(1.0, 0.5);
|
||||||
|
uv3 = vec2(1.0, 0.0);
|
||||||
|
}
|
||||||
|
} else if (faceIndex == 3) {
|
||||||
|
// Left -X
|
||||||
|
normal = vec3(-1.0, 0.0, 0.0);
|
||||||
|
tangent = vec3(0.0, 0.0, 1.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(0.0, 0.0, 1.0);
|
||||||
|
v2 = p + vec3(0.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
if(VoxelType == 1) {
|
||||||
|
|
||||||
|
uv3 = vec2(0.0, 0.0);
|
||||||
|
uv0 = vec2(0.0, 0.5);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(0.5, 0.0);
|
||||||
|
} else{
|
||||||
|
uv0 = vec2(0.5, 0.0);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(1.0, 0.5);
|
||||||
|
uv3 = vec2(1.0, 0.0);
|
||||||
|
}
|
||||||
|
} else if (faceIndex == 4) {
|
||||||
|
// Front +Z
|
||||||
|
normal = vec3(0.0, 0.0, 1.0);
|
||||||
|
tangent = vec3(1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 1.0);
|
||||||
|
v1 = p + vec3(1.0, 0.0, 1.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 1.0);
|
||||||
|
v3 = p + vec3(0.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
if(VoxelType == 1) {
|
||||||
|
|
||||||
|
uv3 = vec2(0.0, 0.0);
|
||||||
|
uv0 = vec2(0.0, 0.5);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(0.5, 0.0);
|
||||||
|
} else{
|
||||||
|
uv0 = vec2(0.5, 0.0);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(1.0, 0.5);
|
||||||
|
uv3 = vec2(1.0, 0.0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Back -Z
|
||||||
|
normal = vec3(0.0, 0.0, -1.0);
|
||||||
|
tangent = vec3(-1.0, 0.0, 0.0);
|
||||||
|
bitangent = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
v0 = p + vec3(0.0, 0.0, 0.0);
|
||||||
|
v1 = p + vec3(0.0, 1.0, 0.0);
|
||||||
|
v2 = p + vec3(1.0, 1.0, 0.0);
|
||||||
|
v3 = p + vec3(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
if(VoxelType == 1) {
|
||||||
|
|
||||||
|
uv2 = vec2(0.0, 0.0);
|
||||||
|
uv3 = vec2(0.0, 0.5);
|
||||||
|
uv0 = vec2(0.5, 0.5);
|
||||||
|
uv1 = vec2(0.5, 0.0);
|
||||||
|
} else{
|
||||||
|
uv0 = vec2(0.5, 0.0);
|
||||||
|
uv1 = vec2(0.5, 0.5);
|
||||||
|
uv2 = vec2(1.0, 0.5);
|
||||||
|
uv3 = vec2(1.0, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeVertex(baseVertex + 0u, v0, normal, tangent, bitangent, uv0);
|
||||||
|
writeVertex(baseVertex + 1u, v1, normal, tangent, bitangent, uv1);
|
||||||
|
writeVertex(baseVertex + 2u, v2, normal, tangent, bitangent, uv2);
|
||||||
|
writeVertex(baseVertex + 3u, v3, normal, tangent, bitangent, uv3);
|
||||||
|
|
||||||
|
indices[baseIndex + 0u] = baseVertex + 0u;
|
||||||
|
indices[baseIndex + 1u] = baseVertex + 1u;
|
||||||
|
indices[baseIndex + 2u] = baseVertex + 2u;
|
||||||
|
|
||||||
|
indices[baseIndex + 3u] = baseVertex + 0u;
|
||||||
|
indices[baseIndex + 4u] = baseVertex + 2u;
|
||||||
|
indices[baseIndex + 5u] = baseVertex + 3u;
|
||||||
|
|
||||||
|
atomicAdd(drawCmds[indirectCommandIndex].indexCount, INDICES_PER_FACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
|
||||||
|
|
||||||
|
if (pos.x >= CHUNK_SIZE || pos.y >= CHUNK_SIZE || pos.z >= CHUNK_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint current = getVoxel(pos);
|
||||||
|
|
||||||
|
if (current == 0u) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u) emitFace(pos, 0,current);
|
||||||
|
if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1,current);
|
||||||
|
if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2,current);
|
||||||
|
if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3,current);
|
||||||
|
if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4,current);
|
||||||
|
if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5,current);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer DrawCommand {
|
||||||
|
uint indexCount;
|
||||||
|
uint instanceCount;
|
||||||
|
uint firstIndex;
|
||||||
|
int vertexOffset;
|
||||||
|
uint firstInstance;
|
||||||
|
} drawCmd;
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer Counters {
|
||||||
|
uint vertexCount;
|
||||||
|
uint indexCount;
|
||||||
|
} counters;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
drawCmd.indexCount = 0u;
|
||||||
|
drawCmd.instanceCount = 1u;
|
||||||
|
drawCmd.firstIndex = 0u;
|
||||||
|
drawCmd.vertexOffset = 0;
|
||||||
|
drawCmd.firstInstance = 0u;
|
||||||
|
|
||||||
|
counters.vertexCount = 0u;
|
||||||
|
counters.indexCount = 0u;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||||
|
|
||||||
|
const uint FLOATS_PER_VERTEX = 14u;
|
||||||
|
|
||||||
|
struct DrawCommand {
|
||||||
|
uint indexCount;
|
||||||
|
uint instanceCount;
|
||||||
|
uint firstIndex;
|
||||||
|
int vertexOffset;
|
||||||
|
uint firstInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer DrawCommands {
|
||||||
|
DrawCommand drawCmds[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer Counters {
|
||||||
|
uint vertexCount;
|
||||||
|
uint indexCount;
|
||||||
|
} counters;
|
||||||
|
|
||||||
|
layout(push_constant) uniform ChunkInfo {
|
||||||
|
ivec3 chunkPos;
|
||||||
|
int slot;
|
||||||
|
uint vertexFloatOffset;
|
||||||
|
uint indexOffset;
|
||||||
|
uint indirectCommandIndex;
|
||||||
|
uint padding0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
drawCmds[indirectCommandIndex].indexCount = 0u;
|
||||||
|
drawCmds[indirectCommandIndex].instanceCount = 1u;
|
||||||
|
drawCmds[indirectCommandIndex].firstIndex = indexOffset;
|
||||||
|
drawCmds[indirectCommandIndex].vertexOffset = int(vertexFloatOffset / FLOATS_PER_VERTEX);
|
||||||
|
drawCmds[indirectCommandIndex].firstInstance = 0u;
|
||||||
|
|
||||||
|
counters.vertexCount = 0u;
|
||||||
|
counters.indexCount = 0u;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
#version 460
|
||||||
|
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||||
|
|
||||||
|
const int CHUNK_SIZE = 16;
|
||||||
|
const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
|
||||||
|
// A 1D storage buffer representing a flat 3D array of voxel IDs
|
||||||
|
layout(std430, binding = 0) buffer VoxelData {
|
||||||
|
uint voxels[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(push_constant) uniform ChunkOffset {
|
||||||
|
ivec3 chunkPos;
|
||||||
|
int padding0;
|
||||||
|
};
|
||||||
|
// Description : Array and textureless GLSL 2D/3D/4D simplex
|
||||||
|
// noise functions.
|
||||||
|
// Author : Ian McEwan, Ashima Arts.
|
||||||
|
// Maintainer : stegu
|
||||||
|
// Lastmod : 20110822 (ijm)
|
||||||
|
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
|
||||||
|
// Distributed under the MIT License. See LICENSE file.
|
||||||
|
// https://github.com
|
||||||
|
|
||||||
|
vec4 permute(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }
|
||||||
|
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
|
||||||
|
|
||||||
|
float simplex_noise(vec3 v) {
|
||||||
|
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
|
||||||
|
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||||
|
|
||||||
|
// First corner
|
||||||
|
vec3 i = floor(v + dot(v, C.yyy));
|
||||||
|
vec3 x0 = v - i + dot(i, C.xxx);
|
||||||
|
|
||||||
|
// Other corners
|
||||||
|
vec3 g = step(x0.yzx, x0.xyz);
|
||||||
|
vec3 l = 1.0 - g;
|
||||||
|
vec3 i1 = min(g.xyz, l.zxy);
|
||||||
|
vec3 i2 = max(g.xyz, l.zxy);
|
||||||
|
|
||||||
|
// x0 = x0 - 0.0 + 0.0 * C.xxx;
|
||||||
|
// x1 = x0 - i1 + 1.0 * C.xxx;
|
||||||
|
// x2 = x0 - i2 + 2.0 * C.xxx;
|
||||||
|
// x3 = x0 - 1.0 + 3.0 * C.xxx;
|
||||||
|
vec3 x1 = x0 - i1 + C.xxx;
|
||||||
|
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||||
|
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||||
|
|
||||||
|
// Permutations
|
||||||
|
i = mod(i, 289.0);
|
||||||
|
vec4 p = permute(permute(permute(
|
||||||
|
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
||||||
|
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
||||||
|
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
|
||||||
|
|
||||||
|
// Gradients: 7x7 points over a square, mapped onto an octahedron.
|
||||||
|
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
|
||||||
|
float n_ = 0.142857142857; // 1.0/7.0
|
||||||
|
vec3 ns = n_ * D.wyz - D.xzx;
|
||||||
|
|
||||||
|
vec4 j = p - 49.0 * floor(p * ns.z); // mod(p,7*7)
|
||||||
|
|
||||||
|
vec4 x_ = floor(j * ns.z);
|
||||||
|
vec4 y_ = floor(j - 7.0 * x_); // mod(j,N)
|
||||||
|
|
||||||
|
vec4 x = x_ * ns.x + ns.yyyy;
|
||||||
|
vec4 y = y_ * ns.x + ns.yyyy;
|
||||||
|
vec4 h = 1.0 - abs(x) - abs(y);
|
||||||
|
|
||||||
|
vec4 b0 = vec4(x.xy, y.xy);
|
||||||
|
vec4 b1 = vec4(x.zw, y.zw);
|
||||||
|
|
||||||
|
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
|
||||||
|
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
|
||||||
|
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
||||||
|
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
||||||
|
vec4 sh = -step(h, vec4(0.0));
|
||||||
|
|
||||||
|
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
||||||
|
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
||||||
|
|
||||||
|
vec3 p0 = vec3(a0.xy, h.x);
|
||||||
|
vec3 p1 = vec3(a0.zw, h.y);
|
||||||
|
vec3 p2 = vec3(a1.xy, h.z);
|
||||||
|
vec3 p3 = vec3(a1.zw, h.w);
|
||||||
|
|
||||||
|
// Normalise gradients
|
||||||
|
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
|
||||||
|
p0 *= norm.x;
|
||||||
|
p1 *= norm.y;
|
||||||
|
p2 *= norm.z;
|
||||||
|
p3 *= norm.w;
|
||||||
|
|
||||||
|
// Mix final noise value
|
||||||
|
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
|
||||||
|
m = m * m;
|
||||||
|
|
||||||
|
// Returns a value scaled exactly between -1.0 and 1.0
|
||||||
|
return 42.0 * dot(m * m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));
|
||||||
|
}
|
||||||
|
float noise2D(vec2 p) {
|
||||||
|
return simplex_noise(vec3(p.x, p.y, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(vec2 p, int octaves, float lacunarity, float gain) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 1.0;
|
||||||
|
float amplitudeSum = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
value += noise2D(p * frequency) * amplitude;
|
||||||
|
amplitudeSum += amplitude;
|
||||||
|
|
||||||
|
frequency *= lacunarity;
|
||||||
|
amplitude *= gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value / amplitudeSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ridgedFbm(vec2 p, int octaves, float lacunarity, float gain) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 1.0;
|
||||||
|
float amplitudeSum = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
float n = noise2D(p * frequency);
|
||||||
|
n = 1.0 - abs(n);
|
||||||
|
n = n * n;
|
||||||
|
|
||||||
|
value += n * amplitude;
|
||||||
|
amplitudeSum += amplitude;
|
||||||
|
|
||||||
|
frequency *= lacunarity;
|
||||||
|
amplitude *= gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value / amplitudeSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 domainWarp(vec2 p) {
|
||||||
|
float wx = fbm(p + vec2(17.31, 91.73), 3, 2.0, 0.5);
|
||||||
|
float wz = fbm(p + vec2(43.17, 12.89), 3, 2.0, 0.5);
|
||||||
|
|
||||||
|
return p + vec2(wx, wz) * 35.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float terrainHeight(vec2 worldXZ) {
|
||||||
|
vec2 p = worldXZ;
|
||||||
|
|
||||||
|
vec2 warped = domainWarp(p * 0.006);
|
||||||
|
|
||||||
|
float continent = fbm(warped * 0.45, 5, 2.0, 0.5);
|
||||||
|
continent = continent * 0.5 + 0.5;
|
||||||
|
|
||||||
|
float hills = fbm(p * 0.025, 5, 2.0, 0.48);
|
||||||
|
float detail = fbm(p * 0.09, 3, 2.1, 0.45);
|
||||||
|
|
||||||
|
float mountainMask = smoothstep(0.52, 0.82, continent);
|
||||||
|
float mountains = ridgedFbm(warped * 1.15, 5, 2.0, 0.52);
|
||||||
|
|
||||||
|
float height = 18.0;
|
||||||
|
height += continent * 28.0;
|
||||||
|
height += hills * 14.0;
|
||||||
|
height += detail * 3.0;
|
||||||
|
height += mountainMask * mountains * 55.0;
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz);
|
||||||
|
|
||||||
|
if (localPos.x >= CHUNK_SIZE || localPos.y >= CHUNK_SIZE || localPos.z >= CHUNK_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos;
|
||||||
|
|
||||||
|
float height = terrainHeight(vec2(worldPos.x,worldPos.z) * 0.02) * 0.0015 + 10 ;
|
||||||
|
|
||||||
|
uint voxelType = 0u;
|
||||||
|
|
||||||
|
if (float(worldPos.y) <= height) {
|
||||||
|
float depthBelowSurface = height - float(worldPos.y);
|
||||||
|
|
||||||
|
if (depthBelowSurface < 1.5) {
|
||||||
|
voxelType = 1u; // Grass/topsoil
|
||||||
|
} else if (depthBelowSurface < 5.0) {
|
||||||
|
voxelType = 2u; // Dirt
|
||||||
|
} else {
|
||||||
|
voxelType = 3u; // Stone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint index = uint((localPos.x * CHUNK_AREA) + (localPos.y * CHUNK_SIZE) + localPos.z);
|
||||||
|
voxels[index] = voxelType;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,260 @@
|
||||||
|
#version 460
|
||||||
|
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||||
|
|
||||||
|
const int CHUNK_SIZE = 16;
|
||||||
|
const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
|
||||||
|
// A 1D storage buffer representing a flat 3D array of voxel IDs
|
||||||
|
layout(std430, binding = 0) buffer VoxelData {
|
||||||
|
uint voxels[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(push_constant) uniform ChunkOffset {
|
||||||
|
ivec3 chunkPos;
|
||||||
|
int slot;
|
||||||
|
uint vertexFloatOffset;
|
||||||
|
uint indexOffset;
|
||||||
|
uint indirectCommandIndex;
|
||||||
|
uint padding0;
|
||||||
|
};
|
||||||
|
// Description : Array and textureless GLSL 2D/3D/4D simplex
|
||||||
|
// noise functions.
|
||||||
|
// Author : Ian McEwan, Ashima Arts.
|
||||||
|
// Maintainer : stegu
|
||||||
|
// Lastmod : 20110822 (ijm)
|
||||||
|
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
|
||||||
|
// Distributed under the MIT License. See LICENSE file.
|
||||||
|
// https://github.com
|
||||||
|
|
||||||
|
vec4 permute(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }
|
||||||
|
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
|
||||||
|
|
||||||
|
float simplex_noise(vec3 v) {
|
||||||
|
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
|
||||||
|
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||||
|
|
||||||
|
// First corner
|
||||||
|
vec3 i = floor(v + dot(v, C.yyy));
|
||||||
|
vec3 x0 = v - i + dot(i, C.xxx);
|
||||||
|
|
||||||
|
// Other corners
|
||||||
|
vec3 g = step(x0.yzx, x0.xyz);
|
||||||
|
vec3 l = 1.0 - g;
|
||||||
|
vec3 i1 = min(g.xyz, l.zxy);
|
||||||
|
vec3 i2 = max(g.xyz, l.zxy);
|
||||||
|
|
||||||
|
// x0 = x0 - 0.0 + 0.0 * C.xxx;
|
||||||
|
// x1 = x0 - i1 + 1.0 * C.xxx;
|
||||||
|
// x2 = x0 - i2 + 2.0 * C.xxx;
|
||||||
|
// x3 = x0 - 1.0 + 3.0 * C.xxx;
|
||||||
|
vec3 x1 = x0 - i1 + C.xxx;
|
||||||
|
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||||
|
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||||
|
|
||||||
|
// Permutations
|
||||||
|
i = mod(i, 289.0);
|
||||||
|
vec4 p = permute(permute(permute(
|
||||||
|
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
||||||
|
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
||||||
|
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
|
||||||
|
|
||||||
|
// Gradients: 7x7 points over a square, mapped onto an octahedron.
|
||||||
|
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
|
||||||
|
float n_ = 0.142857142857; // 1.0/7.0
|
||||||
|
vec3 ns = n_ * D.wyz - D.xzx;
|
||||||
|
|
||||||
|
vec4 j = p - 49.0 * floor(p * ns.z); // mod(p,7*7)
|
||||||
|
|
||||||
|
vec4 x_ = floor(j * ns.z);
|
||||||
|
vec4 y_ = floor(j - 7.0 * x_); // mod(j,N)
|
||||||
|
|
||||||
|
vec4 x = x_ * ns.x + ns.yyyy;
|
||||||
|
vec4 y = y_ * ns.x + ns.yyyy;
|
||||||
|
vec4 h = 1.0 - abs(x) - abs(y);
|
||||||
|
|
||||||
|
vec4 b0 = vec4(x.xy, y.xy);
|
||||||
|
vec4 b1 = vec4(x.zw, y.zw);
|
||||||
|
|
||||||
|
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
|
||||||
|
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
|
||||||
|
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
||||||
|
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
||||||
|
vec4 sh = -step(h, vec4(0.0));
|
||||||
|
|
||||||
|
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
||||||
|
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
||||||
|
|
||||||
|
vec3 p0 = vec3(a0.xy, h.x);
|
||||||
|
vec3 p1 = vec3(a0.zw, h.y);
|
||||||
|
vec3 p2 = vec3(a1.xy, h.z);
|
||||||
|
vec3 p3 = vec3(a1.zw, h.w);
|
||||||
|
|
||||||
|
// Normalise gradients
|
||||||
|
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
|
||||||
|
p0 *= norm.x;
|
||||||
|
p1 *= norm.y;
|
||||||
|
p2 *= norm.z;
|
||||||
|
p3 *= norm.w;
|
||||||
|
|
||||||
|
// Mix final noise value
|
||||||
|
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
|
||||||
|
m = m * m;
|
||||||
|
|
||||||
|
// Returns a value scaled exactly between -1.0 and 1.0
|
||||||
|
return 42.0 * dot(m * m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));
|
||||||
|
}
|
||||||
|
float noise2D(vec2 p) {
|
||||||
|
return simplex_noise(vec3(p.x, p.y, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(vec2 p, int octaves, float lacunarity, float gain) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 1.0;
|
||||||
|
float amplitudeSum = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
value += noise2D(p * frequency) * amplitude;
|
||||||
|
amplitudeSum += amplitude;
|
||||||
|
|
||||||
|
frequency *= lacunarity;
|
||||||
|
amplitude *= gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value / amplitudeSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ridgedFbm(vec2 p, int octaves, float lacunarity, float gain) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 1.0;
|
||||||
|
float amplitudeSum = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
float n = noise2D(p * frequency);
|
||||||
|
n = 1.0 - abs(n);
|
||||||
|
n = n * n;
|
||||||
|
|
||||||
|
value += n * amplitude;
|
||||||
|
amplitudeSum += amplitude;
|
||||||
|
|
||||||
|
frequency *= lacunarity;
|
||||||
|
amplitude *= gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value / amplitudeSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 domainWarp(vec2 p) {
|
||||||
|
float wx = fbm(p + vec2(17.31, 91.73), 3, 2.0, 0.5);
|
||||||
|
float wz = fbm(p + vec2(43.17, 12.89), 3, 2.0, 0.5);
|
||||||
|
|
||||||
|
return p + vec2(wx, wz) * 35.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float terrainHeight(vec2 worldXZ) {
|
||||||
|
vec2 p = worldXZ;
|
||||||
|
|
||||||
|
vec2 warped = domainWarp(p * 0.004);
|
||||||
|
|
||||||
|
float broad = fbm(warped * 0.45, 5, 2.0, 0.5);
|
||||||
|
broad = broad * 0.5 + 0.5;
|
||||||
|
|
||||||
|
float hills = fbm(p * 0.025, 4, 2.0, 0.48);
|
||||||
|
float detail = fbm(p * 0.085, 2, 2.0, 0.4);
|
||||||
|
|
||||||
|
float height = 8.0;
|
||||||
|
height += broad * 12.0;
|
||||||
|
height += hills * 6.0;
|
||||||
|
height += detail * 2.0;
|
||||||
|
|
||||||
|
return clamp(height, 4.0, 28.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float rand(vec2 co) {
|
||||||
|
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
float fbm3D(vec3 p, int octaves, float lacunarity, float gain) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 1.0;
|
||||||
|
float amplitudeSum = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
value += simplex_noise(p * frequency) * amplitude;
|
||||||
|
amplitudeSum += amplitude;
|
||||||
|
|
||||||
|
frequency *= lacunarity;
|
||||||
|
amplitude *= gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value / amplitudeSum;
|
||||||
|
}
|
||||||
|
float valueNoise(vec2 st) {
|
||||||
|
vec2 i = floor(st);
|
||||||
|
vec2 f = fract(st);
|
||||||
|
|
||||||
|
float a = rand(i);
|
||||||
|
float b = rand(i + vec2(1.0, 0.0));
|
||||||
|
float c = rand(i + vec2(0.0, 1.0));
|
||||||
|
float d = rand(i + vec2(1.0, 1.0));
|
||||||
|
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return mix(a, b, u.x) +
|
||||||
|
(c - a) * u.y * (1.0 - u.x) +
|
||||||
|
(d - b) * u.x * u.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 randG(vec2 p) {
|
||||||
|
p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
|
||||||
|
return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float perlinNoise(vec2 st) {
|
||||||
|
vec2 i = floor(st);
|
||||||
|
vec2 f = fract(st);
|
||||||
|
|
||||||
|
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
|
||||||
|
|
||||||
|
float dotTopLeft = dot(randG(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0));
|
||||||
|
float dotTopRight = dot(randG(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0));
|
||||||
|
float dotBottomLeft = dot(randG(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0));
|
||||||
|
float dotBottomRight = dot(randG(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0));
|
||||||
|
|
||||||
|
return mix(mix(dotTopLeft, dotTopRight, u.x),
|
||||||
|
mix(dotBottomLeft, dotBottomRight, u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz);
|
||||||
|
ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos;
|
||||||
|
|
||||||
|
float height = valueNoise(vec2(worldPos.x, worldPos.z) * 0.005) * 100 + valueNoise(vec2(worldPos.x, worldPos.z) * 0.01) * 10 + valueNoise(vec2(worldPos.x, worldPos.z) * 0.1) * 5+ valueNoise(vec2(worldPos.x, worldPos.z)) * 0.5;
|
||||||
|
//height = clamp(height, 4.0, 28.0);
|
||||||
|
|
||||||
|
uint voxelType = 0u;
|
||||||
|
|
||||||
|
if (float(worldPos.y) <= height && float(floor(worldPos.y/CHUNK_SIZE) * CHUNK_SIZE + CHUNK_SIZE * 2) >= height) {
|
||||||
|
float depthBelowSurface = height - float(worldPos.y);
|
||||||
|
|
||||||
|
if (depthBelowSurface < 1.5) {
|
||||||
|
voxelType = 1u; // Grass/topsoil
|
||||||
|
} else if (depthBelowSurface < 5.0) {
|
||||||
|
voxelType = 2u; // Dirt
|
||||||
|
} else {
|
||||||
|
voxelType = 3u; // Stone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (voxelType != 0u && worldPos.y < int(height) - 6) {
|
||||||
|
// float cave = fbm3D(vec3(worldPos) * 0.045, 4, 2.0, 0.5);
|
||||||
|
//
|
||||||
|
// if (cave > 0.42) {
|
||||||
|
// voxelType = 0u;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
uint index = uint((localPos.x * CHUNK_AREA) + (localPos.y * CHUNK_SIZE) + localPos.z);
|
||||||
|
voxels[index] = voxelType;
|
||||||
|
}
|
||||||
Binary file not shown.
|
|
@ -139,8 +139,6 @@ void main() {
|
||||||
float emissiveness = emissive.r;
|
float emissiveness = emissive.r;
|
||||||
|
|
||||||
float ssao = texture(ssaoBlur, inTextCoord).r;
|
float ssao = texture(ssaoBlur, inTextCoord).r;
|
||||||
outFragColor = vec4(vec3(normalW.a/2.0,normalW.a/2.0,normalW.a/2.0), 1);
|
|
||||||
return;
|
|
||||||
|
|
||||||
float roughness = pbr.g;
|
float roughness = pbr.g;
|
||||||
float metallic = pbr.b;
|
float metallic = pbr.b;
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -66,8 +66,12 @@ void main()
|
||||||
} else{
|
} else{
|
||||||
outAlbedo = material.diffuseColor;
|
outAlbedo = material.diffuseColor;
|
||||||
}
|
}
|
||||||
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
|
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
|
||||||
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
|
|
||||||
|
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
|
||||||
|
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
||||||
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -88,11 +88,16 @@ void main()
|
||||||
outAlbedo = material.diffuseColor;
|
outAlbedo = material.diffuseColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
|
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
|
||||||
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
|
|
||||||
|
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
|
||||||
|
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
||||||
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
outOpacity = Opacity;
|
outOpacity = Opacity;
|
||||||
|
|
||||||
float opacityf = Opacity.x + Opacity.y + Opacity.z;
|
float opacityf = Opacity.x + Opacity.y + Opacity.z;
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -65,11 +65,16 @@ void main()
|
||||||
} else{
|
} else{
|
||||||
outAlbedo = material.diffuseColor;
|
outAlbedo = material.diffuseColor;
|
||||||
}
|
}
|
||||||
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
|
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
|
||||||
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
|
|
||||||
|
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
|
||||||
|
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
||||||
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
float opacityf = Opacity.x + Opacity.y + Opacity.z;
|
float opacityf = Opacity.x + Opacity.y + Opacity.z;
|
||||||
opacityf = opacityf/3;
|
opacityf = opacityf/3;
|
||||||
if(opacityf < 0.9){discard;}
|
if(opacityf < 0.9){discard;}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -94,8 +94,12 @@ void main()
|
||||||
outAlbedo = material.diffuseColor;
|
outAlbedo = material.diffuseColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
|
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
|
||||||
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
|
|
||||||
|
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
|
||||||
|
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
||||||
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,12 @@ void main()
|
||||||
} else{
|
} else{
|
||||||
outAlbedo = material.diffuseColor;
|
outAlbedo = material.diffuseColor;
|
||||||
}
|
}
|
||||||
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
|
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
|
||||||
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
|
|
||||||
|
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
|
||||||
|
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
||||||
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -96,8 +96,12 @@ void main()
|
||||||
outAlbedo = material.diffuseColor;
|
outAlbedo = material.diffuseColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
|
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
|
||||||
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
|
|
||||||
|
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
|
||||||
|
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
|
||||||
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -5,6 +5,8 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||||
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
|
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
|
||||||
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.SkyBox;
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.SkyBox;
|
||||||
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelChunkGenerator;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiRenderer;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiRenderer;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiTexture;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiTexture;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Lighting.LightRenderer;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Lighting.LightRenderer;
|
||||||
|
|
@ -28,6 +30,8 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.SwapChainRender;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.SwapChainRender;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
|
||||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.joml.Vector3i;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
import org.lwjgl.vulkan.VkCommandBufferSubmitInfo;
|
import org.lwjgl.vulkan.VkCommandBufferSubmitInfo;
|
||||||
import org.lwjgl.vulkan.VkExtent2D;
|
import org.lwjgl.vulkan.VkExtent2D;
|
||||||
|
|
@ -179,6 +183,8 @@ public class VulkanRenderer implements Renderer {
|
||||||
spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache);
|
spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache);
|
||||||
spriteRenderer.LoadMaterials(RendererContext,materialsCache,textureCache);
|
spriteRenderer.LoadMaterials(RendererContext,materialsCache,textureCache);
|
||||||
GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache);
|
GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache);
|
||||||
|
VoxelWorldManager.Init(RendererContext);
|
||||||
|
// VoxelWorldManager.GenerateChunks(new Vector3i(0,0,0), new Vector3i(16,0,16));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GuiRenderer GetGUIRenderer(){return GuiRender;}
|
public GuiRenderer GetGUIRenderer(){return GuiRender;}
|
||||||
|
|
@ -196,6 +202,9 @@ public class VulkanRenderer implements Renderer {
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
RendererContext.GetDevice().waitIdle();
|
RendererContext.GetDevice().waitIdle();
|
||||||
Logger.debug("Waiting Vulkan Context");
|
Logger.debug("Waiting Vulkan Context");
|
||||||
|
|
||||||
|
VoxelWorldManager.Cleanup(RendererContext);
|
||||||
|
|
||||||
sceneRender.cleanup(RendererContext);
|
sceneRender.cleanup(RendererContext);
|
||||||
if(ssaoRenderer != null)ssaoRenderer.cleanup(RendererContext);
|
if(ssaoRenderer != null)ssaoRenderer.cleanup(RendererContext);
|
||||||
if(ssrRender != null)ssrRender.cleanup(RendererContext);
|
if(ssrRender != null)ssrRender.cleanup(RendererContext);
|
||||||
|
|
@ -239,7 +248,7 @@ public class VulkanRenderer implements Renderer {
|
||||||
|
|
||||||
public static volatile boolean Debug = false;
|
public static volatile boolean Debug = false;
|
||||||
public static volatile DebugRenderMode debugMode = DebugRenderMode.Albedo;
|
public static volatile DebugRenderMode debugMode = DebugRenderMode.Albedo;
|
||||||
|
Vector3f CamPos = new Vector3f();
|
||||||
public void DeferredRender(EngineInstance engineInstance){
|
public void DeferredRender(EngineInstance engineInstance){
|
||||||
SwapChain swapChain = RendererContext.GetSwapChain();
|
SwapChain swapChain = RendererContext.GetSwapChain();
|
||||||
WaitForFence(CurrentFrame);
|
WaitForFence(CurrentFrame);
|
||||||
|
|
@ -247,9 +256,8 @@ public class VulkanRenderer implements Renderer {
|
||||||
|
|
||||||
var CommandPool = CommandPools[CurrentFrame];
|
var CommandPool = CommandPools[CurrentFrame];
|
||||||
var CommandBuffer = CommandBuffers[CurrentFrame];
|
var CommandBuffer = CommandBuffers[CurrentFrame];
|
||||||
|
|
||||||
RecordingStart(CommandPool, CommandBuffer);
|
RecordingStart(CommandPool, CommandBuffer);
|
||||||
|
VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer);
|
||||||
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
||||||
boolean RenderShadows = ShadowRenderer.AllowShadowRendering() && EngineConfig.getInstance().RenderShadows();
|
boolean RenderShadows = ShadowRenderer.AllowShadowRendering() && EngineConfig.getInstance().RenderShadows();
|
||||||
if(RenderShadows) {shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); }
|
if(RenderShadows) {shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); }
|
||||||
|
|
@ -289,9 +297,8 @@ public class VulkanRenderer implements Renderer {
|
||||||
resize(engineInstance);
|
resize(engineInstance);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordingStart(CommandPool, CommandBuffer);
|
RecordingStart(CommandPool, CommandBuffer);
|
||||||
|
VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer);
|
||||||
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
||||||
PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour());
|
PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour());
|
||||||
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);
|
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.Noise2D;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.PermutationArray;
|
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.PermutationArray;
|
||||||
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
|
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
|
||||||
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
|
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelChunkGenerator;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
|
||||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ServerSideNetworkUtils;
|
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ServerSideNetworkUtils;
|
||||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||||
|
|
@ -36,13 +38,11 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPass
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialData;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialData;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.ModelData;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.ModelData;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Forward.ForwardSceneRender;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Forward.ForwardSceneRender;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.*;
|
||||||
import org.joml.Vector2f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
import org.joml.Vector3i;
|
|
||||||
import org.lwjgl.openal.AL11;
|
import org.lwjgl.openal.AL11;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.lang.Math;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ import static org.lwjgl.glfw.GLFW.*;
|
||||||
public class GameCore implements GameLogic {
|
public class GameCore implements GameLogic {
|
||||||
|
|
||||||
private static final float MOUSE_SENSITIVITY = 0.1f;
|
private static final float MOUSE_SENSITIVITY = 0.1f;
|
||||||
private static final float MOVEMENT_SPEED = 0.01f;
|
private static final float MOVEMENT_SPEED = 0.1f;
|
||||||
public static boolean LoadingLevel = false;
|
public static boolean LoadingLevel = false;
|
||||||
|
|
||||||
private Vector2f LastMousePos = new Vector2f(0,0);
|
private Vector2f LastMousePos = new Vector2f(0,0);
|
||||||
|
|
@ -161,6 +161,9 @@ public class GameCore implements GameLogic {
|
||||||
}
|
}
|
||||||
boolean createOfflinePlayer = !PrimaryRuntime.IsServer && !ClientSideNetworkUtils.Connected;
|
boolean createOfflinePlayer = !PrimaryRuntime.IsServer && !ClientSideNetworkUtils.Connected;
|
||||||
|
|
||||||
|
MaterialData VoxelMat = new MaterialData("VoxelTerrain","resources/EngineResources/Texture/test_cube.png","","",new Vector4f(1,1,1,1),
|
||||||
|
0,0,"",new Vector4f(),"",0,"",1,new Vector4f(),1.0f,0);
|
||||||
|
materials.add(VoxelMat);
|
||||||
materials.addAll(MelonaMat);
|
materials.addAll(MelonaMat);
|
||||||
materials.addAll(CollisionVisualisationMat);
|
materials.addAll(CollisionVisualisationMat);
|
||||||
materials.addAll(MelonaMaterial);
|
materials.addAll(MelonaMaterial);
|
||||||
|
|
@ -283,11 +286,11 @@ public class GameCore implements GameLogic {
|
||||||
permutation.GeneratePermutationArray(5783904701859L);
|
permutation.GeneratePermutationArray(5783904701859L);
|
||||||
for(int x = -1; x < 2; x++){
|
for(int x = -1; x < 2; x++){
|
||||||
for(int y = -1; y < 2; y++){
|
for(int y = -1; y < 2; y++){
|
||||||
GenerateChunk(new Vector3i(x, 0, y), 16);
|
//GenerateChunk(new Vector3i(x, 0, y), 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(int i = 0; i < 20; i++){
|
for(int i = 0; i < 20; i++){
|
||||||
SpawnNewActor(engineInstance, new Vector3f(-5 + (float)Math.random() * 10,10 + (float)Math.random() * 10, -5 + (float)Math.random() * 10), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1));
|
//SpawnNewActor(engineInstance, new Vector3f(-5 + (float)Math.random() * 10,10 + (float)Math.random() * 10, -5 + (float)Math.random() * 10), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1));
|
||||||
}
|
}
|
||||||
Settings.textBuffer.set(ClientSideNetworkUtils.ServerIP);
|
Settings.textBuffer.set(ClientSideNetworkUtils.ServerIP);
|
||||||
Settings.UsernameBuffer.set("Player");
|
Settings.UsernameBuffer.set("Player");
|
||||||
|
|
@ -651,10 +654,20 @@ public class GameCore implements GameLogic {
|
||||||
FetchingMetrics = false;
|
FetchingMetrics = false;
|
||||||
return imGuiIO.getWantCaptureKeyboard();
|
return imGuiIO.getWantCaptureKeyboard();
|
||||||
}
|
}
|
||||||
|
Vector3f CamPos = new Vector3f();
|
||||||
@Override
|
@Override
|
||||||
public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
|
public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
|
||||||
if(!PrimaryRuntime.IsServer && !RenderThread.Headless) {
|
if(!PrimaryRuntime.IsServer && !RenderThread.Headless) {
|
||||||
|
CamPos.set(engineInstance.scene().GetCamera().GetPosition());
|
||||||
|
Vector3i ChunkPos = new Vector3i((int)Math.floor(CamPos.x/ (float) VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.y/ (float)VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.z/ (float)VoxelChunkGenerator.CHUNK_SIZE));
|
||||||
|
if(ChunkPos.x != VoxelWorldManager.LastPosition.x || ChunkPos.y != VoxelWorldManager.LastPosition.y || ChunkPos.z != VoxelWorldManager.LastPosition.z) {
|
||||||
|
VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(5, 3, 5));
|
||||||
|
VoxelWorldManager.UnloadFarChunks(ChunkPos, 10);
|
||||||
|
} else {
|
||||||
|
VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(24,10,24));
|
||||||
|
VoxelWorldManager.UnloadFarChunks(ChunkPos, 48);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < VisualisedCollisionActor3D.CollisionVisuals.size(); i++) {
|
for (int i = 0; i < VisualisedCollisionActor3D.CollisionVisuals.size(); i++) {
|
||||||
VisualisedCollisionActor3D.CollisionVisuals.get(i).Update();
|
VisualisedCollisionActor3D.CollisionVisuals.get(i).Update();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,330 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil.ComputePipeline;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.ModelsCache;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.util.shaderc.Shaderc;
|
||||||
|
import org.lwjgl.vulkan.*;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.LongBuffer;
|
||||||
|
|
||||||
|
import static net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.BufferBarrier;
|
||||||
|
import static org.lwjgl.system.MemoryUtil.memFree;
|
||||||
|
import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||||
|
import static org.lwjgl.vulkan.VK10.*;
|
||||||
|
import static org.lwjgl.vulkan.VK10.VK_PIPELINE_BIND_POINT_COMPUTE;
|
||||||
|
import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_COMPUTE_BIT;
|
||||||
|
import static org.lwjgl.vulkan.VK10.vkCmdDispatch;
|
||||||
|
import static org.lwjgl.vulkan.VK10.vkCmdPushConstants;
|
||||||
|
import static org.lwjgl.vulkan.VK13.*;
|
||||||
|
|
||||||
|
public class ComputeVoxelTerrain {
|
||||||
|
public static final int CHUNK_SIZE = 16;
|
||||||
|
public static final int LOCAL_SIZE = 4;
|
||||||
|
public static final int DISPATCH_SIZE = CHUNK_SIZE / LOCAL_SIZE;
|
||||||
|
|
||||||
|
public static final int CHUNK_PUSH_CONSTANT_SIZE = Integer.BYTES * 4;
|
||||||
|
|
||||||
|
private static final int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
private static final int MAX_FACES = VOXEL_COUNT * 6;
|
||||||
|
private static final int MAX_VISIBLE_FACES_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * 16;
|
||||||
|
private static final int MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * 4;
|
||||||
|
private static final int MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * 6;
|
||||||
|
|
||||||
|
private static final int FLOATS_PER_VERTEX = 14;
|
||||||
|
private static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES;
|
||||||
|
private static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES;
|
||||||
|
private static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES;
|
||||||
|
|
||||||
|
private final String DESCRIPTOR_ID_MESH;
|
||||||
|
private final String DESCRIPTOR_ID_RESET;
|
||||||
|
private final String DESCRIPTOR_ID_VOXEL;
|
||||||
|
|
||||||
|
private static final String MESH_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/meshGeneration.glsl";
|
||||||
|
private static final String VOXEL_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/voxelGeneration.glsl";
|
||||||
|
private static final String VOXEL_RESET_GLSL = "resources/EngineResources/VoxelComputeShaders/resetVoxelDraw.glsl";
|
||||||
|
|
||||||
|
private static final String MESH_GENERATION_SPV = MESH_GENERATION_GLSL + ".spv";
|
||||||
|
private static final String VOXEL_GENERATION_SPV = VOXEL_GENERATION_GLSL + ".spv";
|
||||||
|
private static final String VOXEL_RESET_SPV = VOXEL_RESET_GLSL + ".spv";
|
||||||
|
|
||||||
|
private final VulkanBuffer VoxelData;
|
||||||
|
private final VulkanBuffer VertexBuffer;
|
||||||
|
private final VulkanBuffer IndexBuffer;
|
||||||
|
private final VulkanBuffer DrawCommand;
|
||||||
|
private final VulkanBuffer Counters;
|
||||||
|
|
||||||
|
private final DescriptorSetLayout voxelGenerationLayout;
|
||||||
|
private final DescriptorSetLayout resetLayout;
|
||||||
|
private final DescriptorSetLayout meshGenerationLayout;
|
||||||
|
|
||||||
|
private final Pipeline voxelGeneration;
|
||||||
|
private final Pipeline voxelReset;
|
||||||
|
private final Pipeline meshGeneration;
|
||||||
|
|
||||||
|
private final ByteBuffer graphicsPushConstants;
|
||||||
|
|
||||||
|
private final int chunkX;
|
||||||
|
private final int chunkY;
|
||||||
|
private final int chunkZ;
|
||||||
|
|
||||||
|
private boolean generated;
|
||||||
|
|
||||||
|
public ComputeVoxelTerrain(VulkanContext VkCtx, int chunkX, int chunkY, int chunkZ) {
|
||||||
|
this.chunkX = chunkX;
|
||||||
|
this.chunkY = chunkY;
|
||||||
|
this.chunkZ = chunkZ;
|
||||||
|
this.generated = false;
|
||||||
|
DESCRIPTOR_ID_MESH = "DESC_ID_MESH_" + chunkX + "_" + chunkY + "_" + chunkZ;
|
||||||
|
DESCRIPTOR_ID_RESET = "DESC_ID_RESET_" + chunkX + "_" + chunkY + "_" + chunkZ;
|
||||||
|
DESCRIPTOR_ID_VOXEL = "DESC_ID_VOXEL_" + chunkX + "_" + chunkY + "_" + chunkZ;
|
||||||
|
long voxelBufferSize = (long) VOXEL_COUNT * Integer.BYTES;
|
||||||
|
long vertexBufferSize = (long) MAX_VERTICES * VERTEX_SIZE_BYTES;
|
||||||
|
long indexBufferSize = (long) MAX_INDICES * Integer.BYTES;
|
||||||
|
|
||||||
|
VoxelData = new VulkanBuffer(VkCtx,voxelBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
|
||||||
|
VertexBuffer = new VulkanBuffer( VkCtx, vertexBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
|
||||||
|
IndexBuffer = new VulkanBuffer(VkCtx,indexBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
|
||||||
|
DrawCommand = new VulkanBuffer(VkCtx,DRAW_INDEXED_INDIRECT_COMMAND_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
|
||||||
|
Counters = new VulkanBuffer(VkCtx,COUNTER_BUFFER_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
|
||||||
|
voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,
|
||||||
|
VK_SHADER_STAGE_COMPUTE_BIT ) });
|
||||||
|
resetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,
|
||||||
|
VK_SHADER_STAGE_COMPUTE_BIT ),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,
|
||||||
|
VK_SHADER_STAGE_COMPUTE_BIT ) });
|
||||||
|
meshGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,
|
||||||
|
1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,
|
||||||
|
1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,2,
|
||||||
|
1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,3,
|
||||||
|
1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,4,
|
||||||
|
1,VK_SHADER_STAGE_COMPUTE_BIT),});
|
||||||
|
createDescriptorSets(VkCtx);
|
||||||
|
PushConstantsRange[] chunkPushConstants = new PushConstantsRange[]{
|
||||||
|
new PushConstantsRange(
|
||||||
|
VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
0,
|
||||||
|
CHUNK_PUSH_CONSTANT_SIZE
|
||||||
|
)
|
||||||
|
};
|
||||||
|
ShaderModule resetShader = createComputeShader(VkCtx, VOXEL_RESET_GLSL, VOXEL_RESET_SPV);
|
||||||
|
ShaderModule voxelShader = createComputeShader(VkCtx, VOXEL_GENERATION_GLSL, VOXEL_GENERATION_SPV);
|
||||||
|
ShaderModule meshShader = createComputeShader(VkCtx, MESH_GENERATION_GLSL, MESH_GENERATION_SPV);
|
||||||
|
voxelReset = new ComputePipeline( VkCtx, resetShader,new DescriptorSetLayout[]{resetLayout},
|
||||||
|
new PushConstantsRange[0]);
|
||||||
|
voxelGeneration = new ComputePipeline( VkCtx,voxelShader, new DescriptorSetLayout[]{voxelGenerationLayout},
|
||||||
|
chunkPushConstants );
|
||||||
|
meshGeneration = new ComputePipeline(VkCtx, meshShader,new DescriptorSetLayout[]{meshGenerationLayout},
|
||||||
|
chunkPushConstants );
|
||||||
|
resetShader.CleanUp(VkCtx);
|
||||||
|
voxelShader.CleanUp(VkCtx);
|
||||||
|
meshShader.CleanUp(VkCtx);
|
||||||
|
graphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc(VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.INT_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShaderModule createComputeShader(VulkanContext VkCtx, String glslPath, String spvPath) {
|
||||||
|
if (EngineConfig.getInstance().RecompileShaders()) {
|
||||||
|
ShaderCompiler.CompileGLSLShaderOnChange(glslPath, Shaderc.shaderc_glsl_compute_shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ShaderModule(VkCtx, VK_SHADER_STAGE_COMPUTE_BIT, spvPath, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDescriptorSets(VulkanContext VkCtx) {
|
||||||
|
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
|
||||||
|
Device device = VkCtx.GetDevice();
|
||||||
|
|
||||||
|
DescriptorSet resetSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_RESET, resetLayout);
|
||||||
|
resetSet.SetBuffer(device, DrawCommand, DrawCommand.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
resetSet.SetBuffer(device, Counters, Counters.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
|
||||||
|
DescriptorSet voxelSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_VOXEL, voxelGenerationLayout);
|
||||||
|
voxelSet.SetBuffer(device, VoxelData, VoxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
|
||||||
|
DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_MESH, meshGenerationLayout);
|
||||||
|
meshSet.SetBuffer(device, VoxelData, VoxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, VertexBuffer, VertexBuffer.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, IndexBuffer, IndexBuffer.GetRequestedSize(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, DrawCommand, DrawCommand.GetRequestedSize(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, Counters, Counters.GetRequestedSize(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecordGeneration(VulkanContext VkCtx, CommandBuffer commandBuffer) {
|
||||||
|
if (generated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (MemoryStack MemStack = MemoryStack.stackPush()) {
|
||||||
|
VkCommandBuffer CommandBuffer = commandBuffer.GetVulkanCommandBuffer();
|
||||||
|
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
|
||||||
|
|
||||||
|
ByteBuffer chunkPushBuffer = MemStack.malloc(CHUNK_PUSH_CONSTANT_SIZE);
|
||||||
|
chunkPushBuffer.putInt(0, chunkX);
|
||||||
|
chunkPushBuffer.putInt(4, chunkY);
|
||||||
|
chunkPushBuffer.putInt(8, chunkZ);
|
||||||
|
chunkPushBuffer.putInt(12, 0);
|
||||||
|
|
||||||
|
LongBuffer resetDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_RESET).GetVkDescriptorSet());
|
||||||
|
|
||||||
|
LongBuffer voxelDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_VOXEL).GetVkDescriptorSet());
|
||||||
|
|
||||||
|
LongBuffer meshDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_MESH).GetVkDescriptorSet());
|
||||||
|
|
||||||
|
vkCmdBindPipeline(CommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,voxelReset.GetVulkanPipeline());
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelReset.GetVulkanPipelineLayout(),0,resetDescriptorSet,null);
|
||||||
|
|
||||||
|
vkCmdDispatch(CommandBuffer, 1, 1, 1);
|
||||||
|
|
||||||
|
VulkanUtils.BufferBarriers(MemStack, CommandBuffer,
|
||||||
|
new long[]{DrawCommand.GetBuffer(),Counters.GetBuffer()},
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_WRITE_BIT,VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelGeneration.GetVulkanPipeline());
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelGeneration.GetVulkanPipelineLayout(),0, voxelDescriptorSet,null);
|
||||||
|
|
||||||
|
vkCmdPushConstants(CommandBuffer,voxelGeneration.GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0,chunkPushBuffer);
|
||||||
|
|
||||||
|
vkCmdDispatch(CommandBuffer, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
|
||||||
|
|
||||||
|
BufferBarrier(MemStack, CommandBuffer, VoxelData.GetBuffer(),
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_WRITE_BIT,VK_ACCESS_2_SHADER_READ_BIT);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,meshGeneration.GetVulkanPipeline());
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,meshGeneration.GetVulkanPipelineLayout(),0, meshDescriptorSet,null);
|
||||||
|
|
||||||
|
vkCmdPushConstants(CommandBuffer, meshGeneration.GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0,chunkPushBuffer);
|
||||||
|
|
||||||
|
vkCmdDispatch(CommandBuffer, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
|
||||||
|
|
||||||
|
VulkanUtils.BufferBarriers(MemStack, CommandBuffer,
|
||||||
|
new long[]{VertexBuffer.GetBuffer(),
|
||||||
|
IndexBuffer.GetBuffer(),
|
||||||
|
DrawCommand.GetBuffer()},
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_WRITE_BIT,VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT |
|
||||||
|
VK_ACCESS_2_INDEX_READ_BIT | VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT);
|
||||||
|
|
||||||
|
generated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecordRender(VkCommandBuffer CommandBuffer, Pipeline graphicsPipeline,Matrix4f modelMatrix, int materialIndex) {
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
modelMatrix.get(0, graphicsPushConstants);
|
||||||
|
graphicsPushConstants.putInt(VulkanUtils.MATRIX4X4_SIZE, materialIndex);
|
||||||
|
// Logger.debug("Rendering Chunk {}:{}:{}",chunkX,chunkY,chunkZ);
|
||||||
|
vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_VERTEX_BIT,0, graphicsPushConstants.slice(0, VulkanUtils.MATRIX4X4_SIZE));
|
||||||
|
|
||||||
|
vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_FRAGMENT_BIT,VulkanUtils.MATRIX4X4_SIZE, graphicsPushConstants.slice(VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.INT_SIZE));
|
||||||
|
|
||||||
|
LongBuffer vertexBuffers = stack.longs(VertexBuffer.GetBuffer());
|
||||||
|
LongBuffer offsets = stack.longs(0L);
|
||||||
|
|
||||||
|
vkCmdBindVertexBuffers(CommandBuffer, 0, vertexBuffers, offsets);
|
||||||
|
vkCmdBindIndexBuffer(CommandBuffer, IndexBuffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
|
||||||
|
//vkCmdDrawIndexed(CommandBuffer,MAX_INDICES,1,0,0,0);
|
||||||
|
vkCmdDrawIndexedIndirect(CommandBuffer,DrawCommand.GetBuffer(),0,1,DRAW_INDEXED_INDIRECT_COMMAND_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer GetVoxelDataBuffer() {
|
||||||
|
return VoxelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer GetVertexBuffer() {
|
||||||
|
return VertexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer GetIndexBuffer() {
|
||||||
|
return IndexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer GetDrawCommandBuffer() {
|
||||||
|
return DrawCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer GetCountersBuffer() {
|
||||||
|
return Counters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean IsGenerated() {
|
||||||
|
return generated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MarkDirty() {
|
||||||
|
generated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3i GetPosition(){
|
||||||
|
return new Vector3i(chunkX,chunkY,chunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup(VulkanContext VkCtx) {
|
||||||
|
voxelGeneration.CleanUp(VkCtx);
|
||||||
|
voxelReset.CleanUp(VkCtx);
|
||||||
|
meshGeneration.CleanUp(VkCtx);
|
||||||
|
|
||||||
|
voxelGenerationLayout.CleanUp(VkCtx);
|
||||||
|
resetLayout.CleanUp(VkCtx);
|
||||||
|
meshGenerationLayout.CleanUp(VkCtx);
|
||||||
|
|
||||||
|
VoxelData.cleanup(VkCtx);
|
||||||
|
VertexBuffer.cleanup(VkCtx);
|
||||||
|
IndexBuffer.cleanup(VkCtx);
|
||||||
|
DrawCommand.cleanup(VkCtx);
|
||||||
|
Counters.cleanup(VkCtx);
|
||||||
|
|
||||||
|
org.lwjgl.system.MemoryUtil.memFree(graphicsPushConstants);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordComputeCommandBuffer(VkCommandBuffer cmd, long computePipeline, long pipelineLayout,
|
||||||
|
long descriptorSet, int chunkX, int chunkY, int chunkZ) {
|
||||||
|
try (MemoryStack MemStack = MemoryStack.stackPush()) {
|
||||||
|
ByteBuffer pushConstants = MemStack.malloc(CHUNK_PUSH_CONSTANT_SIZE);
|
||||||
|
pushConstants.putInt(0, chunkX);
|
||||||
|
pushConstants.putInt(4, chunkY);
|
||||||
|
pushConstants.putInt(8, chunkZ);
|
||||||
|
pushConstants.putInt(12, 0);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline);
|
||||||
|
vkCmdBindDescriptorSets(cmd,VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout,
|
||||||
|
0,MemStack.longs(descriptorSet),null);
|
||||||
|
|
||||||
|
vkCmdPushConstants(cmd,pipelineLayout,VK_SHADER_STAGE_COMPUTE_BIT,0,pushConstants);
|
||||||
|
|
||||||
|
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
public record RenderChunk(Vector3i position, int slot,long vertexOffsetBytes, long indexOffsetBytes,int maxIndexCount,long indirectCommandOffsetBytes) {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil.ComputePipeline;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
|
||||||
|
import org.lwjgl.util.shaderc.Shaderc;
|
||||||
|
|
||||||
|
import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||||
|
import static org.lwjgl.vulkan.VK13.*;
|
||||||
|
|
||||||
|
public class SharedVoxelTerrainResources {
|
||||||
|
public static final int CHUNK_SIZE = 16;
|
||||||
|
public static final int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
||||||
|
|
||||||
|
public static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES;
|
||||||
|
public static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES;
|
||||||
|
|
||||||
|
|
||||||
|
public static final int TERRAIN_GENERATION_PUSH_CONSTANT_SIZE = Integer.BYTES * 8;
|
||||||
|
/*Push constants:
|
||||||
|
int chunkX
|
||||||
|
int chunkY
|
||||||
|
int chunkZ
|
||||||
|
int slot
|
||||||
|
uint vertexFloatOffset
|
||||||
|
uint indexOffset
|
||||||
|
uint indirectCommandOffset
|
||||||
|
uint padding */
|
||||||
|
private static final String DESC_ID_VOXEL_GENERATION = "VOXEL_SHARED_DESC_GENERATION";
|
||||||
|
private static final String DESC_ID_RESET = "VOXEL_SHARED_DESC_RESET";
|
||||||
|
private static final String DESC_ID_MESH = "VOXEL_SHARED_DESC_MESH";
|
||||||
|
|
||||||
|
private static final String MESH_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl";
|
||||||
|
private static final String VOXEL_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl";
|
||||||
|
private static final String VOXEL_RESET_GLSL = "resources/EngineResources/VoxelComputeShaders/resetVoxelDrawShared.glsl";
|
||||||
|
|
||||||
|
private static final String MESH_GENERATION_SPV = MESH_GENERATION_GLSL + ".spv";
|
||||||
|
private static final String VOXEL_GENERATION_SPV = VOXEL_GENERATION_GLSL + ".spv";
|
||||||
|
private static final String VOXEL_RESET_SPV = VOXEL_RESET_GLSL + ".spv";
|
||||||
|
|
||||||
|
private final VoxelMeshPool meshPool;
|
||||||
|
|
||||||
|
private final VulkanBuffer voxelData;
|
||||||
|
private final VulkanBuffer counters;
|
||||||
|
|
||||||
|
private final DescriptorSetLayout voxelGenerationLayout;
|
||||||
|
private final DescriptorSetLayout resetLayout;
|
||||||
|
private final DescriptorSetLayout meshGenerationLayout;
|
||||||
|
|
||||||
|
private final Pipeline voxelGenerationPipeline;
|
||||||
|
private final Pipeline resetPipeline;
|
||||||
|
private final Pipeline meshGenerationPipeline;
|
||||||
|
|
||||||
|
public SharedVoxelTerrainResources(VulkanContext VkCtx, int maxResidentChunks) {
|
||||||
|
meshPool = new VoxelMeshPool(VkCtx, maxResidentChunks);
|
||||||
|
|
||||||
|
voxelData = new VulkanBuffer(VkCtx, (long) VOXEL_COUNT * Integer.BYTES,
|
||||||
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
|
||||||
|
|
||||||
|
counters = new VulkanBuffer( VkCtx,COUNTER_BUFFER_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
|
||||||
|
|
||||||
|
voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT)
|
||||||
|
});
|
||||||
|
|
||||||
|
resetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,VK_SHADER_STAGE_COMPUTE_BIT)
|
||||||
|
});
|
||||||
|
|
||||||
|
meshGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,2,1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,3,1,VK_SHADER_STAGE_COMPUTE_BIT),
|
||||||
|
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,4,1,VK_SHADER_STAGE_COMPUTE_BIT)
|
||||||
|
});
|
||||||
|
|
||||||
|
createDescriptorSets(VkCtx);
|
||||||
|
|
||||||
|
PushConstantsRange[] generationPushConstants = new PushConstantsRange[]{
|
||||||
|
new PushConstantsRange(VK_SHADER_STAGE_COMPUTE_BIT,0, TERRAIN_GENERATION_PUSH_CONSTANT_SIZE)
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderModule resetShader = createComputeShader(VkCtx, VOXEL_RESET_GLSL, VOXEL_RESET_SPV);
|
||||||
|
ShaderModule voxelShader = createComputeShader(VkCtx, VOXEL_GENERATION_GLSL, VOXEL_GENERATION_SPV);
|
||||||
|
ShaderModule meshShader = createComputeShader(VkCtx, MESH_GENERATION_GLSL, MESH_GENERATION_SPV);
|
||||||
|
|
||||||
|
resetPipeline = new ComputePipeline(VkCtx,resetShader,new DescriptorSetLayout[]{resetLayout},generationPushConstants);
|
||||||
|
|
||||||
|
voxelGenerationPipeline = new ComputePipeline(VkCtx,voxelShader, new DescriptorSetLayout[]{voxelGenerationLayout},generationPushConstants);
|
||||||
|
|
||||||
|
meshGenerationPipeline = new ComputePipeline( VkCtx,meshShader, new DescriptorSetLayout[]{meshGenerationLayout},generationPushConstants );
|
||||||
|
|
||||||
|
resetShader.CleanUp(VkCtx);
|
||||||
|
voxelShader.CleanUp(VkCtx);
|
||||||
|
meshShader.CleanUp(VkCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShaderModule createComputeShader(VulkanContext VkCtx, String glslPath, String spvPath) {
|
||||||
|
if (EngineConfig.getInstance().RecompileShaders()) {
|
||||||
|
ShaderCompiler.CompileGLSLShaderOnChange(glslPath, Shaderc.shaderc_glsl_compute_shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ShaderModule(VkCtx, VK_SHADER_STAGE_COMPUTE_BIT, spvPath, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDescriptorSets(VulkanContext VkCtx) {
|
||||||
|
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
|
||||||
|
Device device = VkCtx.GetDevice();
|
||||||
|
|
||||||
|
DescriptorSet resetSet = allocator.AddDescriptorSet(device, DESC_ID_RESET, resetLayout);
|
||||||
|
resetSet.SetBuffer(device, meshPool.indirectPool(), meshPool.indirectPool().GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
resetSet.SetBuffer(device, counters, counters.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
|
||||||
|
DescriptorSet voxelSet = allocator.AddDescriptorSet(device, DESC_ID_VOXEL_GENERATION, voxelGenerationLayout);
|
||||||
|
voxelSet.SetBuffer(device, voxelData, voxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
|
||||||
|
DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESC_ID_MESH, meshGenerationLayout);
|
||||||
|
meshSet.SetBuffer(device, voxelData, voxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, meshPool.vertexPool(), meshPool.vertexPool().GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, meshPool.indexPool(), meshPool.indexPool().GetRequestedSize(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, meshPool.indirectPool(), meshPool.indirectPool().GetRequestedSize(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
meshSet.SetBuffer(device, counters, counters.GetRequestedSize(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoxelMeshPool meshPool() {
|
||||||
|
return meshPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer voxelData() {
|
||||||
|
return voxelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer counters() {
|
||||||
|
return counters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pipeline voxelGenerationPipeline() {
|
||||||
|
return voxelGenerationPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pipeline resetPipeline() {
|
||||||
|
return resetPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pipeline meshGenerationPipeline() {
|
||||||
|
return meshGenerationPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String voxelGenerationDescriptorId() {
|
||||||
|
return DESC_ID_VOXEL_GENERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String resetDescriptorId() {
|
||||||
|
return DESC_ID_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String meshDescriptorId() {
|
||||||
|
return DESC_ID_MESH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup(VulkanContext VkCtx) {
|
||||||
|
resetPipeline.CleanUp(VkCtx);
|
||||||
|
voxelGenerationPipeline.CleanUp(VkCtx);
|
||||||
|
meshGenerationPipeline.CleanUp(VkCtx);
|
||||||
|
|
||||||
|
resetLayout.CleanUp(VkCtx);
|
||||||
|
voxelGenerationLayout.CleanUp(VkCtx);
|
||||||
|
meshGenerationLayout.CleanUp(VkCtx);
|
||||||
|
|
||||||
|
voxelData.cleanup(VkCtx);
|
||||||
|
counters.cleanup(VkCtx);
|
||||||
|
meshPool.cleanup(VkCtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.DescriptorAllocator;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.vulkan.VkCommandBuffer;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.LongBuffer;
|
||||||
|
|
||||||
|
import static org.lwjgl.vulkan.VK13.*;
|
||||||
|
|
||||||
|
public class VoxelChunkGenerator {
|
||||||
|
public static final int CHUNK_SIZE = 16;
|
||||||
|
public static final int LOCAL_SIZE = 4;
|
||||||
|
public static final int DISPATCH_SIZE = CHUNK_SIZE / LOCAL_SIZE;
|
||||||
|
|
||||||
|
private final SharedVoxelTerrainResources resources;
|
||||||
|
|
||||||
|
public VoxelChunkGenerator(SharedVoxelTerrainResources resources) {
|
||||||
|
this.resources = resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordGenerateChunk(VulkanContext VkCtx,CommandBuffer commandBuffer, RenderChunk chunk) {
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
VkCommandBuffer cmd = commandBuffer.GetVulkanCommandBuffer();
|
||||||
|
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
|
||||||
|
|
||||||
|
ByteBuffer pushConstants = stack.malloc(SharedVoxelTerrainResources.TERRAIN_GENERATION_PUSH_CONSTANT_SIZE);
|
||||||
|
|
||||||
|
int vertexFloatOffset = (int) (chunk.vertexOffsetBytes() / Float.BYTES);
|
||||||
|
int indexOffset = (int) (chunk.indexOffsetBytes() / Integer.BYTES);
|
||||||
|
int indirectCommandIndex = (int) (chunk.indirectCommandOffsetBytes() / VoxelMeshPool.DRAW_INDEXED_INDIRECT_COMMAND_SIZE);
|
||||||
|
|
||||||
|
pushConstants.putInt(0, chunk.position().x);
|
||||||
|
pushConstants.putInt(4, chunk.position().y);
|
||||||
|
pushConstants.putInt(8, chunk.position().z);
|
||||||
|
pushConstants.putInt(12, chunk.slot());
|
||||||
|
pushConstants.putInt(16, vertexFloatOffset);
|
||||||
|
pushConstants.putInt(20, indexOffset);
|
||||||
|
pushConstants.putInt(24, indirectCommandIndex);
|
||||||
|
pushConstants.putInt(28, 0);
|
||||||
|
|
||||||
|
LongBuffer resetDescriptorSet = stack.longs(
|
||||||
|
allocator.GetDescriptorSet(resources.resetDescriptorId()).GetVkDescriptorSet()
|
||||||
|
);
|
||||||
|
|
||||||
|
LongBuffer voxelDescriptorSet = stack.longs(
|
||||||
|
allocator.GetDescriptorSet(resources.voxelGenerationDescriptorId()).GetVkDescriptorSet()
|
||||||
|
);
|
||||||
|
|
||||||
|
LongBuffer meshDescriptorSet = stack.longs(
|
||||||
|
allocator.GetDescriptorSet(resources.meshDescriptorId()).GetVkDescriptorSet()
|
||||||
|
);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipeline());
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipelineLayout(),0, resetDescriptorSet,null );
|
||||||
|
|
||||||
|
vkCmdPushConstants( cmd, resources.resetPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
|
||||||
|
|
||||||
|
vkCmdDispatch(cmd, 1, 1, 1);
|
||||||
|
|
||||||
|
VulkanUtils.BufferBarriers(stack, cmd,
|
||||||
|
new long[]{
|
||||||
|
resources.meshPool().indirectPoolHandle(),
|
||||||
|
resources.counters().GetBuffer()
|
||||||
|
},
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_WRITE_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT
|
||||||
|
);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.voxelGenerationPipeline().GetVulkanPipeline());
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.voxelGenerationPipeline().GetVulkanPipelineLayout(),0, voxelDescriptorSet,null );
|
||||||
|
|
||||||
|
vkCmdPushConstants( cmd, resources.voxelGenerationPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
|
||||||
|
|
||||||
|
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
|
||||||
|
|
||||||
|
VulkanUtils.BufferBarrier(stack, cmd,resources.voxelData().GetBuffer(),
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_WRITE_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_READ_BIT
|
||||||
|
);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmd,VK_PIPELINE_BIND_POINT_COMPUTE,resources.meshGenerationPipeline().GetVulkanPipeline() );
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.meshGenerationPipeline().GetVulkanPipelineLayout(),0, meshDescriptorSet,null );
|
||||||
|
|
||||||
|
vkCmdPushConstants( cmd, resources.meshGenerationPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
|
||||||
|
|
||||||
|
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
|
||||||
|
|
||||||
|
VulkanUtils.BufferBarriers(stack, cmd,
|
||||||
|
new long[]{
|
||||||
|
resources.voxelData().GetBuffer(),
|
||||||
|
resources.counters().GetBuffer(),
|
||||||
|
resources.meshPool().vertexPoolHandle(),
|
||||||
|
resources.meshPool().indexPoolHandle(),
|
||||||
|
resources.meshPool().indirectPoolHandle()
|
||||||
|
},
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT |
|
||||||
|
VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_WRITE_BIT,
|
||||||
|
VK_ACCESS_2_SHADER_READ_BIT |
|
||||||
|
VK_ACCESS_2_SHADER_WRITE_BIT |
|
||||||
|
VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT |
|
||||||
|
VK_ACCESS_2_INDEX_READ_BIT |
|
||||||
|
VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
public enum VoxelChunkVisibility {
|
||||||
|
EMPTY_AIR,
|
||||||
|
FULLY_SOLID_UNDERGROUND,
|
||||||
|
SURFACE
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||||
|
import static org.lwjgl.vulkan.VK13.*;
|
||||||
|
|
||||||
|
public class VoxelMeshPool{
|
||||||
|
public static final int CHUNK_SIZE = 16;
|
||||||
|
|
||||||
|
public static final int FLOATS_PER_VERTEX = 14;
|
||||||
|
public static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES;
|
||||||
|
|
||||||
|
public static final int MAX_VISIBLE_FACES_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * 12;
|
||||||
|
public static final int MAX_VERTICES_PER_CHUNK = MAX_VISIBLE_FACES_PER_CHUNK * 4;
|
||||||
|
public static final int MAX_INDICES_PER_CHUNK = MAX_VISIBLE_FACES_PER_CHUNK * 6;
|
||||||
|
|
||||||
|
public static final int INDEX_SIZE_BYTES = Integer.BYTES;
|
||||||
|
public static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES;
|
||||||
|
|
||||||
|
private final int maxChunks;
|
||||||
|
|
||||||
|
private final long vertexSlotSizeBytes;
|
||||||
|
private final long indexSlotSizeBytes;
|
||||||
|
private final long indirectSlotSizeBytes;
|
||||||
|
|
||||||
|
private final VulkanBuffer vertexPool;
|
||||||
|
private final VulkanBuffer indexPool;
|
||||||
|
private final VulkanBuffer indirectPool;
|
||||||
|
|
||||||
|
private final Queue<Integer> freeSlots = new ArrayDeque<>();
|
||||||
|
|
||||||
|
public VoxelMeshPool(VulkanContext VkCtx, int maxChunks) {
|
||||||
|
this.maxChunks = maxChunks;
|
||||||
|
|
||||||
|
this.vertexSlotSizeBytes = (long) MAX_VERTICES_PER_CHUNK * VERTEX_SIZE_BYTES;
|
||||||
|
this.indexSlotSizeBytes = (long) MAX_INDICES_PER_CHUNK * INDEX_SIZE_BYTES;
|
||||||
|
this.indirectSlotSizeBytes = DRAW_INDEXED_INDIRECT_COMMAND_SIZE;
|
||||||
|
|
||||||
|
long vertexPoolSize = vertexSlotSizeBytes * maxChunks;
|
||||||
|
long indexPoolSize = indexSlotSizeBytes * maxChunks;
|
||||||
|
long indirectPoolSize = indirectSlotSizeBytes * maxChunks;
|
||||||
|
|
||||||
|
vertexPool = new VulkanBuffer(VkCtx,vertexPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0);
|
||||||
|
|
||||||
|
indexPool = new VulkanBuffer(VkCtx,indexPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0);
|
||||||
|
|
||||||
|
indirectPool = new VulkanBuffer(VkCtx,indirectPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0);
|
||||||
|
|
||||||
|
for (int i = 0; i < maxChunks; i++) {
|
||||||
|
freeSlots.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderChunk allocate(Vector3i position) {
|
||||||
|
Integer slot = freeSlots.poll();
|
||||||
|
|
||||||
|
if (slot == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RenderChunk(new Vector3i(position),slot, vertexOffsetBytes(slot),indexOffsetBytes(slot),MAX_INDICES_PER_CHUNK,indirectCommandOffsetBytes(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free(RenderChunk chunk) {
|
||||||
|
freeSlots.add(chunk.slot());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long vertexOffsetBytes(int slot) {
|
||||||
|
return vertexSlotSizeBytes * slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long indexOffsetBytes(int slot) {
|
||||||
|
return indexSlotSizeBytes * slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long indirectCommandOffsetBytes(int slot) {
|
||||||
|
return indirectSlotSizeBytes * slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer vertexPool() {
|
||||||
|
return vertexPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer indexPool() {
|
||||||
|
return indexPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VulkanBuffer indirectPool() {
|
||||||
|
return indirectPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long vertexPoolHandle() {
|
||||||
|
return vertexPool.GetBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long indexPoolHandle() {
|
||||||
|
return indexPool.GetBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long indirectPoolHandle() {
|
||||||
|
return indirectPool.GetBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int maxChunks() {
|
||||||
|
return maxChunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int freeSlotCount() {
|
||||||
|
return freeSlots.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup(VulkanContext VkCtx) {
|
||||||
|
vertexPool.cleanup(VkCtx);
|
||||||
|
indexPool.cleanup(VkCtx);
|
||||||
|
indirectPool.cleanup(VkCtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
public final class VoxelTerrainHeightSampler {
|
||||||
|
private VoxelTerrainHeightSampler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double fract(double value) {
|
||||||
|
return value - Math.floor(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double mix(double a, double b, double t) {
|
||||||
|
return a * (1.0 - t) + b * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double rand(double x, double z) {
|
||||||
|
return fract(Math.sin(x * 12.9898 + z * 78.233) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double valueNoise(double x, double z) {
|
||||||
|
double ix = Math.floor(x);
|
||||||
|
double iz = Math.floor(z);
|
||||||
|
|
||||||
|
double fx = fract(x);
|
||||||
|
double fz = fract(z);
|
||||||
|
|
||||||
|
double a = rand(ix, iz);
|
||||||
|
double b = rand(ix + 1.0, iz);
|
||||||
|
double c = rand(ix, iz + 1.0);
|
||||||
|
double d = rand(ix + 1.0, iz + 1.0);
|
||||||
|
|
||||||
|
double ux = fx * fx * (3.0 - 2.0 * fx);
|
||||||
|
double uz = fz * fz * (3.0 - 2.0 * fz);
|
||||||
|
|
||||||
|
return mix(mix(a, b, ux), mix(c, d, ux), uz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double terrainHeight(double worldX, double worldZ) {
|
||||||
|
return valueNoise(worldX * 0.005, worldZ * 0.005) * 100.0
|
||||||
|
+ valueNoise(worldX * 0.01, worldZ * 0.01) * 10.0
|
||||||
|
+ valueNoise(worldX * 0.1, worldZ * 0.1) * 5.0
|
||||||
|
+ valueNoise(worldX, worldZ) * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double minHeightForChunkXZ(int chunkX, int chunkZ, int chunkSize) {
|
||||||
|
double min = Double.POSITIVE_INFINITY;
|
||||||
|
|
||||||
|
int worldMinX = chunkX * chunkSize;
|
||||||
|
int worldMinZ = chunkZ * chunkSize;
|
||||||
|
int worldMaxX = worldMinX + chunkSize - 1;
|
||||||
|
int worldMaxZ = worldMinZ + chunkSize - 1;
|
||||||
|
|
||||||
|
int samplesPerAxis = 5;
|
||||||
|
|
||||||
|
for (int sx = 0; sx < samplesPerAxis; sx++) {
|
||||||
|
for (int sz = 0; sz < samplesPerAxis; sz++) {
|
||||||
|
double tx = sx / (double) (samplesPerAxis - 1);
|
||||||
|
double tz = sz / (double) (samplesPerAxis - 1);
|
||||||
|
|
||||||
|
double x = mix(worldMinX, worldMaxX, tx);
|
||||||
|
double z = mix(worldMinZ, worldMaxZ, tz);
|
||||||
|
|
||||||
|
min = Math.min(min, terrainHeight(x, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double maxHeightForChunkXZ(int chunkX, int chunkZ, int chunkSize) {
|
||||||
|
double max = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
int worldMinX = chunkX * chunkSize;
|
||||||
|
int worldMinZ = chunkZ * chunkSize;
|
||||||
|
int worldMaxX = worldMinX + chunkSize - 1;
|
||||||
|
int worldMaxZ = worldMinZ + chunkSize - 1;
|
||||||
|
|
||||||
|
int samplesPerAxis = 5;
|
||||||
|
|
||||||
|
for (int sx = 0; sx < samplesPerAxis; sx++) {
|
||||||
|
for (int sz = 0; sz < samplesPerAxis; sz++) {
|
||||||
|
double tx = sx / (double) (samplesPerAxis - 1);
|
||||||
|
double tz = sz / (double) (samplesPerAxis - 1);
|
||||||
|
|
||||||
|
double x = mix(worldMinX, worldMaxX, tx);
|
||||||
|
double z = mix(worldMinZ, worldMaxZ, tz);
|
||||||
|
|
||||||
|
max = Math.max(max, terrainHeight(x, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VoxelChunkVisibility classifyChunk(int chunkX, int chunkY, int chunkZ, int chunkSize) {
|
||||||
|
int chunkMinY = chunkY * chunkSize;
|
||||||
|
int chunkMaxY = chunkMinY + chunkSize - 1;
|
||||||
|
|
||||||
|
double minHeight = minHeightForChunkXZ(chunkX, chunkZ, chunkSize);
|
||||||
|
double maxHeight = maxHeightForChunkXZ(chunkX, chunkZ, chunkSize);
|
||||||
|
|
||||||
|
double safetyPadding = 32.0;
|
||||||
|
|
||||||
|
if (chunkMinY > maxHeight + safetyPadding) {
|
||||||
|
return VoxelChunkVisibility.EMPTY_AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunkMaxY < minHeight - safetyPadding) {
|
||||||
|
return VoxelChunkVisibility.FULLY_SOLID_UNDERGROUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VoxelChunkVisibility.SURFACE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,274 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.vulkan.VkCommandBuffer;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.LongBuffer;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
import static org.lwjgl.vulkan.VK13.*;
|
||||||
|
|
||||||
|
public class VoxelWorldManager {
|
||||||
|
private static final int MAX_RESIDENT_CHUNKS = 512 * 24;
|
||||||
|
private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 32;
|
||||||
|
|
||||||
|
private static final ConcurrentLinkedQueue<Vector3i> RequestedChunks = new ConcurrentLinkedQueue<>();
|
||||||
|
private static final ConcurrentHashMap<Vector3i, RenderChunk> RenderChunks = new ConcurrentHashMap<>();
|
||||||
|
private static final ConcurrentHashMap<Vector3i, Boolean> KnownChunks = new ConcurrentHashMap<>();
|
||||||
|
private static final ConcurrentHashMap<Vector3i, VoxelChunkVisibility> CulledChunks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
private static SharedVoxelTerrainResources Resources;
|
||||||
|
private static VoxelChunkGenerator Generator;
|
||||||
|
|
||||||
|
private static ByteBuffer GraphicsPushConstants;
|
||||||
|
|
||||||
|
public static void Init(VulkanContext VkCtx) {
|
||||||
|
if (Resources != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources = new SharedVoxelTerrainResources(VkCtx, MAX_RESIDENT_CHUNKS);
|
||||||
|
Generator = new VoxelChunkGenerator(Resources);
|
||||||
|
|
||||||
|
GraphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc(
|
||||||
|
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE +
|
||||||
|
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.INT_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GenerateChunk(Vector3i Position) {
|
||||||
|
Vector3i key = new Vector3i(Position);
|
||||||
|
|
||||||
|
if (KnownChunks.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestedChunks.add(key);
|
||||||
|
KnownChunks.put(key, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GenerationOffset = 0;
|
||||||
|
public static Vector3i LastPosition = new Vector3i(0, 0, 0);
|
||||||
|
|
||||||
|
static int IterationX = 0;
|
||||||
|
static Vector3i ChunkPos = new Vector3i(0, 0, 0);
|
||||||
|
static Vector3i ChunkPos2 = new Vector3i(0, 0, 0);
|
||||||
|
|
||||||
|
public static void GenerateChunks(Vector3i Position, Vector3i Radius) {
|
||||||
|
int ChunkX = Position.x;
|
||||||
|
int ChunkY = Position.y;
|
||||||
|
int ChunkY2 = Position.y;
|
||||||
|
int ChunkZ = Position.z;
|
||||||
|
for (int Ry = 0; Ry <= Radius.y; Ry++)
|
||||||
|
{
|
||||||
|
for (int Rx = -IterationX; Rx <= IterationX; Rx++)
|
||||||
|
{
|
||||||
|
for (int Rz = -IterationX; Rz <= IterationX; Rz++)
|
||||||
|
{
|
||||||
|
ChunkX = Position.x + Rx;
|
||||||
|
ChunkY = Position.y + Ry;
|
||||||
|
ChunkY2 = Position.y - Ry;
|
||||||
|
ChunkZ = Position.z + Rz;
|
||||||
|
if (Rx == -IterationX || Rz == -IterationX || Rx == IterationX || Rz == IterationX)
|
||||||
|
{
|
||||||
|
GenerateChunk(ChunkPos.set(ChunkX, ChunkY, ChunkZ));
|
||||||
|
GenerateChunk(ChunkPos2.set(ChunkX, ChunkY2, ChunkZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IterationX++;
|
||||||
|
if (IterationX > Radius.x || Position.x != LastPosition.x || Position.y != LastPosition.y || Position.z != LastPosition.z)
|
||||||
|
{
|
||||||
|
IterationX = 0;
|
||||||
|
}
|
||||||
|
LastPosition.set(Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RecordGeneration(VulkanContext VkCtx, CommandBuffer commandBuffer) {
|
||||||
|
if (Resources == null) {
|
||||||
|
Init(VkCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int generatedThisFrame = 0;
|
||||||
|
|
||||||
|
while (!RequestedChunks.isEmpty() && generatedThisFrame < MAX_CHUNK_GENERATIONS_PER_FRAME) {
|
||||||
|
Vector3i position = RequestedChunks.poll();
|
||||||
|
|
||||||
|
if (position == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// VoxelChunkVisibility visibility = VoxelTerrainHeightSampler.classifyChunk(
|
||||||
|
// position.x,
|
||||||
|
// position.y,
|
||||||
|
// position.z,
|
||||||
|
// VoxelChunkGenerator.CHUNK_SIZE
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// if (visibility != VoxelChunkVisibility.SURFACE) {
|
||||||
|
// CulledChunks.put(new Vector3i(position), visibility);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
RenderChunk renderChunk = Resources.meshPool().allocate(position);
|
||||||
|
|
||||||
|
if (renderChunk == null) {
|
||||||
|
Logger.warn("Voxel mesh pool full. Could not allocate chunk {}", position);
|
||||||
|
RequestedChunks.add(position);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Generator.recordGenerateChunk(VkCtx, commandBuffer, renderChunk);
|
||||||
|
RenderChunks.put(new Vector3i(position), renderChunk);
|
||||||
|
|
||||||
|
generatedThisFrame++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RecordRender(VkCommandBuffer CommandBuffer,Pipeline graphicsPipeline, MaterialsCache materialsCache) {
|
||||||
|
if (Resources == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int terrainMaterialIndex = materialsCache.GetPosition("VoxelTerrain");
|
||||||
|
|
||||||
|
if (terrainMaterialIndex < 0) {
|
||||||
|
terrainMaterialIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
Matrix4f identity = new Matrix4f().identity();
|
||||||
|
|
||||||
|
identity.get(0, GraphicsPushConstants);
|
||||||
|
GraphicsPushConstants.putInt(
|
||||||
|
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE,
|
||||||
|
terrainMaterialIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
vkCmdPushConstants(CommandBuffer, graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
0,GraphicsPushConstants.slice(
|
||||||
|
0,
|
||||||
|
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE));
|
||||||
|
|
||||||
|
vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE,
|
||||||
|
GraphicsPushConstants.slice(
|
||||||
|
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE,
|
||||||
|
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.INT_SIZE ) );
|
||||||
|
|
||||||
|
LongBuffer vertexBuffers = stack.longs(Resources.meshPool().vertexPoolHandle());
|
||||||
|
LongBuffer offsets = stack.longs(0L);
|
||||||
|
|
||||||
|
vkCmdBindVertexBuffers(CommandBuffer, 0, vertexBuffers, offsets);
|
||||||
|
vkCmdBindIndexBuffer(CommandBuffer, Resources.meshPool().indexPoolHandle(), 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
|
||||||
|
RenderChunks.forEach((position, chunk) -> vkCmdDrawIndexedIndirect(CommandBuffer,Resources.meshPool().indirectPoolHandle(),
|
||||||
|
chunk.indirectCommandOffsetBytes(), 1,VoxelMeshPool.DRAW_INDEXED_INDIRECT_COMMAND_SIZE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnloadFarChunks(Vector3i centerChunk, int unloadRadius) {
|
||||||
|
int maxDistSq = unloadRadius * unloadRadius;
|
||||||
|
|
||||||
|
RenderChunks.entrySet().removeIf(entry -> {
|
||||||
|
Vector3i pos = entry.getKey();
|
||||||
|
|
||||||
|
int dx = pos.x - centerChunk.x;
|
||||||
|
int dy = pos.y - centerChunk.y;
|
||||||
|
int dz = pos.z - centerChunk.z;
|
||||||
|
|
||||||
|
int distSq = dx * dx + dy * dy + dz * dz;
|
||||||
|
|
||||||
|
if (distSq > maxDistSq) {
|
||||||
|
RenderChunk chunk = entry.getValue();
|
||||||
|
|
||||||
|
Resources.meshPool().free(chunk);
|
||||||
|
KnownChunks.remove(pos);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
CulledChunks.entrySet().removeIf(entry -> {
|
||||||
|
Vector3i pos = entry.getKey();
|
||||||
|
|
||||||
|
int dx = pos.x - centerChunk.x;
|
||||||
|
int dy = pos.y - centerChunk.y;
|
||||||
|
int dz = pos.z - centerChunk.z;
|
||||||
|
|
||||||
|
int distSq = dx * dx + dy * dy + dz * dz;
|
||||||
|
|
||||||
|
if (distSq > maxDistSq) {
|
||||||
|
KnownChunks.remove(pos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
RequestedChunks.removeIf(pos -> {
|
||||||
|
int dx = pos.x - centerChunk.x;
|
||||||
|
int dy = pos.y - centerChunk.y;
|
||||||
|
int dz = pos.z - centerChunk.z;
|
||||||
|
|
||||||
|
int distSq = dx * dx + dy * dy + dz * dz;
|
||||||
|
|
||||||
|
if (distSq > maxDistSq) {
|
||||||
|
KnownChunks.remove(pos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetRenderableChunkCount() {
|
||||||
|
return RenderChunks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetCulledChunkCount() {
|
||||||
|
return CulledChunks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetRequestedChunkCount() {
|
||||||
|
return RequestedChunks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetFreeMeshSlots() {
|
||||||
|
if (Resources == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Resources.meshPool().freeSlotCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void Cleanup(VulkanContext VkCtx) {
|
||||||
|
if (Resources != null) {
|
||||||
|
Resources.cleanup(VkCtx);
|
||||||
|
Resources = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GraphicsPushConstants != null) {
|
||||||
|
org.lwjgl.system.MemoryUtil.memFree(GraphicsPushConstants);
|
||||||
|
GraphicsPushConstants = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestedChunks.clear();
|
||||||
|
RenderChunks.clear();
|
||||||
|
KnownChunks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.DescriptorSetLayout;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.ShaderModule;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.vulkan.*;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.LongBuffer;
|
||||||
|
|
||||||
|
import static org.lwjgl.vulkan.VK10.*;
|
||||||
|
|
||||||
|
public class ComputePipeline implements Pipeline {
|
||||||
|
|
||||||
|
private final long VulkanPipeline;
|
||||||
|
private final long VulkanPipelineLayout;
|
||||||
|
|
||||||
|
public ComputePipeline(VulkanContext VkCtx,ShaderModule shaderModule, DescriptorSetLayout[] descriptorSetLayouts,PushConstantsRange[] pushConstantsRanges) {
|
||||||
|
Device device = VkCtx.GetDevice();
|
||||||
|
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
LongBuffer pPipelineLayout = stack.mallocLong(1);
|
||||||
|
LongBuffer pPipeline = stack.mallocLong(1);
|
||||||
|
int layoutCount = descriptorSetLayouts != null ? descriptorSetLayouts.length : 0;
|
||||||
|
LongBuffer setLayouts = stack.mallocLong(layoutCount);
|
||||||
|
for (int i = 0; i < layoutCount; i++) {
|
||||||
|
setLayouts.put(i, descriptorSetLayouts[i].GetVkDescriptorLayout());
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPushConstantRange.Buffer pushRanges = null;
|
||||||
|
int pushRangeCount = pushConstantsRanges != null ? pushConstantsRanges.length : 0;
|
||||||
|
if (pushRangeCount > 0) {
|
||||||
|
pushRanges = VkPushConstantRange.calloc(pushRangeCount, stack);
|
||||||
|
|
||||||
|
for (int i = 0; i < pushRangeCount; i++) {
|
||||||
|
PushConstantsRange range = pushConstantsRanges[i];
|
||||||
|
|
||||||
|
pushRanges.get(i)
|
||||||
|
.stageFlags(range.Stage())
|
||||||
|
.offset(range.Offset())
|
||||||
|
.size(range.Size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VkPipelineLayoutCreateInfo layoutInfo = VkPipelineLayoutCreateInfo.calloc(stack)
|
||||||
|
.sType$Default()
|
||||||
|
.pSetLayouts(setLayouts)
|
||||||
|
.pPushConstantRanges(pushRanges);
|
||||||
|
|
||||||
|
VulkanUtils.vkCheck(
|
||||||
|
vkCreatePipelineLayout(device.FetchVulkanDevice(), layoutInfo, null, pPipelineLayout),
|
||||||
|
"Unable to create compute pipeline layout"
|
||||||
|
);
|
||||||
|
VulkanPipelineLayout = pPipelineLayout.get(0);
|
||||||
|
ByteBuffer main = stack.UTF8("main");
|
||||||
|
VkPipelineShaderStageCreateInfo shaderStage = VkPipelineShaderStageCreateInfo.calloc(stack)
|
||||||
|
.sType$Default()
|
||||||
|
.stage(VK_SHADER_STAGE_COMPUTE_BIT)
|
||||||
|
.module(shaderModule.GetHandle())
|
||||||
|
.pName(main);
|
||||||
|
|
||||||
|
VkComputePipelineCreateInfo.Buffer pipelineInfo = VkComputePipelineCreateInfo.calloc(1, stack)
|
||||||
|
.sType$Default()
|
||||||
|
.stage(shaderStage)
|
||||||
|
.layout(VulkanPipelineLayout);
|
||||||
|
|
||||||
|
VulkanUtils.vkCheck(vkCreateComputePipelines(device.FetchVulkanDevice(),VkCtx.GetVkPipelineCache().GetVkPipelineCache(),
|
||||||
|
pipelineInfo,null,pPipeline),"Unable to create compute pipeline" );
|
||||||
|
|
||||||
|
VulkanPipeline = pPipeline.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long GetVulkanPipeline() {
|
||||||
|
return VulkanPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long GetVulkanPipelineLayout() {
|
||||||
|
return VulkanPipelineLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void CleanUp(VulkanContext VkCtx) {
|
||||||
|
VkDevice device = VkCtx.GetDevice().FetchVulkanDevice();
|
||||||
|
vkDestroyPipeline(device, VulkanPipeline, null);
|
||||||
|
vkDestroyPipelineLayout(device, VulkanPipelineLayout, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer;
|
||||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
|
||||||
|
|
@ -379,6 +380,8 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
|
||||||
|
|
||||||
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
|
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
|
||||||
|
|
||||||
|
VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache);
|
||||||
|
|
||||||
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
|
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
|
||||||
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
|
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
|
||||||
skyboxViewMatrix.m30(0.0f);
|
skyboxViewMatrix.m30(0.0f);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.DeferredRendering.DeferredSceneRender;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.DeferredRendering.DeferredSceneRender;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer;
|
||||||
|
|
@ -363,6 +364,7 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
|
||||||
.put(3,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet());
|
.put(3,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet());
|
||||||
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipelineLayout() : VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null);
|
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipelineLayout() : VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null);
|
||||||
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
|
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
|
||||||
|
VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache);
|
||||||
|
|
||||||
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
|
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
|
||||||
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
|
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.Scene.SceneLightingManager;
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.SceneLightingManager;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment;
|
||||||
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.ITexture;
|
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.ITexture;
|
||||||
|
|
@ -393,7 +394,7 @@ public class ShadowRenderer {
|
||||||
vkCmdDrawIndexed(cmdHandle, vulkanMesh.IndicesCount(), 1, 0, 0, 0);
|
vkCmdDrawIndexed(cmdHandle, vulkanMesh.IndicesCount(), 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VoxelWorldManager.RecordRender(cmdHandle,pipeline,materialsCache);
|
||||||
vkCmdEndRendering(cmdHandle);
|
vkCmdEndRendering(cmdHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ public class DescriptorSet {
|
||||||
.sType$Default()
|
.sType$Default()
|
||||||
.dstSet(VkDescriptorSet)
|
.dstSet(VkDescriptorSet)
|
||||||
.dstBinding(Binding)
|
.dstBinding(Binding)
|
||||||
|
.dstArrayElement(0)
|
||||||
.descriptorType(Type)
|
.descriptorType(Type)
|
||||||
.descriptorCount(1)
|
.descriptorCount(1)
|
||||||
.pBufferInfo(BufferInfo);
|
.pBufferInfo(BufferInfo);
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,50 @@ public class VulkanUtils {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void BufferBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long BufferHandle,
|
||||||
|
long SrcStage,long DstStage,long SrcAccess,long DstAccess){
|
||||||
|
var BufferBarrier = VkBufferMemoryBarrier2.calloc(1, MemStack)
|
||||||
|
.sType$Default()
|
||||||
|
.srcStageMask(SrcStage)
|
||||||
|
.dstStageMask(DstStage)
|
||||||
|
.srcAccessMask(SrcAccess)
|
||||||
|
.dstAccessMask(DstAccess)
|
||||||
|
.srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
|
||||||
|
.dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
|
||||||
|
.buffer(BufferHandle)
|
||||||
|
.offset(0)
|
||||||
|
.size(VK_WHOLE_SIZE);
|
||||||
|
VkDependencyInfo DependencyInfo = VkDependencyInfo.calloc(MemStack)
|
||||||
|
.sType$Default()
|
||||||
|
.pBufferMemoryBarriers(BufferBarrier);
|
||||||
|
vkCmdPipelineBarrier2(CommandHandle, DependencyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BufferBarriers(MemoryStack MemStack,VkCommandBuffer CommandHandle,long[] Buffers,
|
||||||
|
long SrcStage,long DstStage,long SrcAccess,long DstAccess ){
|
||||||
|
var BufferBarriers = VkBufferMemoryBarrier2.calloc(Buffers.length, MemStack);
|
||||||
|
for (int i = 0; i < Buffers.length; i++) {
|
||||||
|
BufferBarriers.get(i)
|
||||||
|
.sType$Default()
|
||||||
|
.srcStageMask(SrcStage)
|
||||||
|
.dstStageMask(DstStage)
|
||||||
|
.srcAccessMask(SrcAccess)
|
||||||
|
.dstAccessMask(DstAccess)
|
||||||
|
.srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
|
||||||
|
.dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
|
||||||
|
.buffer(Buffers[i])
|
||||||
|
.offset(0)
|
||||||
|
.size(VK_WHOLE_SIZE);
|
||||||
|
}
|
||||||
|
VkDependencyInfo DependencyInfo = VkDependencyInfo.calloc(MemStack)
|
||||||
|
.sType$Default()
|
||||||
|
.pBufferMemoryBarriers(BufferBarriers);
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier2(CommandHandle, DependencyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
public static void ImageBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long Image, int OldLayout,
|
public static void ImageBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long Image, int OldLayout,
|
||||||
int NewLayout, long SrcStage, long DstStage, long SrcAccess, long DstAccess,
|
int NewLayout, long SrcStage, long DstStage, long SrcAccess, long DstAccess,
|
||||||
int AspectMask){
|
int AspectMask){
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue