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 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 metallic = pbr.b;

View file

@ -66,9 +66,13 @@ void main()
} else{
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
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) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}

View file

@ -88,11 +88,16 @@ void main()
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
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) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
outOpacity = Opacity;
float opacityf = Opacity.x + Opacity.y + Opacity.z;

View file

@ -65,11 +65,16 @@ void main()
} else{
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
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) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3;
if(opacityf < 0.9){discard;}

View file

@ -94,9 +94,13 @@ void main()
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
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) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
outOpacity = Opacity;

View file

@ -64,9 +64,13 @@ void main()
} else{
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
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) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}

View file

@ -96,9 +96,13 @@ void main()
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a,outAlbedo.a,outAlbedo.a,1);
if(material.OpacityFactor != 1) Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1);
if(material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES){
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
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) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
outOpacity = Opacity;

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.Rendering.SkyBox;
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.GuiTexture;
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.Util.VulkanUtils;
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBufferSubmitInfo;
import org.lwjgl.vulkan.VkExtent2D;
@ -179,6 +183,8 @@ public class VulkanRenderer implements Renderer {
spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache);
spriteRenderer.LoadMaterials(RendererContext,materialsCache,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;}
@ -196,6 +202,9 @@ public class VulkanRenderer implements Renderer {
public void cleanup() {
RendererContext.GetDevice().waitIdle();
Logger.debug("Waiting Vulkan Context");
VoxelWorldManager.Cleanup(RendererContext);
sceneRender.cleanup(RendererContext);
if(ssaoRenderer != null)ssaoRenderer.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 DebugRenderMode debugMode = DebugRenderMode.Albedo;
Vector3f CamPos = new Vector3f();
public void DeferredRender(EngineInstance engineInstance){
SwapChain swapChain = RendererContext.GetSwapChain();
WaitForFence(CurrentFrame);
@ -247,9 +256,8 @@ public class VulkanRenderer implements Renderer {
var CommandPool = CommandPools[CurrentFrame];
var CommandBuffer = CommandBuffers[CurrentFrame];
RecordingStart(CommandPool, CommandBuffer);
VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer);
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
boolean RenderShadows = ShadowRenderer.AllowShadowRendering() && EngineConfig.getInstance().RenderShadows();
if(RenderShadows) {shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); }
@ -289,9 +297,8 @@ public class VulkanRenderer implements Renderer {
resize(engineInstance);
return;
}
RecordingStart(CommandPool, CommandBuffer);
VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer);
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour());
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.Profiling.CPUMonitor;
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.ServerSideNetworkUtils;
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.ModelData;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Forward.ForwardSceneRender;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.joml.*;
import org.lwjgl.openal.AL11;
import org.tinylog.Logger;
import java.lang.Math;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -51,7 +51,7 @@ import static org.lwjgl.glfw.GLFW.*;
public class GameCore implements GameLogic {
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;
private Vector2f LastMousePos = new Vector2f(0,0);
@ -161,6 +161,9 @@ public class GameCore implements GameLogic {
}
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(CollisionVisualisationMat);
materials.addAll(MelonaMaterial);
@ -283,11 +286,11 @@ public class GameCore implements GameLogic {
permutation.GeneratePermutationArray(5783904701859L);
for(int x = -1; x < 2; x++){
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++){
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.UsernameBuffer.set("Player");
@ -651,10 +654,20 @@ public class GameCore implements GameLogic {
FetchingMetrics = false;
return imGuiIO.getWantCaptureKeyboard();
}
Vector3f CamPos = new Vector3f();
@Override
public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
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++) {
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.Actor3DElement;
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.SceneRenderer;
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
@ -379,6 +380,8 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache);
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
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.Actor3DElement;
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.Structure.DisplayToScreen.ImageView;
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());
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipelineLayout() : VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null);
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache);
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
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.IScene;
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.Images.Attachment;
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);
}
}
VoxelWorldManager.RecordRender(cmdHandle,pipeline,materialsCache);
vkCmdEndRendering(cmdHandle);
}
}

View file

@ -47,6 +47,7 @@ public class DescriptorSet {
.sType$Default()
.dstSet(VkDescriptorSet)
.dstBinding(Binding)
.dstArrayElement(0)
.descriptorType(Type)
.descriptorCount(1)
.pBufferInfo(BufferInfo);

View file

@ -206,6 +206,50 @@ public class VulkanUtils {
}
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,
int NewLayout, long SrcStage, long DstStage, long SrcAccess, long DstAccess,
int AspectMask){