i did a little memory optimisation (19GB of VRAM -> 2.6GB of VRAM), lost some FPS in vertex rendering as a result but i'll figure it out

This commit is contained in:
Halbear 2026-09-16 20:38:37 +01:00
parent bf9af81f38
commit ce7051d8ca
21 changed files with 766 additions and 592 deletions

View file

@ -7,6 +7,7 @@ const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
const int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; const int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
const uint FLOATS_PER_VERTEX = 14u; const uint FLOATS_PER_VERTEX = 14u;
const uint INTEGERS_PER_VERTEX = 1u;
const uint VERTICES_PER_FACE = 4u; const uint VERTICES_PER_FACE = 4u;
const uint INDICES_PER_FACE = 6u; const uint INDICES_PER_FACE = 6u;
@ -89,13 +90,12 @@ void emitFace(ivec3 voxelPos, int faceIndex) {
return; return;
} }
vec3 p = vec3(chunkPos * CHUNK_SIZE + voxelPos); vec3 p = vec3(voxelPos);
vec3 normal; vec3 normal;
vec3 tangent; vec3 tangent;
vec3 bitangent; vec3 bitangent;
vec3 v0; vec3 v0;
vec3 v1; vec3 v1;
vec3 v2; vec3 v2;

View file

@ -6,261 +6,72 @@ const int CHUNK_SIZE = 16;
const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE; const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
const int VOXEL_COUNT = CHUNK_SIZE * 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 = 6u;
const uint VERTICES_PER_FACE = 4u; const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * 6);
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 { layout(std430, binding = 0) readonly buffer VoxelData {
uint voxels[]; uint voxels[];
}; };
layout(std430, binding = 1) buffer VertexBuffer { layout(std430, binding = 1) buffer FaceBuffer {
float vertices[]; uint faces[];
};
layout(std430, binding = 2) buffer IndexBuffer {
uint indices[];
}; };
struct DrawCommand { struct DrawCommand {
uint indexCount; uint vertexCount;
uint instanceCount; uint instanceCount;
uint firstIndex; uint firstVertex;
int vertexOffset;
uint firstInstance; uint firstInstance;
}; };
layout(std430, binding = 3) buffer DrawCommands { layout(std430, binding = 2) buffer DrawCommands {
DrawCommand drawCmds[]; DrawCommand drawCmds[];
}; };
layout(std430, binding = 3) buffer Counters {
uint faceCount;
} counters;
layout(push_constant) uniform ChunkInfo { layout(push_constant) uniform ChunkInfo {
ivec3 chunkPos; ivec3 chunkPos;
int slot; int slot;
uint vertexFloatOffset; uint faceOffset;
uint indexOffset; uint unused0;
uint indirectCommandIndex; uint indirectCommandIndex;
uint padding0; uint padding0;
}; };
layout(std430, binding = 4) buffer Counters {
uint vertexCount;
uint indexCount;
} counters;
uint flatten(ivec3 pos) { uint flatten(ivec3 pos) {
return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z); return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z);
} }
uint getVoxel(ivec3 pos) { uint getVoxel(ivec3 pos) {
if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0; if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0u;
if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0; if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0u;
if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0; if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0u;
return voxels[flatten(pos)]; return voxels[flatten(pos)];
} }
void writeVertex(uint vertexIndex, vec3 position, vec3 normal, vec3 tangent, vec3 bitangent, vec2 uv) { uint packFace(uvec3 voxelPos, uint faceIndex, uint materialId, uint ao) {
uint base = vertexFloatOffset + vertexIndex * FLOATS_PER_VERTEX; return (voxelPos.x & 0x1Fu) |
((voxelPos.y & 0x1Fu) << 5u) |
vertices[base + 0u] = position.x; ((voxelPos.z & 0x1Fu) << 10u) |
vertices[base + 1u] = position.y; ((faceIndex & 0x7u) << 15u) |
vertices[base + 2u] = position.z; ((materialId & 0xFFu) << 18u) |
((ao & 0x3u) << 26u);
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) { void emitFace(ivec3 voxelPos, uint faceIndex, uint voxelType) {
uint localBaseVertex = atomicAdd(counters.vertexCount, VERTICES_PER_FACE); uint localFace = atomicAdd(counters.faceCount, 1u);
uint localBaseIndex = atomicAdd(counters.indexCount, INDICES_PER_FACE);
if (localBaseVertex + VERTICES_PER_FACE > MAX_VERTICES || if (localFace >= MAX_VISIBLE_FACES_PER_CHUNK) {
localBaseIndex + INDICES_PER_FACE > MAX_INDICES) {
return; return;
} }
uint baseVertex = localBaseVertex; faces[faceOffset + localFace] = packFace(uvec3(voxelPos), faceIndex, voxelType, 0u);
uint baseIndex = indexOffset + localBaseIndex;
vec3 p = vec3(chunkPos * CHUNK_SIZE + voxelPos); atomicAdd(drawCmds[indirectCommandIndex].vertexCount, VERTICES_PER_FACE);
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() { void main() {
@ -276,10 +87,10 @@ void main() {
return; return;
} }
if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u) emitFace(pos, 0,current); if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u) emitFace(pos, 0u, current);
if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1,current); if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1u, current);
if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2,current); if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2u, current);
if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3,current); if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3u, current);
if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4,current); if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4u, current);
if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5,current); if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5u, current);
} }

View file

@ -2,13 +2,10 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
const uint FLOATS_PER_VERTEX = 14u;
struct DrawCommand { struct DrawCommand {
uint indexCount; uint vertexCount;
uint instanceCount; uint instanceCount;
uint firstIndex; uint firstVertex;
int vertexOffset;
uint firstInstance; uint firstInstance;
}; };
@ -17,26 +14,23 @@ layout(std430, binding = 0) buffer DrawCommands {
}; };
layout(std430, binding = 1) buffer Counters { layout(std430, binding = 1) buffer Counters {
uint vertexCount; uint faceCount;
uint indexCount;
} counters; } counters;
layout(push_constant) uniform ChunkInfo { layout(push_constant) uniform ChunkInfo {
ivec3 chunkPos; ivec3 chunkPos;
int slot; int slot;
uint vertexFloatOffset; uint faceOffset;
uint indexOffset; uint unused0;
uint indirectCommandIndex; uint indirectCommandIndex;
uint padding0; uint padding0;
}; };
void main() { void main() {
drawCmds[indirectCommandIndex].indexCount = 0u; drawCmds[indirectCommandIndex].vertexCount = 0u;
drawCmds[indirectCommandIndex].instanceCount = 1u; drawCmds[indirectCommandIndex].instanceCount = 1u;
drawCmds[indirectCommandIndex].firstIndex = indexOffset; drawCmds[indirectCommandIndex].firstVertex = faceOffset * 6u;
drawCmds[indirectCommandIndex].vertexOffset = int(vertexFloatOffset / FLOATS_PER_VERTEX);
drawCmds[indirectCommandIndex].firstInstance = 0u; drawCmds[indirectCommandIndex].firstInstance = 0u;
counters.vertexCount = 0u; counters.faceCount = 0u;
counters.indexCount = 0u;
} }

View file

