what if minecraft ran on the GPU exclusively? glad you asked! because now it can

This commit is contained in:
Halbear 2026-09-15 20:49:24 +01:00
parent fa7bf893e7
commit bf9af81f38
41 changed files with 2433 additions and 34 deletions

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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);
} }

View file

@ -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;

View file

@ -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;}

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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);

View file

@ -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();
} }

View file

@ -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);
}
}
}

View file

@ -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) {
}

View file

@ -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);
}
}

View file

@ -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
);
}
}
}

View file

@ -0,0 +1,7 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
public enum VoxelChunkVisibility {
EMPTY_AIR,
FULLY_SOLID_UNDERGROUND,
SURFACE
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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());

View file

@ -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);
} }
} }

View file

@ -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);

View file

@ -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){