@ -9,187 +9,70 @@ layout(std430, binding = 0) buffer VoxelData {
uint voxels[]; uint voxels[];
}; };
layout(push_constant) uniform ChunkOffset { layout(push_constant) uniform ChunkInfo {
ivec3 chunkPos; ivec3 chunkPos;
int slot; int slot;
uint vertexFloatOffset; uint faceOffset;
uint indexOffset; uint unused0;
uint indirectCommandIndex; uint indirectCommandIndex;
uint padding0; uint padding0;
}; };
// Description : Array and textureless GLSL 2D/3D/4D simplex vec3 random3(vec3 st) {
// noise functions. return fract(sin(vec3(
// Author : Ian McEwan, Ashima Arts. dot(st, vec3(127.1, 311.7, 74.7)),
// Maintainer : stegu dot(st, vec3(269.5, 183.3, 246.1)),
// Lastmod : 20110822 (ijm) dot(st, vec3(113.5, 271.9, 124.6))
// License : Copyright (C) 2011 Ashima Arts. All rights reserved. )) * 43758.5453123);
// 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 random3to1(vec3 st) {
float value = 0.0; return fract(sin(dot(st, vec3(127.1, 311.7, 74.7))) * 43758.5453123);
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 interpolate(float a, float b, float c, float d, float x) {
float value = 0.0; float p = (d - c) - (a - b);
float amplitude = 0.5;
float frequency = 1.0;
float amplitudeSum = 0.0;
for (int i = 0; i < octaves; i++) { return x * (x * (x * p + ((a - b) - p)) + (c - a)) + b;
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 sampleX(vec3 at) {
float wx = fbm(p + vec2(17.31, 91.73), 3, 2.0, 0.5); float floored = floor(at.x);
float wz = fbm(p + vec2(43.17, 12.89), 3, 2.0, 0.5);
return p + vec2(wx, wz) * 35.0; return interpolate(
random3to1(vec3(floored - 1.0, at.yz)),
random3to1(vec3(floored, at.yz)),
random3to1(vec3(floored + 1.0, at.yz)),
random3to1(vec3(floored + 2.0, at.yz)),
at.x - floored) * 0.5 + 0.25;
} }
float terrainHeight(vec2 worldXZ) { float sampleY(vec3 at) {
vec2 p = worldXZ; float floored = floor(at.y);
vec2 warped = domainWarp(p * 0.004); return interpolate(
sampleX(vec3(at.x, floored - 1.0, at.z)),
float broad = fbm(warped * 0.45, 5, 2.0, 0.5); sampleX(vec3(at.x, floored, at.z)),
broad = broad * 0.5 + 0.5; sampleX(vec3(at.x, floored + 1.0, at.z)),
sampleX(vec3(at.x, floored + 2.0, at.z)),
float hills = fbm(p * 0.025, 4, 2.0, 0.48); at.y - floored);
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 cubicNoise(vec3 at) {
float floored = floor(at.z);
return interpolate(
sampleY(vec3(at.xy, floored - 1.0)),
sampleY(vec3(at.xy, floored)),
sampleY(vec3(at.xy, floored + 1.0)),
sampleY(vec3(at.xy, floored + 2.0)),
at.z - floored);
}
float rand(vec2 co) { float rand(vec2 co) {
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453123); 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) { float valueNoise(vec2 st) {
vec2 i = floor(st); vec2 i = floor(st);
vec2 f = fract(st); vec2 f = fract(st);
@ -205,37 +88,29 @@ float valueNoise(vec2 st) {
(c - a) * u.y * (1.0 - u.x) + (c - a) * u.y * (1.0 - u.x) +
(d - b) * u.x * u.y; (d - b) * u.x * u.y;
} }
bool isCave(vec3 worldPos) {
vec3 X = vec3(worldPos);
X = mat3(
0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626) * X;
float n = cubicNoise(X);
vec2 randG(vec2 p) { return n > 0.5;
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() { void main() {
ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz); ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz);
ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos; 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; float islandheight = valueNoise(vec2(worldPos.z, worldPos.x) * 0.005) * 100 + valueNoise(vec2(worldPos.x, worldPos.z) * 0.1) * 20 + valueNoise(vec2(worldPos.x, worldPos.z) * 0.1) * 5+ valueNoise(vec2(worldPos.x, worldPos.z)) * 0.5 - 15;
//height = clamp(height, 4.0, 28.0);
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;
float height2 = 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 + 100;
float islandheight2 = 100 + valueNoise(vec2(-worldPos.z, -worldPos.x) * 0.005) * 100 + valueNoise(vec2(-worldPos.x, -worldPos.z) * 0.1) * 20 + valueNoise(vec2(worldPos.x, worldPos.z) * 0.1) * 5+ valueNoise(vec2(worldPos.x, worldPos.z)) * 0.5 - 5;
//height = clamp(height, 4.0, 28.0);
uint voxelType = 0u; uint voxelType = 0u;
if (float(worldPos.y) <= height && float(floor(worldPos.y/CHUNK_SIZE) * CHUNK_SIZE + CHUNK_SIZE * 2) >= height) { if (float(worldPos.y) <= height && float(worldPos.y) >= islandheight) {
float depthBelowSurface = height - float(worldPos.y); float depthBelowSurface = height - float(worldPos.y);
if (depthBelowSurface < 1.5) { if (depthBelowSurface < 1.5) {
@ -246,14 +121,23 @@ void main() {
voxelType = 3u; // Stone voxelType = 3u; // Stone
} }
} }
if(float(worldPos.y) <= height2 && float(worldPos.y) >= islandheight2){
float depthBelowSurface = height2 - float(worldPos.y);
// if (voxelType != 0u && worldPos.y < int(height) - 6) { if (depthBelowSurface < 1.5) {
// float cave = fbm3D(vec3(worldPos) * 0.045, 4, 2.0, 0.5); voxelType = 1u; // Grass/topsoil
// } else if (depthBelowSurface < 5.0) {
// if (cave > 0.42) { voxelType = 2u; // Dirt
// voxelType = 0u; } else {
// } voxelType = 3u; // Stone
// } }
}
if (voxelType != 0u) {
if (isCave(vec3(worldPos*0.05))) {
voxelType = 0u;
}
}
uint index = uint((localPos.x * CHUNK_AREA) + (localPos.y * CHUNK_SIZE) + localPos.z); uint index = uint((localPos.x * CHUNK_AREA) + (localPos.y * CHUNK_SIZE) + localPos.z);
voxels[index] = voxelType; voxels[index] = voxelType;

View file

@ -0,0 +1,96 @@
#version 450
layout(location = 0) in uint inPackedVertex;
layout(location = 0) out vec4 outPos;
layout(location = 1) out vec3 outNormal;
layout(location = 2) out vec3 outTangent;
layout(location = 3) out vec3 outBitangent;
layout(location = 4) out vec2 outTextCoords;
layout(location = 5) out mat4 viewMatrix;
const vec3 NORMALS[6] = vec3[6](
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, -1.0, 0.0),
vec3( 1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3( 0.0, 0.0, 1.0),
vec3( 0.0, 0.0, -1.0)
);
const vec3 TANGENTS[6] = vec3[6](
vec3( 1.0, 0.0, 0.0),
vec3( 1.0, 0.0, 0.0),
vec3( 0.0, 0.0, -1.0),
vec3( 0.0, 0.0, 1.0),
vec3( 1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0)
);
const vec3 BITANGENTS[6] = vec3[6](
vec3( 0.0, 0.0, 1.0),
vec3( 0.0, 0.0, -1.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0)
);
const vec2 CORNER_UVS[16] = vec2[16](
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0),
vec2(0.0, 0.5),
vec2(0.0, 1.0),
vec2(0.5, 1.0),
vec2(0.5, 0.5),
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0),
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0)
);
layout(set = 0, binding = 0) uniform ProjUniform { mat4 matrix; } projUniform;
layout(set = 1, binding = 0) uniform ViewUniform { mat4 matrix; } viewUniform;
layout(push_constant) uniform pc {
vec4 ModelOffset;
vec4 Padding0;
vec4 Padding1;
vec4 Padding2;
} push_constants;
void main() {
viewMatrix = viewUniform.matrix;
uint posX = inPackedVertex & 0x1Fu;
uint posY = (inPackedVertex >> 5u) & 0x1Fu;
uint posZ = (inPackedVertex >> 10u) & 0x1Fu;
uint faceIdx = (inPackedVertex >> 15u) & 0x7u;
uint cornerIdx = (inPackedVertex >> 18u) & 0x3u;
uint matId = (inPackedVertex >> 20u) & 0xFFu;
vec3 inPos = vec3(posX, posY, posZ) + push_constants.ModelOffset.xyz * 16.0;
vec3 inNormal = NORMALS[faceIdx];
vec3 inTangent = TANGENTS[faceIdx];
vec3 inBitangent = BITANGENTS[faceIdx];
vec2 inTextCoords = CORNER_UVS[cornerIdx + 4 * matId];
vec4 worldPos = vec4(inPos, 1.0);
gl_Position = projUniform.matrix * viewUniform.matrix * worldPos;
outPos = worldPos;
outNormal = inNormal;
outTangent = inTangent;
outBitangent = inBitangent;
outTextCoords = inTextCoords;
}

View file

@ -0,0 +1,149 @@
#version 450
layout(location = 0) out vec4 outPos;
layout(location = 1) out vec3 outNormal;
layout(location = 2) out vec3 outTangent;
layout(location = 3) out vec3 outBitangent;
layout(location = 4) out vec2 outTextCoords;
layout(location = 5) out mat4 viewMatrix;
layout(set = 0, binding = 0) uniform ProjUniform { mat4 matrix; } projUniform;
layout(set = 1, binding = 0) uniform ViewUniform { mat4 matrix; } viewUniform;
layout(set = 4, binding = 0) readonly buffer FaceBuffer {
uint faces[];
};
layout(push_constant) uniform pc {
vec4 ModelOffset;
vec4 Padding0;
vec4 Padding1;
vec4 Padding2;
} push_constants;
const uint TRI_TO_CORNER[6] = uint[6](0u, 1u, 2u, 0u, 2u, 3u);
const vec3 NORMALS[6] = vec3[6](
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, -1.0, 0.0),
vec3( 1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3( 0.0, 0.0, 1.0),
vec3( 0.0, 0.0, -1.0)
);
const vec3 TANGENTS[6] = vec3[6](
vec3( 1.0, 0.0, 0.0),
vec3( 1.0, 0.0, 0.0),
vec3( 0.0, 0.0, -1.0),
vec3( 0.0, 0.0, 1.0),
vec3( 1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0)
);
const vec3 BITANGENTS[6] = vec3[6](
vec3( 0.0, 0.0, 1.0),
vec3( 0.0, 0.0, -1.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0)
);
const vec2 CORNER_UVS[16] = vec2[16](
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0),
vec2(0.0, 0.5),
vec2(0.0, 1.0),
vec2(0.5, 1.0),
vec2(0.5, 0.5),
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0),
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0)
);
vec3 buildFaceCornerPosition(uvec3 voxelPos, uint faceId, uint cornerIndex) {
vec3 p = vec3(voxelPos);
if (faceId == 0u) {
if (cornerIndex == 0u) return p + vec3(0.0, 1.0, 0.0);
if (cornerIndex == 1u) return p + vec3(0.0, 1.0, 1.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 1.0);
return p + vec3(1.0, 1.0, 0.0);
}
if (faceId == 1u) {
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(1.0, 0.0, 0.0);
if (cornerIndex == 2u) return p + vec3(1.0, 0.0, 1.0);
return p + vec3(0.0, 0.0, 1.0);
}
if (faceId == 2u) {
if (cornerIndex == 0u) return p + vec3(1.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(1.0, 1.0, 0.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 1.0);
return p + vec3(1.0, 0.0, 1.0);
}
if (faceId == 3u) {
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(0.0, 0.0, 1.0);
if (cornerIndex == 2u) return p + vec3(0.0, 1.0, 1.0);
return p + vec3(0.0, 1.0, 0.0);
}
if (faceId == 4u) {
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 1.0);
if (cornerIndex == 1u) return p + vec3(1.0, 0.0, 1.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 1.0);
return p + vec3(0.0, 1.0, 1.0);
}
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(0.0, 1.0, 0.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 0.0);
return p + vec3(1.0, 0.0, 0.0);
}
void main() {
viewMatrix = viewUniform.matrix;
uint faceRecordIndex = uint(gl_VertexIndex) / 6u;
uint triangleVertex = uint(gl_VertexIndex) % 6u;
uint cornerIndex = TRI_TO_CORNER[triangleVertex];
uint packedFace = faces[faceRecordIndex];
uint voxelX = packedFace & 0x1Fu;
uint voxelY = (packedFace >> 5u) & 0x1Fu;
uint voxelZ = (packedFace >> 10u) & 0x1Fu;
uint faceId = (packedFace >> 15u) & 0x7u;
uint matId = (packedFace >> 18u) & 0xFFu;
faceId = min(faceId, 5u);
matId = min(matId, 3u);
vec3 localPos = buildFaceCornerPosition(uvec3(voxelX, voxelY, voxelZ), faceId, cornerIndex);
vec3 worldPos = localPos + push_constants.ModelOffset.xyz * 16.0;
vec4 worldPosVec4 = vec4(worldPos, 1.0);
gl_Position = projUniform.matrix * viewUniform.matrix * worldPosVec4;
outPos = worldPosVec4;
outNormal = NORMALS[faceId];
outTangent = TANGENTS[faceId];
outBitangent = BITANGENTS[faceId];
outTextCoords = CORNER_UVS[cornerIndex + 4u * matId];
}

View file

@ -0,0 +1,84 @@
#version 450
layout(set = 3, binding = 0) readonly buffer FaceBuffer {
uint faces[];
};
layout(push_constant) uniform matrices {
vec4 ModelOffset;
vec4 Padding0;
vec4 Padding1;
vec4 Padding2;
uint materialIdx;
} push_constants;
layout(location = 0) out vec2 outTextCoord;
layout(location = 1) out flat uint outMaterialIdx;
const uint TRI_TO_CORNER[6] = uint[6](0u, 1u, 2u, 0u, 2u, 3u);
vec3 buildFaceCornerPosition(uvec3 voxelPos, uint faceId, uint cornerIndex) {
vec3 p = vec3(voxelPos);
if (faceId == 0u) {
if (cornerIndex == 0u) return p + vec3(0.0, 1.0, 0.0);
if (cornerIndex == 1u) return p + vec3(0.0, 1.0, 1.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 1.0);
return p + vec3(1.0, 1.0, 0.0);
}
if (faceId == 1u) {
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(1.0, 0.0, 0.0);
if (cornerIndex == 2u) return p + vec3(1.0, 0.0, 1.0);
return p + vec3(0.0, 0.0, 1.0);
}
if (faceId == 2u) {
if (cornerIndex == 0u) return p + vec3(1.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(1.0, 1.0, 0.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 1.0);
return p + vec3(1.0, 0.0, 1.0);
}
if (faceId == 3u) {
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(0.0, 0.0, 1.0);
if (cornerIndex == 2u) return p + vec3(0.0, 1.0, 1.0);
return p + vec3(0.0, 1.0, 0.0);
}
if (faceId == 4u) {
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 1.0);
if (cornerIndex == 1u) return p + vec3(1.0, 0.0, 1.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 1.0);
return p + vec3(0.0, 1.0, 1.0);
}
if (cornerIndex == 0u) return p + vec3(0.0, 0.0, 0.0);
if (cornerIndex == 1u) return p + vec3(0.0, 1.0, 0.0);
if (cornerIndex == 2u) return p + vec3(1.0, 1.0, 0.0);
return p + vec3(1.0, 0.0, 0.0);
}
void main() {
uint faceRecordIndex = uint(gl_VertexIndex) / 6u;
uint triangleVertex = uint(gl_VertexIndex) % 6u;
uint cornerIndex = TRI_TO_CORNER[triangleVertex];
uint packedFace = faces[faceRecordIndex];
uint voxelX = packedFace & 0x1Fu;
uint voxelY = (packedFace >> 5u) & 0x1Fu;
uint voxelZ = (packedFace >> 10u) & 0x1Fu;
uint faceId = (packedFace >> 15u) & 0x7u;
uint matId = (packedFace >> 18u) & 0xFFu;
vec3 localPos = buildFaceCornerPosition(uvec3(voxelX, voxelY, voxelZ), faceId, cornerIndex);
vec3 worldPos = localPos + push_constants.ModelOffset.xyz * 16.0;
outTextCoord = vec2(0.0);
outMaterialIdx = matId;
gl_Position = vec4(worldPos, 1.0);
}

View file

@ -183,7 +183,7 @@ 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.Init(RendererContext);
// VoxelWorldManager.GenerateChunks(new Vector3i(0,0,0), new Vector3i(16,0,16)); // VoxelWorldManager.GenerateChunks(new Vector3i(0,0,0), new Vector3i(16,0,16));
} }

View file

@ -660,13 +660,13 @@ public class GameCore implements GameLogic {
if(!PrimaryRuntime.IsServer && !RenderThread.Headless) { if(!PrimaryRuntime.IsServer && !RenderThread.Headless) {
CamPos.set(engineInstance.scene().GetCamera().GetPosition()); 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)); 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) { // 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.GenerateChunks(ChunkPos, new Vector3i(5, 5, 5));
VoxelWorldManager.UnloadFarChunks(ChunkPos, 10); // VoxelWorldManager.UnloadFarChunks(ChunkPos, 10);
} else { //} else {
VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(24,10,24)); VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(24,5,24));
VoxelWorldManager.UnloadFarChunks(ChunkPos, 48); VoxelWorldManager.UnloadFarChunks(ChunkPos, 24);
} //}
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

@ -93,10 +93,10 @@ public class CPUMonitor {
break; break;
} }
} }
return output.toString().isEmpty() ? "Unknown CPU" : output.toString(); return output.toString().isEmpty() || output.toString().contains("cannot") ? "Unknown CPU" : output.toString();
} }
} catch (Exception e) { } catch (Exception e) {
return "Error reading CPU name: " + e.getMessage(); return "Couldn't read CPU name";
} }
} }
} }

View file

@ -48,7 +48,7 @@ public class ComputeVoxelTerrain {
private static final int FLOATS_PER_VERTEX = 14; private static final int FLOATS_PER_VERTEX = 14;
private static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES; 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 DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 4 * Integer.BYTES;
private static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES; private static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES;
private final String DESCRIPTOR_ID_MESH; private final String DESCRIPTOR_ID_MESH;

View file

@ -1,6 +1,7 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
import org.joml.Matrix4f;
import org.joml.Vector3i; import org.joml.Vector3i;
public record RenderChunk(Vector3i position, int slot,long vertexOffsetBytes, long indexOffsetBytes,int maxIndexCount,long indirectCommandOffsetBytes) { public record RenderChunk(Vector3i position, int slot, long faceOffsetBytes,int maxFaceCount,long indirectCommandOffsetBytes, Matrix4f ModelMatrix) {
} }

View file

@ -17,31 +17,15 @@ public class SharedVoxelTerrainResources {
public static final int CHUNK_SIZE = 16; public static final int CHUNK_SIZE = 16;
public static final int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; 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 DRAW_INDIRECT_COMMAND_SIZE = 4 * Integer.BYTES;
public static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES; public static final int COUNTER_BUFFER_SIZE = Integer.BYTES;
public static final int TERRAIN_GENERATION_PUSH_CONSTANT_SIZE = Integer.BYTES * 8; 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_VOXEL_GENERATION = "VOXEL_SHARED_DESC_GENERATION";
private static final String DESC_ID_RESET = "VOXEL_SHARED_DESC_RESET"; 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 DESC_ID_MESH = "VOXEL_SHARED_DESC_MESH";
private static final String DESC_ID_FACE_GRAPHICS = "VOXEL_SHARED_DESC_FACE_GRAPHICS";
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 VoxelMeshPool meshPool;
@ -51,6 +35,15 @@ public class SharedVoxelTerrainResources {
private final DescriptorSetLayout voxelGenerationLayout; private final DescriptorSetLayout voxelGenerationLayout;
private final DescriptorSetLayout resetLayout; private final DescriptorSetLayout resetLayout;
private final DescriptorSetLayout meshGenerationLayout; private final DescriptorSetLayout meshGenerationLayout;
private final DescriptorSetLayout faceGraphicsLayout;
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 Pipeline voxelGenerationPipeline; private final Pipeline voxelGenerationPipeline;
private final Pipeline resetPipeline; private final Pipeline resetPipeline;
@ -60,26 +53,29 @@ public class SharedVoxelTerrainResources {
meshPool = new VoxelMeshPool(VkCtx, maxResidentChunks); meshPool = new VoxelMeshPool(VkCtx, maxResidentChunks);
voxelData = new VulkanBuffer(VkCtx, (long) VOXEL_COUNT * Integer.BYTES, voxelData = new VulkanBuffer(VkCtx, (long) VOXEL_COUNT * Integer.BYTES,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); 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, counters = new VulkanBuffer(VkCtx, COUNTER_BUFFER_SIZE, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 ); VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, 0);
voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ voxelGenerationLayout = 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, 0, 1, VK_SHADER_STAGE_COMPUTE_BIT)
}); });
resetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ 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, 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, 1, 1, VK_SHADER_STAGE_COMPUTE_BIT)
}); });
meshGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ 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, 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, 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, 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, 3, 1, VK_SHADER_STAGE_COMPUTE_BIT)
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,4,1,VK_SHADER_STAGE_COMPUTE_BIT) });
faceGraphicsLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_VERTEX_BIT )
}); });
createDescriptorSets(VkCtx); createDescriptorSets(VkCtx);
@ -124,10 +120,20 @@ public class SharedVoxelTerrainResources {
DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESC_ID_MESH, meshGenerationLayout); DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESC_ID_MESH, meshGenerationLayout);
meshSet.SetBuffer(device, voxelData, voxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); 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.facePool(), meshPool.facePool().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(), 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(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, counters, counters.GetRequestedSize(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
DescriptorSet faceGraphicsSet = allocator.AddDescriptorSet(device, DESC_ID_FACE_GRAPHICS, faceGraphicsLayout);
faceGraphicsSet.SetBuffer(device, meshPool.facePool(), meshPool.facePool().GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
}
public DescriptorSetLayout faceGraphicsLayout() {
return faceGraphicsLayout;
}
public String faceGraphicsDescriptorId() {
return DESC_ID_FACE_GRAPHICS;
} }
public VoxelMeshPool meshPool() { public VoxelMeshPool meshPool() {
@ -174,6 +180,7 @@ public class SharedVoxelTerrainResources {
resetLayout.CleanUp(VkCtx); resetLayout.CleanUp(VkCtx);
voxelGenerationLayout.CleanUp(VkCtx); voxelGenerationLayout.CleanUp(VkCtx);
meshGenerationLayout.CleanUp(VkCtx); meshGenerationLayout.CleanUp(VkCtx);
faceGraphicsLayout.CleanUp(VkCtx);
voxelData.cleanup(VkCtx); voxelData.cleanup(VkCtx);
counters.cleanup(VkCtx); counters.cleanup(VkCtx);

View file

@ -30,16 +30,15 @@ public class VoxelChunkGenerator {
ByteBuffer pushConstants = stack.malloc(SharedVoxelTerrainResources.TERRAIN_GENERATION_PUSH_CONSTANT_SIZE); ByteBuffer pushConstants = stack.malloc(SharedVoxelTerrainResources.TERRAIN_GENERATION_PUSH_CONSTANT_SIZE);
int vertexFloatOffset = (int) (chunk.vertexOffsetBytes() / Float.BYTES); int indirectCommandIndex = (int) (chunk.indirectCommandOffsetBytes() / VoxelMeshPool.DRAW_INDIRECT_COMMAND_SIZE);
int indexOffset = (int) (chunk.indexOffsetBytes() / Integer.BYTES); int faceOffset = (int) (chunk.faceOffsetBytes() / VoxelMeshPool.FACE_RECORD_SIZE_BYTES);
int indirectCommandIndex = (int) (chunk.indirectCommandOffsetBytes() / VoxelMeshPool.DRAW_INDEXED_INDIRECT_COMMAND_SIZE);
pushConstants.putInt(0, chunk.position().x); pushConstants.putInt(0, chunk.position().x);
pushConstants.putInt(4, chunk.position().y); pushConstants.putInt(4, chunk.position().y);
pushConstants.putInt(8, chunk.position().z); pushConstants.putInt(8, chunk.position().z);
pushConstants.putInt(12, chunk.slot()); pushConstants.putInt(12, chunk.slot());
pushConstants.putInt(16, vertexFloatOffset); pushConstants.putInt(16, faceOffset);
pushConstants.putInt(20, indexOffset); pushConstants.putInt(20, 0);
pushConstants.putInt(24, indirectCommandIndex); pushConstants.putInt(24, indirectCommandIndex);
pushConstants.putInt(28, 0); pushConstants.putInt(28, 0);
@ -101,19 +100,16 @@ public class VoxelChunkGenerator {
new long[]{ new long[]{
resources.voxelData().GetBuffer(), resources.voxelData().GetBuffer(),
resources.counters().GetBuffer(), resources.counters().GetBuffer(),
resources.meshPool().vertexPoolHandle(), resources.meshPool().facePoolHandle(),
resources.meshPool().indexPoolHandle(),
resources.meshPool().indirectPoolHandle() resources.meshPool().indirectPoolHandle()
}, },
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
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_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT, VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT, VK_ACCESS_2_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
VK_ACCESS_2_SHADER_READ_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 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT
); );
} }

View file

@ -2,6 +2,8 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerr
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector3i; import org.joml.Vector3i;
import java.util.ArrayDeque; import java.util.ArrayDeque;
@ -13,24 +15,16 @@ import static org.lwjgl.vulkan.VK13.*;
public class VoxelMeshPool{ public class VoxelMeshPool{
public static final int CHUNK_SIZE = 16; public static final int CHUNK_SIZE = 16;
public static final int FLOATS_PER_VERTEX = 14; public static final int MAX_VISIBLE_FACES_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * 6;
public static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES; public static final int FACE_RECORD_SIZE_BYTES = Integer.BYTES;
public static final int DRAW_INDIRECT_COMMAND_SIZE = 4 * Integer.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 int maxChunks;
private final long vertexSlotSizeBytes; private final long faceSlotSizeBytes;
private final long indexSlotSizeBytes;
private final long indirectSlotSizeBytes; private final long indirectSlotSizeBytes;
private final VulkanBuffer vertexPool; private final VulkanBuffer facePool;
private final VulkanBuffer indexPool;
private final VulkanBuffer indirectPool; private final VulkanBuffer indirectPool;
private final Queue<Integer> freeSlots = new ArrayDeque<>(); private final Queue<Integer> freeSlots = new ArrayDeque<>();
@ -38,19 +32,14 @@ public class VoxelMeshPool{
public VoxelMeshPool(VulkanContext VkCtx, int maxChunks) { public VoxelMeshPool(VulkanContext VkCtx, int maxChunks) {
this.maxChunks = maxChunks; this.maxChunks = maxChunks;
this.vertexSlotSizeBytes = (long) MAX_VERTICES_PER_CHUNK * VERTEX_SIZE_BYTES; this.faceSlotSizeBytes = (long) MAX_VISIBLE_FACES_PER_CHUNK * FACE_RECORD_SIZE_BYTES;
this.indexSlotSizeBytes = (long) MAX_INDICES_PER_CHUNK * INDEX_SIZE_BYTES; this.indirectSlotSizeBytes = DRAW_INDIRECT_COMMAND_SIZE;
this.indirectSlotSizeBytes = DRAW_INDEXED_INDIRECT_COMMAND_SIZE;
long vertexPoolSize = vertexSlotSizeBytes * maxChunks; long facePoolSize = faceSlotSizeBytes * maxChunks;
long indexPoolSize = indexSlotSizeBytes * maxChunks;
long indirectPoolSize = indirectSlotSizeBytes * maxChunks; long indirectPoolSize = indirectSlotSizeBytes * maxChunks;
facePool = new VulkanBuffer(VkCtx,facePoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
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); 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, 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); VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0);
@ -66,44 +55,44 @@ public class VoxelMeshPool{
if (slot == null) { if (slot == null) {
return null; return null;
} }
return new RenderChunk(
return new RenderChunk(new Vector3i(position),slot, vertexOffsetBytes(slot),indexOffsetBytes(slot),MAX_INDICES_PER_CHUNK,indirectCommandOffsetBytes(slot)); new Vector3i(position),
slot,
faceOffsetBytes(slot),
MAX_VISIBLE_FACES_PER_CHUNK,
indirectCommandOffsetBytes(slot),
new Matrix4f().identity().translate(
new Vector3f(
position.x * CHUNK_SIZE,
position.y * CHUNK_SIZE,
position.z * CHUNK_SIZE
)
)
);
} }
public void free(RenderChunk chunk) { public void free(RenderChunk chunk) {
freeSlots.add(chunk.slot()); freeSlots.add(chunk.slot());
} }
public long vertexOffsetBytes(int slot) { public long faceOffsetBytes(int slot) {
return vertexSlotSizeBytes * slot; return faceSlotSizeBytes * slot;
}
public long indexOffsetBytes(int slot) {
return indexSlotSizeBytes * slot;
} }
public long indirectCommandOffsetBytes(int slot) { public long indirectCommandOffsetBytes(int slot) {
return indirectSlotSizeBytes * slot; return indirectSlotSizeBytes * slot;
} }
public VulkanBuffer vertexPool() { public VulkanBuffer facePool() {
return vertexPool; return facePool;
}
public VulkanBuffer indexPool() {
return indexPool;
} }
public VulkanBuffer indirectPool() { public VulkanBuffer indirectPool() {
return indirectPool; return indirectPool;
} }
public long vertexPoolHandle() { public long facePoolHandle() {
return vertexPool.GetBuffer(); return facePool.GetBuffer();
}
public long indexPoolHandle() {
return indexPool.GetBuffer();
} }
public long indirectPoolHandle() { public long indirectPoolHandle() {
@ -119,8 +108,7 @@ public class VoxelMeshPool{
} }
public void cleanup(VulkanContext VkCtx) { public void cleanup(VulkanContext VkCtx) {
vertexPool.cleanup(VkCtx); facePool.cleanup(VkCtx);
indexPool.cleanup(VkCtx);
indirectPool.cleanup(VkCtx); indirectPool.cleanup(VkCtx);
} }
} }

View file

@ -98,7 +98,7 @@ public final class VoxelTerrainHeightSampler {
double minHeight = minHeightForChunkXZ(chunkX, chunkZ, chunkSize); double minHeight = minHeightForChunkXZ(chunkX, chunkZ, chunkSize);
double maxHeight = maxHeightForChunkXZ(chunkX, chunkZ, chunkSize); double maxHeight = maxHeightForChunkXZ(chunkX, chunkZ, chunkSize);
double safetyPadding = 32.0; double safetyPadding = 16.0;
if (chunkMinY > maxHeight + safetyPadding) { if (chunkMinY > maxHeight + safetyPadding) {
return VoxelChunkVisibility.EMPTY_AIR; return VoxelChunkVisibility.EMPTY_AIR;

View file

@ -4,22 +4,21 @@ 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.Pipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
import org.joml.Matrix4f; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import org.joml.Vector3i; import org.joml.Vector3i;
import org.lwjgl.system.MemoryStack; import org.joml.Vector4f;
import org.lwjgl.vulkan.VkCommandBuffer; import org.lwjgl.vulkan.VkCommandBuffer;
import org.tinylog.Logger; import org.tinylog.Logger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import static org.lwjgl.vulkan.VK13.*; import static org.lwjgl.vulkan.VK13.*;
public class VoxelWorldManager { public class VoxelWorldManager {
private static final int MAX_RESIDENT_CHUNKS = 512 * 24; private static final int MAX_RESIDENT_CHUNKS = 8192 * 2;
private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 32; private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 256;
private static final ConcurrentLinkedQueue<Vector3i> RequestedChunks = new ConcurrentLinkedQueue<>(); private static final ConcurrentLinkedQueue<Vector3i> RequestedChunks = new ConcurrentLinkedQueue<>();
private static final ConcurrentHashMap<Vector3i, RenderChunk> RenderChunks = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Vector3i, RenderChunk> RenderChunks = new ConcurrentHashMap<>();
@ -41,8 +40,8 @@ public class VoxelWorldManager {
Generator = new VoxelChunkGenerator(Resources); Generator = new VoxelChunkGenerator(Resources);
GraphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc( GraphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc(
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.MATRIX4X4_SIZE +
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.INT_SIZE VulkanUtils.INT_SIZE
); );
} }
@ -116,7 +115,7 @@ public class VoxelWorldManager {
// VoxelChunkGenerator.CHUNK_SIZE // VoxelChunkGenerator.CHUNK_SIZE
// ); // );
// //
// if (visibility != VoxelChunkVisibility.SURFACE) { // if (visibility == VoxelChunkVisibility.EMPTY_AIR) {
// CulledChunks.put(new Vector3i(position), visibility); // CulledChunks.put(new Vector3i(position), visibility);
// continue; // continue;
// } // }
@ -136,48 +135,42 @@ public class VoxelWorldManager {
} }
} }
public static void RecordRender(VkCommandBuffer CommandBuffer,Pipeline graphicsPipeline, MaterialsCache materialsCache) { public static SharedVoxelTerrainResources Resources() {
return Resources;
}
public static void RecordRender(VkCommandBuffer CommandBuffer, Pipeline graphicsPipeline, MaterialsCache materialsCache, boolean shadowPass) {
if (Resources == null) { if (Resources == null) {
return; return;
} }
int terrainMaterialIndex = materialsCache.GetPosition("VoxelTerrain"); int terrainMaterialIndex;
if (terrainMaterialIndex < 0) { if (materialsCache.GetPosition("VoxelTerrain") < 0) {
terrainMaterialIndex = 0; terrainMaterialIndex = 0;
} else {
terrainMaterialIndex = materialsCache.GetPosition("VoxelTerrain");
} }
try (MemoryStack stack = MemoryStack.stackPush()) { RenderChunks.forEach((position, chunk) -> {
Matrix4f identity = new Matrix4f().identity(); SetPushConstants(CommandBuffer, new Vector4f(position, 0), graphicsPipeline, terrainMaterialIndex, shadowPass);
vkCmdDrawIndirect(CommandBuffer, Resources.meshPool().indirectPoolHandle(), chunk.indirectCommandOffsetBytes(),
1, VoxelMeshPool.DRAW_INDIRECT_COMMAND_SIZE);
});
}
identity.get(0, GraphicsPushConstants); private static void SetPushConstants(VkCommandBuffer CmdHandle, Vector4f ModelMatrix, Pipeline VkPipeline, int MaterialIndex, boolean shadowPass){
GraphicsPushConstants.putInt( ModelMatrix.get(0,GraphicsPushConstants);
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE, GraphicsPushConstants.putInt(VulkanUtils.MATRIX4X4_SIZE, MaterialIndex);
terrainMaterialIndex vkCmdPushConstants(CmdHandle, VkPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0,
); GraphicsPushConstants.slice(0,VulkanUtils.MATRIX4X4_SIZE));
if(!shadowPass){
vkCmdPushConstants(CommandBuffer, graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_VERTEX_BIT, vkCmdPushConstants(CmdHandle, VkPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT, VulkanUtils.MATRIX4X4_SIZE,
0,GraphicsPushConstants.slice( GraphicsPushConstants.slice(VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.INT_SIZE));
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) { public static void UnloadFarChunks(Vector3i centerChunk, int unloadRadius) {
int maxDistSq = unloadRadius * unloadRadius; int maxDistSq = unloadRadius * unloadRadius;

View file

@ -82,6 +82,9 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
private static final String FRAGMENT_OPAQUE_SHADER_FILE_SPV = FRAGMENT_OPAQUE_SHADER_FILE_GLSL + ".spv"; private static final String FRAGMENT_OPAQUE_SHADER_FILE_SPV = FRAGMENT_OPAQUE_SHADER_FILE_GLSL + ".spv";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_vertex.glsl"; private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_vertex.glsl";
private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv";
private static final String PACKED_VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/packed_scene_vertex.glsl";
private static final String PACKED_VERTEX_SHADER_FILE_SPV = PACKED_VERTEX_SHADER_FILE_GLSL + ".spv";
private Pipeline VkVoxelPipeline;
private final VulkanBuffer[] BufferViewMatrices; private final VulkanBuffer[] BufferViewMatrices;
private Pipeline VkPipeline; private Pipeline VkPipeline;
private Pipeline VkPipelineOpaque; private Pipeline VkPipelineOpaque;
@ -166,6 +169,19 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
shaderModules = DeferredSceneRender.CreateShaderModules(vulkanContext,2); shaderModules = DeferredSceneRender.CreateShaderModules(vulkanContext,2);
VkPipelineTranslucent = CreatePipeline(vulkanContext, shaderModules, layouts, false, true,true,EngineConfig.getInstance().AlphaToCoverage(),2); VkPipelineTranslucent = CreatePipeline(vulkanContext, shaderModules, layouts, false, true,true,EngineConfig.getInstance().AlphaToCoverage(),2);
Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext)); Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext));
VoxelWorldManager.Init(vulkanContext);
DescriptorSetLayout[] voxelLayouts = new DescriptorSetLayout[]{
descriptorLayoutVertexUniform,
descriptorLayoutVertexUniform,
descriptorLayoutFragStorage,
descriptorLayoutTexture,
VoxelWorldManager.Resources().faceGraphicsLayout()
};
shaderModules = DeferredSceneRender.CreateShaderModules(vulkanContext, 3);
VkVoxelPipeline = CreateVoxelPipeline(vulkanContext, shaderModules, voxelLayouts);
Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext));
DescriptorSetLayout[] skyboxLayouts = new DescriptorSetLayout[]{ DescriptorSetLayout[] skyboxLayouts = new DescriptorSetLayout[]{
descriptorLayoutVertexUniform, descriptorLayoutVertexUniform,
@ -229,11 +245,11 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){ private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){
if(EngineConfig.getInstance().RecompileShaders()){ if(EngineConfig.getInstance().RecompileShaders()){
ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader); ShaderCompiler.CompileGLSLShaderOnChange(Translucent > 2 ? PACKED_VERTEX_SHADER_FILE_GLSL : VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader);
ShaderCompiler.CompileGLSLShaderOnChange( Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_GLSL : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_GLSL : FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_fragment_shader); ShaderCompiler.CompileGLSLShaderOnChange( Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_GLSL : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_GLSL : FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_fragment_shader);
} }
return new ShaderModule[]{ return new ShaderModule[]{
new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV,null), new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, Translucent > 2 ? PACKED_VERTEX_SHADER_FILE_SPV :VERTEX_SHADER_FILE_SPV,null),
new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_SPV : FRAGMENT_SHADER_FILE_SPV,null) new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_SPV : FRAGMENT_SHADER_FILE_SPV,null)
}; };
} }
@ -282,6 +298,41 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
} }
} }
private static Pipeline CreateVoxelPipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts) {
int[] colorFormats = new int[]{
MultiRenderTargetAttachments.POSITION_FORMAT,
MultiRenderTargetAttachments.ALBEDO_FORMAT,
MultiRenderTargetAttachments.NORMAL_FORMAT,
MultiRenderTargetAttachments.PBR_FORMAT,
MultiRenderTargetAttachments.EMISSIVE_FORMAT,
MultiRenderTargetAttachments.TRANSLUCECNY_FORMAT,
MultiRenderTargetAttachments.OPACITY_FORMAT,
MultiRenderTargetAttachments.VIEW_POS_FORMAT
};
try (MemoryStack stack = MemoryStack.stackPush()) {
VkPipelineVertexInputStateCreateInfo vertexInputState = VkPipelineVertexInputStateCreateInfo.calloc(stack)
.sType(VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO)
.pVertexBindingDescriptions(null)
.pVertexAttributeDescriptions(null);
var BuildInfo = new PipelineBuildInfo(ShaderModules, vertexInputState, colorFormats)
.SetDepthFormat(MultiRenderTargetAttachments.DEPTH_FORMAT)
.SetDepthWrite(true)
.SetPushConstantRanges(new PushConstantsRange[]{
new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT, 0, VulkanUtils.MATRIX4X4_SIZE),
new PushConstantsRange(VK_SHADER_STAGE_FRAGMENT_BIT, VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.INT_SIZE)
})
.SetDescriptorSetLayouts(DescriptorSetLayouts)
.SetBlendingMethod(0)
.BlendingIsUsed(false)
.SetDualPass(false)
.SetAlphaToCoverage(true);
return new DefaultPipeline(VkCtx, BuildInfo);
}
}
private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts, boolean DepthWrite, boolean DualRender, boolean Blending, boolean AlphaToCoverage, int BlendingMethod){ private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts, boolean DepthWrite, boolean DualRender, boolean Blending, boolean AlphaToCoverage, int BlendingMethod){
var vertexBufferStructure = new VertexBufferStructure(); var vertexBufferStructure = new VertexBufferStructure();
var BuildInfo = new PipelineBuildInfo(ShaderModules,vertexBufferStructure.getVertexInput(),new int[]{ var BuildInfo = new PipelineBuildInfo(ShaderModules,vertexBufferStructure.getVertexInput(),new int[]{
@ -356,18 +407,6 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
VulkanUtils.CopyMatrixToBuffer(vulkanContext, BufferViewMatrices[CurrentFrame],engineInstance.scene().GetCamera().GetViewMatrix(), 0); // here VulkanUtils.CopyMatrixToBuffer(vulkanContext, BufferViewMatrices[CurrentFrame],engineInstance.scene().GetCamera().GetViewMatrix(), 0); // here
/* LongBuffer vBuffers = memAllocLong(1).put(0, terrainMesh.GetVertexBuffer());
LongBuffer offsets = memAllocLong(1).put(0, 0L);
vkCmdBindVertexBuffers(commandBuffer.GetVulkanCommandBuffer(), 0, vBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer.GetVulkanCommandBuffer(), terrainMesh.GetIndexBuffer(), 0, VK_INDEX_TYPE_UINT32);
// Draw the procedural geometry primitives
vkCmdDrawIndexed(commandBuffer.GetVulkanCommandBuffer(), terrainMesh.GetIndexCount(), 1, 0, 0, 0);
memFree(vBuffers);
memFree(offsets);
*/
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipeline() : VkPipeline.GetVulkanPipeline()); vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipeline() : VkPipeline.GetVulkanPipeline());
DescriptorAllocator descriptorAllocator = vulkanContext.GetDescriptorAllocator(); DescriptorAllocator descriptorAllocator = vulkanContext.GetDescriptorAllocator();
@ -377,10 +416,20 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
.put(2,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_MAT).GetVkDescriptorSet()) .put(2,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_MAT).GetVkDescriptorSet())
.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); vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkVoxelPipeline.GetVulkanPipeline());
LongBuffer voxelDescriptorSets = MemStack.mallocLong(5)
.put(0, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_PRJ).GetVkDescriptorSet())
.put(1, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_VIEW, CurrentFrame).GetVkDescriptorSet())
.put(2, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_MAT).GetVkDescriptorSet())
.put(3, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet())
.put(4, descriptorAllocator.GetDescriptorSet(VoxelWorldManager.Resources().faceGraphicsDescriptorId()).GetVkDescriptorSet());
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkVoxelPipeline.GetVulkanPipelineLayout(), 0, voxelDescriptorSets, null);
VoxelWorldManager.RecordRender(CommandHandle, VkVoxelPipeline, materialsCache, false);
Matrix4f skyboxViewMatrix = new Matrix4f().identity(); Matrix4f skyboxViewMatrix = new Matrix4f().identity();
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix()); skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
@ -542,6 +591,7 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
public void cleanup(VulkanContext VkCtx){ public void cleanup(VulkanContext VkCtx){
VkPipeline.CleanUp(VkCtx); VkPipeline.CleanUp(VkCtx);
// VkSkyboxPipeline.CleanUp(VkCtx); // VkSkyboxPipeline.CleanUp(VkCtx);
VkVoxelPipeline.CleanUp(VkCtx);
VkPipelineOpaque.CleanUp(VkCtx); VkPipelineOpaque.CleanUp(VkCtx);
VkPipelineTranslucent.CleanUp(VkCtx); VkPipelineTranslucent.CleanUp(VkCtx);
Arrays.asList(BufferViewMatrices).forEach(b -> b.cleanup(VkCtx)); Arrays.asList(BufferViewMatrices).forEach(b -> b.cleanup(VkCtx));

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.SharedVoxelTerrainResources;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager; 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;
@ -65,6 +66,9 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
public static String SkyBoxID = "SKYBOX_TEXTURE"; public static String SkyBoxID = "SKYBOX_TEXTURE";
private static final int PUSH_CONSTANTS_SIZE = VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.INT_SIZE; private static final int PUSH_CONSTANTS_SIZE = VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.INT_SIZE;
private final VulkanBuffer BufferProjectionMatrix; private final VulkanBuffer BufferProjectionMatrix;
private static final String PACKED_VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/packed_scene_vertex.glsl";
private static final String PACKED_VERTEX_SHADER_FILE_SPV = PACKED_VERTEX_SHADER_FILE_GLSL + ".spv";
private Pipeline VkVoxelPipeline;
private final DescriptorSetLayout descriptorLayoutFragStorage; private final DescriptorSetLayout descriptorLayoutFragStorage;
private final DescriptorSetLayout descriptorLayoutTexture; private final DescriptorSetLayout descriptorLayoutTexture;
private final DescriptorSetLayout descriptorLayoutVertexUniform; private final DescriptorSetLayout descriptorLayoutVertexUniform;
@ -169,6 +173,19 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
shaderModules = CreateShaderModules(vulkanContext,2); shaderModules = CreateShaderModules(vulkanContext,2);
VkPipelineTranslucent = CreatePipeline(vulkanContext, shaderModules, layouts, false, true,true,EngineConfig.getInstance().AlphaToCoverage(),2); VkPipelineTranslucent = CreatePipeline(vulkanContext, shaderModules, layouts, false, true,true,EngineConfig.getInstance().AlphaToCoverage(),2);
Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext)); Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext));
VoxelWorldManager.Init(vulkanContext);
DescriptorSetLayout[] voxelLayouts = new DescriptorSetLayout[]{
descriptorLayoutVertexUniform,
descriptorLayoutVertexUniform,
descriptorLayoutFragStorage,
descriptorLayoutTexture,
VoxelWorldManager.Resources().faceGraphicsLayout()
};
shaderModules = CreateShaderModules(vulkanContext, 3);
VkVoxelPipeline = CreateVoxelPipeline(vulkanContext, shaderModules, voxelLayouts);
Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext));
DescriptorSetLayout[] skyboxLayouts = new DescriptorSetLayout[]{ DescriptorSetLayout[] skyboxLayouts = new DescriptorSetLayout[]{
descriptorLayoutVertexUniform, descriptorLayoutVertexUniform,
@ -198,6 +215,40 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
return new Attachment(VkCtx, SwapChainExtent.width(), SwapChainExtent.height(), COLOUR_FORMAT,VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); return new Attachment(VkCtx, SwapChainExtent.width(), SwapChainExtent.height(), COLOUR_FORMAT,VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
} }
private static Pipeline CreateVoxelPipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts) {
int[] colorFormats = new int[]{
MultiRenderTargetAttachments.POSITION_FORMAT,
MultiRenderTargetAttachments.ALBEDO_FORMAT,
MultiRenderTargetAttachments.NORMAL_FORMAT,
MultiRenderTargetAttachments.PBR_FORMAT,
MultiRenderTargetAttachments.EMISSIVE_FORMAT,
MultiRenderTargetAttachments.TRANSLUCECNY_FORMAT,
MultiRenderTargetAttachments.OPACITY_FORMAT,
MultiRenderTargetAttachments.VIEW_POS_FORMAT
};
try (MemoryStack stack = MemoryStack.stackPush()) {
VkPipelineVertexInputStateCreateInfo vertexInputState = VkPipelineVertexInputStateCreateInfo.calloc(stack)
.sType(VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO)
.pVertexBindingDescriptions(null)
.pVertexAttributeDescriptions(null);
var BuildInfo = new PipelineBuildInfo(ShaderModules, vertexInputState, colorFormats)
.SetDepthFormat(MultiRenderTargetAttachments.DEPTH_FORMAT)
.SetDepthWrite(true)
.SetPushConstantRanges(new PushConstantsRange[]{
new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT, 0, VulkanUtils.MATRIX4X4_SIZE),
new PushConstantsRange(VK_SHADER_STAGE_FRAGMENT_BIT, VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.INT_SIZE)
})
.SetDescriptorSetLayouts(DescriptorSetLayouts)
.SetBlendingMethod(0)
.BlendingIsUsed(false)
.SetDualPass(false)
.SetAlphaToCoverage(true);
return new DefaultPipeline(VkCtx, BuildInfo);
}
}
private static VkRenderingAttachmentInfo.Buffer CreateColourAttachmentInfo(Attachment attachment, VkClearValue ClearValue){ private static VkRenderingAttachmentInfo.Buffer CreateColourAttachmentInfo(Attachment attachment, VkClearValue ClearValue){
return VkRenderingAttachmentInfo.calloc(1) return VkRenderingAttachmentInfo.calloc(1)
@ -241,11 +292,11 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){ private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){
if(EngineConfig.getInstance().RecompileShaders()){ if(EngineConfig.getInstance().RecompileShaders()){
ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader); ShaderCompiler.CompileGLSLShaderOnChange(Translucent > 2 ? PACKED_VERTEX_SHADER_FILE_GLSL :VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader);
ShaderCompiler.CompileGLSLShaderOnChange( Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_GLSL : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_GLSL : FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_fragment_shader); ShaderCompiler.CompileGLSLShaderOnChange( Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_GLSL : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_GLSL : FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_fragment_shader);
} }
return new ShaderModule[]{ return new ShaderModule[]{
new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV,null), new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, Translucent > 2 ? PACKED_VERTEX_SHADER_FILE_SPV : VERTEX_SHADER_FILE_SPV,null),
new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_SPV : FRAGMENT_SHADER_FILE_SPV,null) new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_SPV : FRAGMENT_SHADER_FILE_SPV,null)
}; };
@ -364,7 +415,19 @@ 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); vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkVoxelPipeline.GetVulkanPipeline());
LongBuffer voxelDescriptorSets = MemStack.mallocLong(5)
.put(0, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_PRJ).GetVkDescriptorSet())
.put(1, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_VIEW, CurrentFrame).GetVkDescriptorSet())
.put(2, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_MAT).GetVkDescriptorSet())
.put(3, descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet())
.put(4, descriptorAllocator.GetDescriptorSet(VoxelWorldManager.Resources().faceGraphicsDescriptorId()).GetVkDescriptorSet());
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkVoxelPipeline.GetVulkanPipelineLayout(), 0, voxelDescriptorSets, null);
VoxelWorldManager.RecordRender(CommandHandle, VkVoxelPipeline, materialsCache, false);
Matrix4f skyboxViewMatrix = new Matrix4f().identity(); Matrix4f skyboxViewMatrix = new Matrix4f().identity();
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix()); skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
@ -530,6 +593,7 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
VkPipeline.CleanUp(VkCtx); VkPipeline.CleanUp(VkCtx);
VkPipelineTranslucent.CleanUp(VkCtx); VkPipelineTranslucent.CleanUp(VkCtx);
VkPipelineOpaque.CleanUp(VkCtx); VkPipelineOpaque.CleanUp(VkCtx);
VkVoxelPipeline.CleanUp(VkCtx);
Arrays.asList(BufferViewMatrices).forEach(buffer -> buffer.cleanup(VkCtx)); Arrays.asList(BufferViewMatrices).forEach(buffer -> buffer.cleanup(VkCtx));
RenderInfo.free(); RenderInfo.free();
AttachmentInfoColour.free(); AttachmentInfoColour.free();

View file

@ -46,7 +46,7 @@ public class AmbientOcclusionRenderer {
VulkanUtils.VEC4_SIZE + // screenSize.xy, radius, bias VulkanUtils.VEC4_SIZE + // screenSize.xy, radius, bias
VulkanUtils.VEC4_SIZE; // kernelSize + padding VulkanUtils.VEC4_SIZE; // kernelSize + padding
private static final int SSAO_KERNEL_SIZE = 64; private static final int SSAO_KERNEL_SIZE = 64;
private static final float SSAO_RADIUS = 0.75f; private static final float SSAO_RADIUS = 0.35f;
private static final float SSAO_BIAS = 0.025f; private static final float SSAO_BIAS = 0.025f;
private static final long SSAO_KERNEL_BUFFER_SIZE = SSAO_KERNEL_SIZE * 4L * VulkanUtils.FLOAT_SIZE; private static final long SSAO_KERNEL_BUFFER_SIZE = SSAO_KERNEL_SIZE * 4L * VulkanUtils.FLOAT_SIZE;

View file

@ -14,6 +14,7 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.I
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PipelineBuildInfo; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PipelineBuildInfo;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.DeferredRendering.MultiRenderTargetAttachments;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VertexBufferStructure; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VertexBufferStructure;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.*; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.*;
@ -80,7 +81,8 @@ public class ShadowRenderer {
private static final String SHADOW_GEOMETRY_SHADER_FILE_SPV = SHADOW_GEOMETRY_SHADER_FILE_GLSL + ".spv"; private static final String SHADOW_GEOMETRY_SHADER_FILE_SPV = SHADOW_GEOMETRY_SHADER_FILE_GLSL + ".spv";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/shadow_vertex.glsl"; private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/shadow_vertex.glsl";
private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv";
private static final String PACKED_VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/shadow_vertex_packed.glsl";
private static final String PACKED_VERTEX_SHADER_FILE_SPV = PACKED_VERTEX_SHADER_FILE_GLSL + ".spv";
private final CascadeShadows[] cascadeShadows; private final CascadeShadows[] cascadeShadows;
private final VkClearValue ClearValueColour; private final VkClearValue ClearValueColour;
private final VkClearValue ClearValueDepth; private final VkClearValue ClearValueDepth;
@ -90,6 +92,7 @@ public class ShadowRenderer {
private VkRenderingAttachmentInfo depthAttachmentInfo; private VkRenderingAttachmentInfo depthAttachmentInfo;
private final DescriptorSetLayout descLayoutFrgStorage; private final DescriptorSetLayout descLayoutFrgStorage;
private Pipeline pipeline; private Pipeline pipeline;
private Pipeline pipelinePacked;
private final VulkanBuffer[] prjBuffers; private final VulkanBuffer[] prjBuffers;
private final ByteBuffer pushConstBuff; private final ByteBuffer pushConstBuff;
private VkRenderingInfo renderingInfo; private VkRenderingInfo renderingInfo;
@ -180,6 +183,14 @@ public class ShadowRenderer {
pipeline = createPipeline(VulkanContext, shaderModules, new DescriptorSetLayout[]{uniformGeomDescriptorSetLayout, textDescriptorSetLayout, pipeline = createPipeline(VulkanContext, shaderModules, new DescriptorSetLayout[]{uniformGeomDescriptorSetLayout, textDescriptorSetLayout,
descLayoutFrgStorage}); descLayoutFrgStorage});
Arrays.asList(shaderModules).forEach(s -> s.CleanUp(VulkanContext)); Arrays.asList(shaderModules).forEach(s -> s.CleanUp(VulkanContext));
shaderModules = createPackedVertexShaderModules(VulkanContext);
pipelinePacked = CreateVoxelPipeline(VulkanContext, shaderModules, new DescriptorSetLayout[]{
uniformGeomDescriptorSetLayout,
textDescriptorSetLayout,
descLayoutFrgStorage,
VoxelWorldManager.Resources().faceGraphicsLayout()
});
Arrays.asList(shaderModules).forEach(s -> s.CleanUp(VulkanContext));
cascadeShadows = new CascadeShadows[VulkanUtils.MAX_IN_FLIGHT]; cascadeShadows = new CascadeShadows[VulkanUtils.MAX_IN_FLIGHT];
for (int i = 0; i < VulkanUtils.MAX_IN_FLIGHT; i++) { for (int i = 0; i < VulkanUtils.MAX_IN_FLIGHT; i++) {
@ -238,6 +249,32 @@ public class ShadowRenderer {
return pipeline; return pipeline;
} }
private static Pipeline CreateVoxelPipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts) {
int[] colorFormats = new int[]{
ATTACHMENT_FORMATT
};
try (MemoryStack stack = MemoryStack.stackPush()) {
VkPipelineVertexInputStateCreateInfo vertexInputState = VkPipelineVertexInputStateCreateInfo.calloc(stack)
.sType(VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO)
.pVertexBindingDescriptions(null)
.pVertexAttributeDescriptions(null);
var BuildInfo = new PipelineBuildInfo(ShaderModules, vertexInputState, colorFormats)
.SetDepthFormat(DEPTH_FORMAT)
.SetPushConstantRanges(
new PushConstantsRange[]{
new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT, 0, PUSH_CONSTANTS_SIZE)
})
.SetDescriptorSetLayouts(DescriptorSetLayouts)
.SetDepthClamp(VkCtx.GetDevice().getDepthClamp())
.CullMode(VK_CULL_MODE_FRONT_BIT)
.DepthBuffer(VK_COMPARE_OP_LESS_OR_EQUAL);
return new DefaultPipeline(VkCtx, BuildInfo);
}
}
private static VkRenderingInfo createRenderInfo(VkRenderingAttachmentInfo.Buffer colorAttachmentInfo, private static VkRenderingInfo createRenderInfo(VkRenderingAttachmentInfo.Buffer colorAttachmentInfo,
VkRenderingAttachmentInfo depthAttachments) { VkRenderingAttachmentInfo depthAttachments) {
var result = VkRenderingInfo.calloc().sType$Default(); var result = VkRenderingInfo.calloc().sType$Default();
@ -254,7 +291,18 @@ public class ShadowRenderer {
} }
return result; return result;
} }
private static ShaderModule[] createPackedVertexShaderModules(VulkanContext VulkanContext) {
if (EngineConfig.getInstance().RecompileShaders()) {
ShaderCompiler.CompileGLSLShaderOnChange(PACKED_VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader);
ShaderCompiler.CompileGLSLShaderOnChange(SHADOW_GEOMETRY_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_geometry_shader);
ShaderCompiler.CompileGLSLShaderOnChange(FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_fragment_shader);
}
return new ShaderModule[]{
new ShaderModule(VulkanContext, VK_SHADER_STAGE_VERTEX_BIT, PACKED_VERTEX_SHADER_FILE_SPV, null),
new ShaderModule(VulkanContext, VK_SHADER_STAGE_GEOMETRY_BIT, SHADOW_GEOMETRY_SHADER_FILE_SPV, null),
new ShaderModule(VulkanContext, VK_SHADER_STAGE_FRAGMENT_BIT, FRAGMENT_SHADER_FILE_SPV, null),
};
}
private static ShaderModule[] createShaderModules(VulkanContext VulkanContext) { private static ShaderModule[] createShaderModules(VulkanContext VulkanContext) {
if (EngineConfig.getInstance().RecompileShaders()) { if (EngineConfig.getInstance().RecompileShaders()) {
ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader); ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader);
@ -271,6 +319,7 @@ public class ShadowRenderer {
public void cleanup(VulkanContext VulkanContext) { public void cleanup(VulkanContext VulkanContext) {
AllowShadowRendering(false); AllowShadowRendering(false);
pipeline.CleanUp(VulkanContext); pipeline.CleanUp(VulkanContext);
pipelinePacked.CleanUp(VulkanContext);
uniformGeomDescriptorSetLayout.CleanUp(VulkanContext); uniformGeomDescriptorSetLayout.CleanUp(VulkanContext);
descLayoutFrgStorage.CleanUp(VulkanContext); descLayoutFrgStorage.CleanUp(VulkanContext);
textDescriptorSetLayout.CleanUp(VulkanContext); textDescriptorSetLayout.CleanUp(VulkanContext);
@ -394,7 +443,15 @@ public class ShadowRenderer {
vkCmdDrawIndexed(cmdHandle, vulkanMesh.IndicesCount(), 1, 0, 0, 0); vkCmdDrawIndexed(cmdHandle, vulkanMesh.IndicesCount(), 1, 0, 0, 0);
} }
} }
VoxelWorldManager.RecordRender(cmdHandle,pipeline,materialsCache);
descriptorSets = stack.mallocLong(4)
.put(0, descAllocator.GetDescriptorSet(DESCRIPTOR_ID_PRJ, currentFrame).GetVkDescriptorSet())
.put(1, descAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet())
.put(2, descAllocator.GetDescriptorSet(DESCRIPTOR_ID_MAT).GetVkDescriptorSet())
.put(3, descAllocator.GetDescriptorSet(VoxelWorldManager.Resources().faceGraphicsDescriptorId()).GetVkDescriptorSet());
vkCmdBindPipeline(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinePacked.GetVulkanPipeline());
vkCmdBindDescriptorSets(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinePacked.GetVulkanPipelineLayout(),0,descriptorSets,null);
VoxelWorldManager.RecordRender(cmdHandle,pipelinePacked,materialsCache,true);
vkCmdEndRendering(cmdHandle); vkCmdEndRendering(cmdHandle);
} }
} }