diff --git a/resources/EngineResources/Texture/blueleaf_set.png b/resources/EngineResources/Texture/blueleaf_set.png new file mode 100644 index 0000000..3c22f59 Binary files /dev/null and b/resources/EngineResources/Texture/blueleaf_set.png differ diff --git a/resources/EngineResources/Texture/blueleaf_set_2.png b/resources/EngineResources/Texture/blueleaf_set_2.png new file mode 100644 index 0000000..7d4e30e Binary files /dev/null and b/resources/EngineResources/Texture/blueleaf_set_2.png differ diff --git a/resources/EngineResources/Texture/blueleaf_set_2_translucent.png b/resources/EngineResources/Texture/blueleaf_set_2_translucent.png new file mode 100644 index 0000000..c1b5625 Binary files /dev/null and b/resources/EngineResources/Texture/blueleaf_set_2_translucent.png differ diff --git a/resources/EngineResources/Texture/blueleaf_set_translucent.png b/resources/EngineResources/Texture/blueleaf_set_translucent.png new file mode 100644 index 0000000..bf87761 Binary files /dev/null and b/resources/EngineResources/Texture/blueleaf_set_translucent.png differ diff --git a/resources/EngineResources/Texture/test_cube_translucency.png b/resources/EngineResources/Texture/test_cube_translucency.png new file mode 100644 index 0000000..8c44307 Binary files /dev/null and b/resources/EngineResources/Texture/test_cube_translucency.png differ diff --git a/resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl b/resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl index 0ed1040..844a691 100644 --- a/resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl +++ b/resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl @@ -32,11 +32,26 @@ layout(std430, binding = 3) buffer Counters { uint faceCount; } counters; +struct Voxel { + uint MaterialIndex; + uint BlockType; + uvec2[2] UpIndex; + uvec2[2] DownIndex; + uvec2[2] NorthIndex; + uvec2[2] SouthIndex; + uvec2[2] EastIndex; + uvec2[2] WestIndex; +}; + +layout(std430, set = 1, binding = 0) readonly buffer VoxelUniform { + Voxel materials[]; +} voxelReg; + layout(push_constant) uniform ChunkInfo { ivec3 chunkPos; int slot; uint faceOffset; - uint unused0; + uint voxelTypeCount; uint indirectCommandIndex; uint padding0; }; @@ -44,7 +59,10 @@ layout(push_constant) uniform ChunkInfo { uint flatten(ivec3 pos) { return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z); } - +bool isSeeThrough(Voxel voxel, uint type) { + if (type == 0u || voxel.BlockType == 3u || type > voxelTypeCount) return true; + return voxelReg.materials[type - 1u].BlockType >= 1u; +} uint getVoxel(ivec3 pos) { if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0u; if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0u; @@ -58,7 +76,16 @@ uint hash21(uvec2 p) { p.y += p.x * 1664525u; return p.x ^ (p.x >> 16); } +uint pcg_hash(uint seed) { + uint state = seed * 747796405u + 289133645u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} +uint randomRangeUint(uint seed, uint minVal, uint maxVal) { + uint range = maxVal - minVal + 1u; + return minVal + (pcg_hash(seed) % range); +} uint random_1_to_3(vec2 uv, uint customSeed) { uvec2 p = uvec2(floatBitsToUint(uv.x), floatBitsToUint(uv.y)); p.x ^= customSeed; @@ -66,6 +93,31 @@ uint random_1_to_3(vec2 uv, uint customSeed) { return (randInt % 3u) + 1u; } +uint packFace(uvec3 voxelPos, uint faceIndex, Voxel voxel) { + uint randomSeed = uint(voxelPos.x) * 73856093u ^ uint(voxelPos.z) * 19349663u; + uvec2 UpIndex = uvec2(randomRangeUint(randomSeed,voxel.UpIndex[0].x,voxel.UpIndex[1].x),randomRangeUint(randomSeed,voxel.UpIndex[0].y,voxel.UpIndex[1].y)); + uvec2 DownIndex = uvec2(randomRangeUint(randomSeed,voxel.DownIndex[0].x,voxel.DownIndex[1].x),randomRangeUint(randomSeed,voxel.DownIndex[0].y,voxel.DownIndex[1].y)); + uvec2 NorthIndex = uvec2(randomRangeUint(randomSeed,voxel.NorthIndex[0].x,voxel.NorthIndex[1].x),randomRangeUint(randomSeed,voxel.NorthIndex[0].y,voxel.NorthIndex[1].y)); + uvec2 SouthIndex = uvec2(randomRangeUint(randomSeed,voxel.SouthIndex[0].x,voxel.SouthIndex[1].x),randomRangeUint(randomSeed,voxel.SouthIndex[0].y,voxel.SouthIndex[1].y)); + uvec2 EastIndex = uvec2(randomRangeUint(randomSeed,voxel.EastIndex[0].x,voxel.EastIndex[1].x),randomRangeUint(randomSeed,voxel.EastIndex[0].y,voxel.EastIndex[1].y)); + uvec2 WestIndex = uvec2(randomRangeUint(randomSeed,voxel.WestIndex[0].x,voxel.WestIndex[1].x),randomRangeUint(randomSeed,voxel.WestIndex[0].y,voxel.WestIndex[1].y)); + + uvec2 textureIndices[8] = uvec2[8](UpIndex, DownIndex, NorthIndex, + SouthIndex, EastIndex, WestIndex, NorthIndex,SouthIndex); + uvec2 tex = textureIndices[faceIndex]; + uint textureIndexX = tex.x; + uint textureIndexY = tex.y; + uint materialId = voxel.MaterialIndex; + + return (voxelPos.x & 0xFu) | + ((voxelPos.y & 0xFu) << 4u) | + ((voxelPos.z & 0xFu) << 8u) | + ((faceIndex & 0x7u) << 12u) | + ((materialId & 0x7FFu) << 15u) | + ((textureIndexX & 0x7u) << 26u) | + ((textureIndexY & 0x7u) << 29u); +} + uint packFace(uvec3 voxelPos, uint faceIndex, uint materialId) { uint randomFaceValue = random_1_to_3(vec2(voxelPos.x, voxelPos.z),faceOffset); uint textureIndexX = 0u; @@ -107,23 +159,28 @@ uint packFace(uvec3 voxelPos, uint faceIndex, uint materialId) { textureIndexY = 0u; } - return (voxelPos.x & 0x1Fu) | - ((voxelPos.y & 0x1Fu) << 5u) | - ((voxelPos.z & 0x1Fu) << 10u) | - ((faceIndex & 0x7u) << 15u) | - ((materialId & 0xFFu) << 18u) | + return (voxelPos.x & 0xFu) | + ((voxelPos.y & 0xFu) << 4u) | + ((voxelPos.z & 0xFu) << 8u) | + ((faceIndex & 0x7u) << 12u) | + ((materialId & 0x7FFu) << 15u) | ((textureIndexX & 0x7u) << 26u) | ((textureIndexY & 0x7u) << 29u); } void emitFace(ivec3 voxelPos, uint faceIndex, uint voxelType) { + if (voxelType == 0u || voxelType > voxelTypeCount) { + return; + } + uint localFace = atomicAdd(counters.faceCount, 1u); if (localFace >= MAX_VISIBLE_FACES_PER_CHUNK) { return; } - faces[faceOffset + localFace] = packFace(uvec3(voxelPos), faceIndex, voxelType); + Voxel voxel = voxelReg.materials[voxelType - 1u]; + faces[faceOffset + localFace] = packFace(uvec3(voxelPos), faceIndex, voxel); atomicAdd(drawCmds[indirectCommandIndex].vertexCount, VERTICES_PER_FACE); } @@ -136,21 +193,20 @@ void main() { } uint current = getVoxel(pos); - - if (current == 0u) { + if (current == 0u || current > voxelTypeCount) { return; } - - if (current == 4u) { + Voxel voxel = voxelReg.materials[current - 1u]; + if (voxel.BlockType == 1u) { emitFace(pos, 6u, current); emitFace(pos, 7u, current); return; } - if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u || getVoxel(pos + ivec3( 0, 1, 0)) == 4u) emitFace(pos, 0u, current); - if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u || getVoxel(pos + ivec3( 0, -1, 0)) == 4u) emitFace(pos, 1u, current); - if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u || getVoxel(pos + ivec3( 1, 0, 0)) == 4u) emitFace(pos, 2u, current); - if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u || getVoxel(pos + ivec3( -1, 0, 0)) == 4u) emitFace(pos, 3u, current); - if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u|| getVoxel(pos + ivec3( 0, 0, 1)) == 4u) emitFace(pos, 4u, current); - if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u || getVoxel(pos + ivec3( 0, 0, -1)) == 4u) emitFace(pos, 5u, current); + if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, 1, 0)))) emitFace(pos, 0u, current); + if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, -1, 0)))) emitFace(pos, 1u, current); + if (isSeeThrough(voxel,getVoxel(pos + ivec3( 1, 0, 0)))) emitFace(pos, 2u, current); + if (isSeeThrough(voxel,getVoxel(pos + ivec3(-1, 0, 0)))) emitFace(pos, 3u, current); + if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, 0, 1)))) emitFace(pos, 4u, current); + if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, 0, -1)))) emitFace(pos, 5u, current); } \ No newline at end of file diff --git a/resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl b/resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl index 44ad8f3..e091158 100644 --- a/resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl +++ b/resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl @@ -8,6 +8,19 @@ const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE; layout(std430, binding = 0) buffer VoxelData { uint voxels[]; }; +struct Biome { + uint surfaceBlock; + uint dirtBlock; + uint stoneBlock; + uint grassFoliage; + uint[4] flowers; + uint[4] tallBlocks; + uint[4] otherFoliage; +}; + +layout(std430, set = 1, binding = 0) readonly buffer BiomeUniform { + Biome biomes[]; +} BiomeReg; layout(push_constant) uniform ChunkInfo { ivec3 chunkPos; @@ -15,15 +28,8 @@ layout(push_constant) uniform ChunkInfo { uint faceOffset; uint unused0; uint indirectCommandIndex; - uint padding0; + uint biomeCount; }; -vec3 random3(vec3 st) { - return fract(sin(vec3( - dot(st, vec3(127.1, 311.7, 74.7)), - dot(st, vec3(269.5, 183.3, 246.1)), - dot(st, vec3(113.5, 271.9, 124.6)) - )) * 43758.5453123); -} float random3to1(vec3 st) { return fract(sin(dot(st, vec3(127.1, 311.7, 74.7))) * 43758.5453123); @@ -88,6 +94,29 @@ float valueNoise(vec2 st) { (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } + +uint pcg_hash(uint seed) { + uint state = seed * 747796405u + 289133645u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +uint randomRangeUint(uint seed, uint minVal, uint maxVal) { + uint range = maxVal - minVal + 1u; + return minVal + (pcg_hash(seed) % range); +} + +uint GetBiome(vec3 worldPos, uint MaxBiomes) { + if (MaxBiomes == 0u) return 0u; + 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 = clamp(cubicNoise(X), 0.0, 0.9999); + uint Biome = uint(floor(n * float(MaxBiomes))); + return min(Biome, MaxBiomes - 1u); +} bool isCave(vec3 worldPos) { vec3 X = vec3(worldPos); X = mat3( @@ -101,33 +130,41 @@ bool isCave(vec3 worldPos) { void main() { ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz); ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos; - + + uint biome = GetBiome(vec3(worldPos.z, worldPos.y, worldPos.x) * 0.05, biomeCount); + Biome currentBiome = BiomeReg.biomes[biome]; + float YZone = floor(worldPos.y/150.0)*150.0; - float SurfaceHeight = valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.005) * 100 + + float SurfaceHeight = valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.005) * 100 + + valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.01) * 10 + valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.1) * 5 + valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2)) * 0.5 + YZone; + uint RandomBlockVal = randomRangeUint(uint(worldPos.x) * 73856093u ^ uint(worldPos.z) * 19349663u,0u ,3u); float IslandUnderneathHeight = valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.005) * 100 + + valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.1) * 20 + valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.1) * 5 + valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2)) * 0.5 - 15 + YZone; - float grassNoise = valueNoise(vec2(worldPos.z + YZone * 2, worldPos.x + YZone * 2)); + float grassNoise = valueNoise(vec2(worldPos.z * 0.5 - YZone * 2, worldPos.x * 0.5 - YZone * 2)); uint voxelType = 0u; if (float(worldPos.y) <= SurfaceHeight && float(worldPos.y) >= IslandUnderneathHeight) { float depthBelowSurface = SurfaceHeight - float(worldPos.y); if (depthBelowSurface < 0.5) { - if(grassNoise < 0.65) voxelType = 4u; // Grass foliage + if(grassNoise < 0.65) voxelType = currentBiome.grassFoliage; // Grass foliage + else if (grassNoise < 0.75) voxelType = currentBiome.flowers[RandomBlockVal]; + else if (grassNoise < 0.85) voxelType = currentBiome.otherFoliage[RandomBlockVal]; else voxelType = 0u; }else if (depthBelowSurface < 2.5) { - voxelType = 1u; // Grass + voxelType = currentBiome.surfaceBlock; // Grass } else if (depthBelowSurface < 6.0) { - voxelType = 2u; // Dirt(also stone rn) + voxelType = currentBiome.dirtBlock; // Dirt(also stone rn) } else { - voxelType = 3u; // Stone + voxelType = currentBiome.stoneBlock; // Stone } } else{ @@ -145,14 +182,16 @@ void main() { float depthBelowSurface = height2 - float(worldPos.y); if (depthBelowSurface < 0.5) { - if (grassNoise < 0.65) voxelType = 4u; // Grass foliage + if (grassNoise < 0.65) voxelType = currentBiome.grassFoliage; // Grass foliage + else if (grassNoise < 0.75) voxelType = currentBiome.flowers[RandomBlockVal]; + else if (grassNoise < 0.85) voxelType = currentBiome.otherFoliage[RandomBlockVal]; else voxelType = 0u; } else if (depthBelowSurface < 1.5) { - voxelType = 1u; // Grass + voxelType = currentBiome.surfaceBlock; // Grass } else if (depthBelowSurface < 6.0) { - voxelType = 2u; // Dirt(also stone rn) + voxelType = currentBiome.dirtBlock; // Dirt(also stone rn) } else { - voxelType = 3u; // Stone + voxelType = currentBiome.stoneBlock; // Stone } } } diff --git a/resources/EngineResources/shaders/packed_scene_fragment.glsl b/resources/EngineResources/shaders/packed_scene_fragment.glsl new file mode 100644 index 0000000..d31628a --- /dev/null +++ b/resources/EngineResources/shaders/packed_scene_fragment.glsl @@ -0,0 +1,88 @@ +#version 450 +#extension GL_EXT_nonuniform_qualifier : require + +const int MAX_TEXTURES = 128; + +layout(location = 0) in vec4 inPos; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec3 inTangent; +layout(location = 3) in vec3 inBitangent; +layout(location = 4) in vec2 inTextCoords; +layout(location = 5) in mat4 viewMatrix; +layout(location = 9) in flat uint textureIndex; + +layout(location = 0) out vec4 outAlbedo; +layout(location = 1) out vec4 outViewPos; + +struct Material { + vec4 diffuseColor; //16 + uint hasTexture; //20 + uint textureIdx; //24 + uint hasNormalMap; //28 + uint normalMapIdx; //32 + uint hasRoughMap; //36 + uint roughMapIdx; //40 + float roughnessFactor; //44 + float metallicFactor; //48 + vec4 emissiveColour; //64 + uint hasEmissiveMap; //68 + uint emissiveMapIdx; //72 + uint hasTranslucencyMap; //76 + uint translucencyMapIdx; //80 + float translucencyFactor; //84 + uint hasOpacityMap; //88 + uint OpacityMapIdx; //92 + float OpacityFactor; //96 + float reflectiveness; //100 + float refractiveness; //104 + float Padding1; //108 + float Padding2; //112 +}; + +layout(set = 2, binding = 0) readonly buffer MaterialUniform{ + Material materials[]; +} matUniform; + +layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES]; + + +layout(push_constant) uniform pc{ + layout(offset = 64) uint materialIdx; +} push_constants; + +void main() +{ + vec4 viewPos = vec4(viewMatrix * inPos); + outViewPos = viewPos; + + Material material = matUniform.materials[textureIndex]; + + uint albedoTextureIndex = material.textureIdx; + if (albedoTextureIndex >= MAX_TEXTURES){ + outAlbedo = vec4(0.0,0.0,1.0,1.0); + return; + } + + if(material.hasTexture == 1){ + vec4 texColor = texture(textSampler[nonuniformEXT(albedoTextureIndex)], inTextCoords); + outAlbedo = texColor; + } else{ + outAlbedo = material.diffuseColor; + } + + 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[nonuniformEXT(material.OpacityMapIdx)], inTextCoords); + } + + float opacityf = Opacity.x + Opacity.y + Opacity.z; + opacityf = opacityf / 3; + if(opacityf < 0.4){ discard; } + + outAlbedo = vec4(outAlbedo.rgb, opacityf); +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/packed_scene_fragment_deferred.glsl b/resources/EngineResources/shaders/packed_scene_fragment_deferred.glsl new file mode 100644 index 0000000..8f5d5bf --- /dev/null +++ b/resources/EngineResources/shaders/packed_scene_fragment_deferred.glsl @@ -0,0 +1,149 @@ +#version 450 +#extension GL_EXT_nonuniform_qualifier : require + +const int MAX_TEXTURES = 128; + + +layout(location = 0) in vec4 inPos; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec3 inTangent; +layout(location = 3) in vec3 inBitangent; +layout(location = 4) in vec2 inTextCoords; +layout(location = 5) in mat4 viewMatrix; +layout(location = 9) in flat uint MaterialID; + +layout(location = 1) out vec4 outAlbedo ; +layout(location = 0) out vec4 outPos; +layout(location = 2) out vec4 outNormal; +layout(location = 3) out vec4 outPBR; +layout(location = 4) out vec4 outEmissive; +layout(location = 5) out vec4 outTranslucency; +layout(location = 6) out vec4 outOpacity; +layout(location = 7) out vec4 outViewPos; + +struct Material { + vec4 diffuseColor; //16 + uint hasTexture; //20 + uint textureIdx; //24 + uint hasNormalMap; //28 + uint normalMapIdx; //32 + uint hasRoughMap; //36 + uint roughMapIdx; //40 + float roughnessFactor; //44 + float metallicFactor; //48 + vec4 emissiveColour; //64 + uint hasEmissiveMap; //68 + uint emissiveMapIdx; //72 + uint hasTranslucencyMap; //76 + uint translucencyMapIdx; //80 + float translucencyFactor; //84 + uint hasOpacityMap; //88 + uint OpacityMapIdx; //92 + float OpacityFactor; //96 + float reflectiveness; //100 + float refractiveness; //104 + float Padding1; //108 + float Padding2; //112 +}; +layout(set = 2, binding = 0) readonly buffer MaterialUniform { + Material materials[]; +} matUniform; +layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES]; + +vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN) +{ + vec3 newNormal = normal; + if (material.hasNormalMap > 0 && material.normalMapIdx < MAX_TEXTURES) + { + newNormal = texture(textSampler[nonuniformEXT(material.normalMapIdx)], textCoords).rgb; + newNormal = normalize(newNormal * 2.0 - 1.0); + newNormal = normalize(TBN * newNormal); + } + return newNormal; +} + +layout(push_constant) uniform pc { + layout(offset = 64) uint materialIdx; +} push_constants; + +void main() +{ + outPos = inPos; + + vec4 viewPos = vec4(viewMatrix * vec4(inPos.xyz, 1.0)); + outViewPos = viewPos; + + Material material = matUniform.materials[MaterialID]; + + uint albedoTextureIndex = material.textureIdx; + if (albedoTextureIndex >= MAX_TEXTURES) { + outAlbedo = vec4(0.0,0.0,1.0,1.0); + outOpacity = vec4(0.0,0.0,1.0,1.0); + outNormal = vec4(0.0,0.0,1.0,1.0); + outEmissive = vec4(0.0,0.0,1.0,1.0); + outTranslucency = vec4(0.0,0.0,1.0,1.0); + outPBR = vec4(0.0,0.0,1.0,1.0); + return; + } + + if (material.hasTexture == 1) { + outAlbedo = texture(textSampler[nonuniformEXT(albedoTextureIndex)], inTextCoords); + } else { + outAlbedo = material.diffuseColor; + } + + 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) { + outOpacity = texture(textSampler[nonuniformEXT(material.OpacityMapIdx)], inTextCoords); + } else { + outOpacity = Opacity; + } + + Opacity = outOpacity; + + float opacityf = Opacity.x + Opacity.y + Opacity.z; + opacityf = opacityf / 3; + + outAlbedo = vec4(outAlbedo.rgb, opacityf); + + if(outAlbedo.a < 0.5) discard; + + mat3 TBN = mat3(inTangent, inBitangent, inNormal); + vec3 newNormal = calcNormal(material, inNormal, inTextCoords, TBN); + + float ao = 0.5f; + float roughnessFactor = 0.0f; + float metallicFactor = 0.0f; + + if (material.hasRoughMap > 0 && material.roughMapIdx < MAX_TEXTURES) { + vec4 metRoughValue = texture(textSampler[nonuniformEXT(material.roughMapIdx)], inTextCoords); + roughnessFactor = metRoughValue.g; + metallicFactor = metRoughValue.b; + } else { + roughnessFactor = material.roughnessFactor; + metallicFactor = material.metallicFactor; + } + + vec4 emissive = material.emissiveColour; + if (material.hasEmissiveMap > 0 && material.emissiveMapIdx < MAX_TEXTURES) { + emissive = texture(textSampler[nonuniformEXT(material.emissiveMapIdx)], inTextCoords); + } + outEmissive = emissive; + + vec4 Translucency = vec4(material.translucencyFactor, material.translucencyFactor, material.translucencyFactor, 1); + if(material.hasTranslucencyMap > 0 && material.translucencyMapIdx < MAX_TEXTURES){ + Translucency = texture(textSampler[nonuniformEXT(material.translucencyMapIdx)], inTextCoords); + } + outTranslucency = Translucency; + + float Refractiveness = material.refractiveness; + float Reflectiveness = material.reflectiveness; + + outNormal = vec4(newNormal, Refractiveness); + outPBR = vec4(ao, roughnessFactor, metallicFactor, Reflectiveness); +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/packed_scene_vertex.glsl b/resources/EngineResources/shaders/packed_scene_vertex.glsl index 6e125f4..be818ae 100644 --- a/resources/EngineResources/shaders/packed_scene_vertex.glsl +++ b/resources/EngineResources/shaders/packed_scene_vertex.glsl @@ -6,6 +6,7 @@ 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(location = 9) out flat uint outMaterialID; layout(set = 0, binding = 0) uniform ProjUniform { mat4 matrix; } projUniform; layout(set = 1, binding = 0) uniform ViewUniform { mat4 matrix; } viewUniform; @@ -93,17 +94,13 @@ void main() { uint triangleVertex = (uint(gl_VertexIndex))% 6u; uint cornerIndex = TRI_TO_CORNER[triangleVertex]; - //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; + uint voxelX = packedFace & 0xFu; + uint voxelY = (packedFace >> 4u) & 0xFu; + uint voxelZ = (packedFace >> 8u) & 0xFu; + uint faceId = (packedFace >> 12u) & 0x7u; + uint matId = (packedFace >> 15u) & 0x7FFu; uint texIdxX = (packedFace >> 26u) & 0x7u; uint texIdxY = (packedFace >> 29u) & 0x7u; @@ -111,7 +108,6 @@ void main() { vec2 scalar = vec2(1.0/4.0,1.0/4.0); faceId = min(faceId, 7u); - matId = min(matId, 4u); vec3 localPos = vec3(voxelX, voxelY, voxelZ) + FACE_CORNERS[faceId][cornerIndex]; vec3 worldPos = localPos + push_constants.ModelOffset.xyz * 16.0; @@ -119,10 +115,14 @@ void main() { 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_GRASS_BLOCK[faceId][cornerIndex] * scalar + texID; + vec2 atlasSize = vec2(64, 64); + vec2 texel = 0.5 / atlasSize; + vec2 tileMin = vec2(texIdxX, texIdxY) * scalar + texel; + vec2 tileMax = vec2(texIdxX + 1u, texIdxY + 1u) * scalar - texel; + outTextCoords = mix(tileMin, tileMax, CORNER_UVS_GRASS_BLOCK[faceId][cornerIndex]); + outMaterialID = matId; } \ No newline at end of file diff --git a/resources/EngineResources/shaders/shadow_vertex_packed.glsl b/resources/EngineResources/shaders/shadow_vertex_packed.glsl index 8833df7..7fc691a 100644 --- a/resources/EngineResources/shaders/shadow_vertex_packed.glsl +++ b/resources/EngineResources/shaders/shadow_vertex_packed.glsl @@ -17,6 +17,69 @@ layout(location = 1) out flat uint outMaterialIdx; const uint TRI_TO_CORNER[6] = uint[6](0u, 1u, 2u, 0u, 2u, 3u); +const vec3 NORMALS[8] = vec3[8]( + vec3( 0.0, 1.0, 0.0), // Face 0 (+Y) + vec3( 0.0, -1.0, 0.0), // Face 1 (-Y) + vec3( 1.0, 0.0, 0.0), // Face 2 (+X) + vec3(-1.0, 0.0, 0.0), // Face 3 (-X) + vec3( 0.0, 0.0, 1.0), // Face 4 (+Z) + vec3( 0.0, 0.0, -1.0), // Face 5 (-Z) + vec3(-0.7071, 0.0, 0.7071), // Face 6 + vec3( 0.7071, 0.0, 0.7071) // Face 7 +); + +const vec3 TANGENTS[8] = vec3[8]( + vec3( 1.0, 0.0, 0.0), // Face 0 + vec3( 1.0, 0.0, 0.0), // Face 1 + vec3( 0.0, 0.0, -1.0), // Face 2 + vec3( 0.0, 0.0, 1.0), // Face 3 + vec3( 1.0, 0.0, 0.0), // Face 4 + vec3(-1.0, 0.0, 0.0), // Face 5 + vec3( 0.7071, 0.0, 0.7071), // Face 6 + vec3( 0.7071, 0.0,-0.7071) // Face 7 +); + +const vec3 BITANGENTS[8] = vec3[8]( + vec3( 0.0, 0.0, 1.0), // Face 0 + vec3( 0.0, 0.0, -1.0), // Face 1 + vec3( 0.0, 1.0, 0.0), // Face 2 + vec3( 0.0, 1.0, 0.0), // Face 3 + vec3( 0.0, 1.0, 0.0), // Face 4 + vec3( 0.0, 1.0, 0.0), // Face 5 + vec3( 0.0, 1.0, 0.0), // Face 6 + vec3( 0.0, 1.0, 0.0) // Face 7 +); + +const vec2 CORNER_UVS[5][4] = vec2[5][4]( + vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)), + vec2[4](vec2(0.0, 0.5), vec2(0.0, 1.0), vec2(0.5, 1.0), vec2(0.5, 0.5)), + vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)), + vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)), + vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.5), vec2(0.5, 0.5), vec2(0.5, 1.0)) +); +const vec2 CORNER_UVS_GRASS_BLOCK[8][4] = vec2[8][4]( + vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)), + vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)), + vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0), vec2(0.0, 1.0)), + vec2[4]( vec2(0.0, 1.0),vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0)), + vec2[4]( vec2(0.0, 1.0),vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0)), + vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0), vec2(0.0, 1.0)), + vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(0.0, 1.0)), + vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(0.0, 1.0)) + +); + +const vec3 FACE_CORNERS[8][4] = vec3[8][4]( + vec3[4](vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 0.0)), // Face 0 (+Y) + vec3[4](vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 1.0), vec3(0.0, 0.0, 1.0)), // Face 1 (-Y) + vec3[4](vec3(1.0, 0.0, 0.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0)), // Face 2 (+X) + vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), vec3(0.0, 1.0, 0.0)), // Face 3 (-X) + vec3[4](vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(0.0, 1.0, 1.0)), // Face 4 (+Z) + vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0)), // Face 5 (-Z) + vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0)), // Face 6 (cross model pane 1) + vec3[4](vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0)) // Face 7 (cross model pane 2) +); + vec3 buildFaceCornerPosition(uvec3 voxelPos, uint faceId, uint cornerIndex) { vec3 p = vec3(voxelPos); @@ -63,21 +126,40 @@ vec3 buildFaceCornerPosition(uvec3 voxelPos, uint faceId, uint cornerIndex) { void main() { uint faceRecordIndex = uint(gl_VertexIndex) / 6u; - uint triangleVertex = uint(gl_VertexIndex) % 6u; + uint triangleVertex = (uint(gl_VertexIndex))% 6u; uint cornerIndex = TRI_TO_CORNER[triangleVertex]; + //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; + uint voxelX = packedFace & 0xFu; + uint voxelY = (packedFace >> 4u) & 0xFu; + uint voxelZ = (packedFace >> 8u) & 0xFu; + uint faceId = (packedFace >> 12u) & 0x7u; + uint matId = (packedFace >> 15u) & 0x7FFu; + uint texIdxX = (packedFace >> 26u) & 0x7u; + uint texIdxY = (packedFace >> 29u) & 0x7u; - vec3 localPos = buildFaceCornerPosition(uvec3(voxelX, voxelY, voxelZ), faceId, cornerIndex); + // (voxelPos.x & 0xFu) | + // ((voxelPos.y & 0xFu) << 4u) | + // ((voxelPos.z & 0xFu) << 8u) | + // ((faceIndex & 0x7u) << 12u) | + // ((materialId & 0x7FFu) << 15u) | + // ((textureIndexX & 0x7u) << 26u) | + // ((textureIndexY & 0x7u) << 29u); + + vec2 texID = vec2((texIdxX)/4.0,(texIdxY)/4.0); + vec2 scalar = vec2(1.0/4.0,1.0/4.0); + + faceId = min(faceId, 7u); + + vec3 localPos = vec3(voxelX, voxelY, voxelZ) + FACE_CORNERS[faceId][cornerIndex]; vec3 worldPos = localPos + push_constants.ModelOffset.xyz * 16.0; - outTextCoord = vec2(0.0); + outTextCoord = CORNER_UVS_GRASS_BLOCK[faceId][cornerIndex] * scalar + texID; outMaterialIdx = matId; gl_Position = vec4(worldPos, 1.0); diff --git a/resources/EngineResources/shaders/water_frag.glsl b/resources/EngineResources/shaders/water_frag.glsl new file mode 100644 index 0000000..745b053 --- /dev/null +++ b/resources/EngineResources/shaders/water_frag.glsl @@ -0,0 +1,51 @@ +#version 460 core + +in vec3 FragPos; +in vec2 TexCoords; +in vec3 Normal; + +out vec4 FragColor; + +uniform vec3 cameraPos; +uniform vec3 lightPos; + +// Material constants +const vec3 waterShallowColor = vec3(0.0, 0.6, 0.7); +const vec3 waterDeepColor = vec3(0.05, 0.15, 0.3); +const vec3 sunColor = vec3(1.0, 0.95, 0.8); + +void main() { + // Normalize vectors + vec3 n = normalize(Normal); + vec3 viewDir = normalize(cameraPos - FragPos); + vec3 lightDir = normalize(lightPos - FragPos); + + // 1. Ambient Lighting + vec3 ambient = 0.3 * waterShallowColor; + + // 2. Diffuse Shading + float diff = max(dot(n, lightDir), 0.0); + vec3 diffuse = diff * sunColor * 0.4; + + // 3. Specular Highlights (Blinn-Phong) + vec3 halfwayDir = normalize(lightDir + viewDir); + float spec = pow(max(dot(n, halfwayDir), 0.0), 64.0); // High shininess for water glaze + vec3 specular = spec * sunColor * 0.8; + + // 4. Fresnel Approximation (Schlick's approximation) + // Water has a base reflectivity of roughly 0.02 at a perpendicular view angle + float F0 = 0.02; + float fresnel = F0 + (1.0 - F0) * pow(1.0 - max(dot(n, viewDir), 0.0), 5.0); + + // Mix deep and shallow water colors based on the normal angle + vec3 baseWaterColor = mix(waterShallowColor, waterDeepColor, max(dot(n, vec3(0.0, 1.0, 0.0)), 0.0)); + + // Combine lighting results + vec3 lightingResult = ambient + diffuse + specular; + + // Blend final look with Fresnel reflection dominance + vec3 finalColor = mix(baseWaterColor + specular, lightingResult + vec3(fresnel * 0.5), fresnel); + + // Output final color with subtle translucency opacity + FragColor = vec4(finalColor, 0.85); +} diff --git a/resources/EngineResources/shaders/water_vert.glsl b/resources/EngineResources/shaders/water_vert.glsl new file mode 100644 index 0000000..ac3c0a1 --- /dev/null +++ b/resources/EngineResources/shaders/water_vert.glsl @@ -0,0 +1,46 @@ +#version 450 + +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoords; + +out vec3 FragPos; +out vec2 TexCoords; +out vec3 Normal; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; +uniform float uTime; + +// Wave configuration constants +const float AMPLITUDE = 0.15; +const float FREQUENCY = 1.5; +const float SPEED = 2.0; + +// Simple wave function that modifies elevation based on position and time +float calculateWave(vec3 pos, float time, vec2 direction) { + return AMPLITUDE * sin(dot(pos.xz, direction) * FREQUENCY + time * SPEED); +} + +// Derivative of the wave function to calculate accurate dynamic surface normals +vec3 calculateWaveNormal(vec3 pos, float time) { + float dx = AMPLITUDE * FREQUENCY * cos(pos.x * FREQUENCY + time * SPEED); + float dz = AMPLITUDE * FREQUENCY * cos(pos.z * FREQUENCY + time * SPEED); + return normalize(vec3(-dx, 1.0, -dz)); +} + +void main() { + vec3 displacedPos = aPos; + + // Combine two wave directions for a less predictable, more organic look + displacedPos.y += calculateWave(aPos, uTime, vec2(1.0, 0.0)); + displacedPos.y += calculateWave(aPos, uTime * 1.2, vec2(0.5, 0.8)); + + FragPos = vec3(model * vec4(displacedPos, 1.0)); + TexCoords = aTexCoords; + + // Pass transformed normals and position to the fragment shader + Normal = mat3(transpose(inverse(model))) * calculateWaveNormal(displacedPos, uTime); + + gl_Position = projection * view * model * vec4(displacedPos, 1.0); +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java index fd49cf3..a1b633a 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java @@ -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.Biome; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.Voxel; 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; @@ -30,6 +32,7 @@ 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.Vector2i; import org.joml.Vector3f; import org.joml.Vector3i; import org.lwjgl.system.MemoryStack; @@ -188,6 +191,190 @@ public class VulkanRenderer implements Renderer { GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache); //VoxelWorldManager.Init(RendererContext); // VoxelWorldManager.GenerateChunks(new Vector3i(0,0,0), new Vector3i(16,0,16)); + Vector2i positionArr[][] = new Vector2i[4][4]; + for(int x = 0; x < 4; x++){ + for(int y = 0; y < 4; y++){ + positionArr[x][y] = new Vector2i(x,y); + } + } + int Index = materialsCache.GetPosition("VoxelTerrain"); + int Index2 = materialsCache.GetPosition("Blueleaf"); + int Index3 = materialsCache.GetPosition("Blueleaf2"); + Voxel grassVoxel = new Voxel(Index, 0, + new Vector2i[]{positionArr[0][1], positionArr[0][3]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}); + + Voxel stoneVoxel = new Voxel(Index, 0, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}); + + Voxel grassSideVoxel = new Voxel(Index, 1, + new Vector2i[]{positionArr[1][1], positionArr[1][3]}, + new Vector2i[]{positionArr[1][1], positionArr[1][3]}, + new Vector2i[]{positionArr[1][1], positionArr[1][3]}, + new Vector2i[]{positionArr[1][1], positionArr[1][3]}, + new Vector2i[]{positionArr[1][1], positionArr[1][3]}, + new Vector2i[]{positionArr[1][1], positionArr[1][3]}); + Voxel Mushroom = new Voxel(Index, 1, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}); + + Voxel Log = new Voxel(Index, 0, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}); + + Voxel Leaves = new Voxel(Index, 2, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}); + + Voxel bluegrassVoxel = new Voxel(Index2, 0, + new Vector2i[]{positionArr[0][1], positionArr[1][3]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}, + new Vector2i[]{positionArr[0][0], positionArr[0][0]}); + + Voxel blueDirtVoxel = new Voxel(Index2, 0, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}, + new Vector2i[]{positionArr[1][0], positionArr[1][0]}); + + Voxel bluegrassSideVoxel = new Voxel(Index3, 1, + new Vector2i[]{positionArr[0][0], positionArr[1][2]}, + new Vector2i[]{positionArr[0][0], positionArr[1][2]}, + new Vector2i[]{positionArr[0][0], positionArr[1][2]}, + new Vector2i[]{positionArr[0][0], positionArr[1][2]}, + new Vector2i[]{positionArr[0][0], positionArr[1][2]}, + new Vector2i[]{positionArr[0][0], positionArr[1][2]}); + + Voxel blueFlower1 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}, + new Vector2i[]{positionArr[2][0], positionArr[2][0]}); + + Voxel blueFlower2 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}, + new Vector2i[]{positionArr[2][1], positionArr[2][1]}); + + Voxel blueFlower3 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}, + new Vector2i[]{positionArr[2][2], positionArr[2][2]}); + + Voxel blueFlower4 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}, + new Vector2i[]{positionArr[2][3], positionArr[2][3]}); + + Voxel blueFlower5 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[3][0], positionArr[3][0]}, + new Vector2i[]{positionArr[3][0], positionArr[3][0]}, + new Vector2i[]{positionArr[3][0], positionArr[3][0]}, + new Vector2i[]{positionArr[3][0], positionArr[3][0]}, + new Vector2i[]{positionArr[3][0], positionArr[3][0]}, + new Vector2i[]{positionArr[3][0], positionArr[3][0]}); + + Voxel blueFlower6 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[3][1], positionArr[3][1]}, + new Vector2i[]{positionArr[3][1], positionArr[3][1]}, + new Vector2i[]{positionArr[3][1], positionArr[3][1]}, + new Vector2i[]{positionArr[3][1], positionArr[3][1]}, + new Vector2i[]{positionArr[3][1], positionArr[3][1]}, + new Vector2i[]{positionArr[3][1], positionArr[3][1]}); + + Voxel blueFlower7 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[3][2], positionArr[3][2]}, + new Vector2i[]{positionArr[3][2], positionArr[3][2]}, + new Vector2i[]{positionArr[3][2], positionArr[3][2]}, + new Vector2i[]{positionArr[3][2], positionArr[3][2]}, + new Vector2i[]{positionArr[3][2], positionArr[3][2]}, + new Vector2i[]{positionArr[3][2], positionArr[3][2]}); + + Voxel blueFlower8 = new Voxel(Index2, 1, + new Vector2i[]{positionArr[3][3], positionArr[3][3]}, + new Vector2i[]{positionArr[3][3], positionArr[3][3]}, + new Vector2i[]{positionArr[3][3], positionArr[3][3]}, + new Vector2i[]{positionArr[3][3], positionArr[3][3]}, + new Vector2i[]{positionArr[3][3], positionArr[3][3]}, + new Vector2i[]{positionArr[3][3], positionArr[3][3]}); + Voxel blueLeaves1 = new Voxel(Index3, 2, + new Vector2i[]{positionArr[0][3], positionArr[0][3]}, + new Vector2i[]{positionArr[0][3], positionArr[0][3]}, + new Vector2i[]{positionArr[0][3], positionArr[0][3]}, + new Vector2i[]{positionArr[0][3], positionArr[0][3]}, + new Vector2i[]{positionArr[0][3], positionArr[0][3]}, + new Vector2i[]{positionArr[0][3], positionArr[0][3]}); + Voxel blueLeaves2 = new Voxel(Index3, 2, + new Vector2i[]{positionArr[1][3], positionArr[1][3]}, + new Vector2i[]{positionArr[1][3], positionArr[1][3]}, + new Vector2i[]{positionArr[1][3], positionArr[1][3]}, + new Vector2i[]{positionArr[1][3], positionArr[1][3]}, + new Vector2i[]{positionArr[1][3], positionArr[1][3]}, + new Vector2i[]{positionArr[1][3], positionArr[1][3]}); + + VoxelWorldManager.AddVoxel(grassVoxel, "grass");//1 + VoxelWorldManager.AddVoxel(stoneVoxel, "DirtVoxel");//2 + VoxelWorldManager.AddVoxel(stoneVoxel, "StoneVoxel");//3 + VoxelWorldManager.AddVoxel(grassSideVoxel, "grassSideVoxel");//4 + VoxelWorldManager.AddVoxel(Mushroom, "mushroom");//5 + VoxelWorldManager.AddVoxel(Log, "log");//6 + VoxelWorldManager.AddVoxel(Leaves, "leaves");//7 + VoxelWorldManager.AddVoxel(bluegrassVoxel, "bluegrassVoxel");//8 + VoxelWorldManager.AddVoxel(blueDirtVoxel, "blueDirtVoxel");//9 + VoxelWorldManager.AddVoxel(bluegrassSideVoxel, "bluegrassSideVoxel");//10 + VoxelWorldManager.AddVoxel(blueFlower1, "blueFlower1");//11 + VoxelWorldManager.AddVoxel(blueFlower2, "blueFlower2");//12 + VoxelWorldManager.AddVoxel(blueFlower3, "blueFlower3");//13 + VoxelWorldManager.AddVoxel(blueFlower4, "blueFlower4");//14 + VoxelWorldManager.AddVoxel(blueFlower5, "blueFlower5");//15 + VoxelWorldManager.AddVoxel(blueFlower6, "blueFlower6");//16 + VoxelWorldManager.AddVoxel(blueFlower7, "blueFlower7");//17 + VoxelWorldManager.AddVoxel(blueFlower8, "blueFlower8");//18 + VoxelWorldManager.AddVoxel(blueLeaves1, "blueLeaves1");//19 + VoxelWorldManager.AddVoxel(blueLeaves2, "blueLeaves2");//20 + + Biome GreenBiome = new Biome(1,2,3,4,new int[]{5,6,7,4},new int[]{4,4,4,4},new int[]{4,18,16,17}); + Biome Blueleaf = new Biome(8,9,3,10,new int[]{11,19,20,14},new int[]{5,6,7,8},new int[]{15,16,17,18}); + + VoxelWorldManager.AddBiome(Blueleaf, "blueleaf"); + VoxelWorldManager.AddBiome(GreenBiome, "greenBiome"); } public GuiRenderer GetGUIRenderer(){return GuiRender;} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java index b748b65..53ff5d8 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java @@ -163,8 +163,14 @@ 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); + 0,0,"",new Vector4f(),"resources/EngineResources/Texture/test_cube_translucency.png",0,"",1,new Vector4f(),1.0f,0); + MaterialData BlueleafMat = new MaterialData("Blueleaf","resources/EngineResources/Texture/blueleaf_set.png","","",new Vector4f(1,1,1,1), + 0,0,"",new Vector4f(),"resources/EngineResources/Texture/blueleaf_set_translucent.png",0,"",1,new Vector4f(),1.0f,0); + MaterialData BlueleafMat2 = new MaterialData("Blueleaf2","resources/EngineResources/Texture/blueleaf_set_2.png","","",new Vector4f(1,1,1,1), + 0,0,"",new Vector4f(),"resources/EngineResources/Texture/blueleaf_set_2_translucent.png",0,"",1,new Vector4f(),1.0f,0); materials.add(VoxelMat); + materials.add(BlueleafMat); + materials.add(BlueleafMat2); materials.addAll(MelonaMat); materials.addAll(CollisionVisualisationMat); materials.addAll(MelonaMaterial); @@ -681,11 +687,11 @@ public class GameCore implements GameLogic { Vector3f CamRot = cam.GetRotation(); 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 || CamRot.x != LastCamRotation.x || CamRot.y != LastCamRotation.y || CamRot.z != LastCamRotation.z) { - VoxelWorldManager.UnloadFarChunks(ChunkPos, 12,cam.GetViewMatrix(),projection.GetProjectionMatrix()); - VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(12,8,12),cam.GetViewMatrix(),projection.GetProjectionMatrix()); + VoxelWorldManager.UnloadFarChunks(ChunkPos, 16,cam.GetViewMatrix(),projection.GetProjectionMatrix()); + VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(16,16,16),cam.GetViewMatrix(),projection.GetProjectionMatrix()); } else { - VoxelWorldManager.UnloadFarChunks(ChunkPos, 24,cam.GetViewMatrix(),projection.GetProjectionMatrix()); - VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(24,12,24),cam.GetViewMatrix(),projection.GetProjectionMatrix()); + VoxelWorldManager.UnloadFarChunks(ChunkPos, 96,cam.GetViewMatrix(),projection.GetProjectionMatrix()); + VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(48,16,48),cam.GetViewMatrix(),projection.GetProjectionMatrix()); } LastCamRotation.set(CamRot); if(PrimaryRuntime.IsServer){ diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java index 9b8ccd8..567f985 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java @@ -163,9 +163,9 @@ CreateNewClientConnection(); Logger.debug("UnThrottlingEngine"); FrameAccuracy= OriginalFrameAccuracy; } - PrimaryThread.UpdateFrameAccuracy(); - DrawingThread.UpdateFrameAccuracy(); - FastThread.UpdateFrameAccuracy(); + if(PrimaryThread != null)PrimaryThread.UpdateFrameAccuracy(); + if(DrawingThread != null)DrawingThread.UpdateFrameAccuracy(); + if(FastThread != null)FastThread.UpdateFrameAccuracy(); } public void UpdateTickRateThreshold(){ CappedToTickRate = EngineConfig.getInstance().GetPrimaryTickCap(); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/Biome.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/Biome.java new file mode 100644 index 0000000..6796a78 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/Biome.java @@ -0,0 +1,4 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +public record Biome(int surfaceBlock, int dirtBlock, int stoneBlock, int grassFoliage, int[] foliageBlocks, int[] tallBlocks, int[] otherFoliage) { +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java index fc60b0d..24796f3 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/SharedVoxelTerrainResources.java @@ -8,8 +8,13 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.P 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.system.MemoryUtil; import org.lwjgl.util.shaderc.Shaderc; +import java.nio.ByteBuffer; +import java.util.List; + +import static org.lwjgl.util.vma.Vma.VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; import static org.lwjgl.vulkan.VK13.*; @@ -22,20 +27,31 @@ public class SharedVoxelTerrainResources { public static final int TERRAIN_GENERATION_PUSH_CONSTANT_SIZE = Integer.BYTES * 8; + public static final int MAX_VOXEL_TYPES = 256; + public static final int MAX_BIOME_TYPES = 256; + public static final int VOXEL_REG_DATA_SIZE = 104; + public static final int BIOME_REG_DATA_SIZE = 64; + 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 DESC_ID_FACE_GRAPHICS = "VOXEL_SHARED_DESC_FACE_GRAPHICS"; + private static final String DESC_ID_VOXEL_REG = "VOXEL_REGISTRY"; + private static final String DESC_ID_BIOME_REG = "BIOME_REGISTRY"; private final VoxelMeshPool meshPool; private final VulkanBuffer voxelData; private final VulkanBuffer counters; + private final VulkanBuffer voxelRegistryBuffer; + private final VulkanBuffer biomeRegistryBuffer; private final DescriptorSetLayout voxelGenerationLayout; private final DescriptorSetLayout resetLayout; private final DescriptorSetLayout meshGenerationLayout; private final DescriptorSetLayout faceGraphicsLayout; + private final DescriptorSetLayout voxelDeclarationLayout; + private final DescriptorSetLayout biomeDeclarationLayout; private static final String MESH_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl"; private static final String VOXEL_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl"; @@ -58,6 +74,15 @@ public class SharedVoxelTerrainResources { counters = new VulkanBuffer(VkCtx, COUNTER_BUFFER_SIZE, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0, 0); + voxelRegistryBuffer = new VulkanBuffer(VkCtx, (long) MAX_VOXEL_TYPES * VOXEL_REG_DATA_SIZE, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + biomeRegistryBuffer = new VulkanBuffer(VkCtx, (long) MAX_BIOME_TYPES * BIOME_REG_DATA_SIZE, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, 1, VK_SHADER_STAGE_COMPUTE_BIT) }); @@ -78,6 +103,13 @@ public class SharedVoxelTerrainResources { new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_VERTEX_BIT ) }); + voxelDeclarationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, 1, VK_SHADER_STAGE_COMPUTE_BIT) + }); + biomeDeclarationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{ + new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, 1, VK_SHADER_STAGE_COMPUTE_BIT) + }); + createDescriptorSets(VkCtx); PushConstantsRange[] generationPushConstants = new PushConstantsRange[]{ @@ -90,9 +122,11 @@ public class SharedVoxelTerrainResources { resetPipeline = new ComputePipeline(VkCtx,resetShader,new DescriptorSetLayout[]{resetLayout},generationPushConstants); - voxelGenerationPipeline = new ComputePipeline(VkCtx,voxelShader, new DescriptorSetLayout[]{voxelGenerationLayout},generationPushConstants); + voxelGenerationPipeline = new ComputePipeline(VkCtx,voxelShader, + new DescriptorSetLayout[]{voxelGenerationLayout,biomeDeclarationLayout},generationPushConstants); - meshGenerationPipeline = new ComputePipeline( VkCtx,meshShader, new DescriptorSetLayout[]{meshGenerationLayout},generationPushConstants ); + meshGenerationPipeline = new ComputePipeline(VkCtx, meshShader, + new DescriptorSetLayout[]{meshGenerationLayout, voxelDeclarationLayout}, generationPushConstants); resetShader.CleanUp(VkCtx); voxelShader.CleanUp(VkCtx); @@ -126,6 +160,71 @@ public class SharedVoxelTerrainResources { DescriptorSet faceGraphicsSet = allocator.AddDescriptorSet(device, DESC_ID_FACE_GRAPHICS, faceGraphicsLayout); faceGraphicsSet.SetBuffer(device, meshPool.facePool(), meshPool.facePool().GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + + DescriptorSet voxelDeclareDescriptorSet = allocator.AddDescriptorSet(device, DESC_ID_VOXEL_REG, voxelDeclarationLayout); + voxelDeclareDescriptorSet.SetBuffer(device, voxelRegistryBuffer, voxelRegistryBuffer.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + DescriptorSet biomeDeclareDescriptorSet = allocator.AddDescriptorSet(device, DESC_ID_BIOME_REG, biomeDeclarationLayout); + biomeDeclareDescriptorSet.SetBuffer(device, biomeRegistryBuffer, biomeRegistryBuffer.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + + } + + public void UploadBiomeRegistry(VulkanContext VkCtx, List biomeReg) { + int count = Math.min(biomeReg.size(), MAX_BIOME_TYPES); + long memoryAddr = biomeRegistryBuffer.MapMemory(VkCtx); + ByteBuffer buffer = MemoryUtil.memByteBuffer(memoryAddr, (int) biomeRegistryBuffer.GetRequestedSize()); + + for (int i = 0; i < count; i++) { + Biome biome = biomeReg.get(i); + int base = i * BIOME_REG_DATA_SIZE; + buffer.putInt(base + 0, biome.surfaceBlock()); + buffer.putInt(base + 4, biome.dirtBlock()); + buffer.putInt(base + 8, biome.stoneBlock()); + buffer.putInt(base + 12, biome.grassFoliage()); + for (int j = 0; j < 4; j++) { + buffer.putInt(base + 16 + j * 4, biome.foliageBlocks()[j]); + buffer.putInt(base + 32 + j * 4, biome.tallBlocks()[j]); + buffer.putInt(base + 48 + j * 4, biome.otherFoliage()[j]); + } + } + biomeRegistryBuffer.UnMapMemory(VkCtx); + } + + public void UploadVoxelRegistry(VulkanContext VkCtx, List voxelReg) { + int count = Math.min(voxelReg.size(), MAX_VOXEL_TYPES); + long memoryAddr = voxelRegistryBuffer.MapMemory(VkCtx); + ByteBuffer buffer = MemoryUtil.memByteBuffer(memoryAddr, (int) voxelRegistryBuffer.GetRequestedSize()); + + for (int i = 0; i < count; i++) { + Voxel voxel = voxelReg.get(i); + int base = i * VOXEL_REG_DATA_SIZE; + buffer.putInt(base + 0, voxel.MaterialID()); + buffer.putInt(base + 4, voxel.BlockType()); + buffer.putInt(base + 8, voxel.UpUV()[0].x); + buffer.putInt(base + 12, voxel.UpUV()[0].y); + buffer.putInt(base + 16, voxel.UpUV()[1].x); + buffer.putInt(base + 20, voxel.UpUV()[1].y); + buffer.putInt(base + 24, voxel.DownUV()[0].x); + buffer.putInt(base + 28, voxel.DownUV()[0].y); + buffer.putInt(base + 32, voxel.DownUV()[1].x); + buffer.putInt(base + 36, voxel.DownUV()[1].y); + buffer.putInt(base + 40, voxel.NorthUV()[0].x); + buffer.putInt(base + 44, voxel.NorthUV()[0].y); + buffer.putInt(base + 48, voxel.NorthUV()[1].x); + buffer.putInt(base + 52, voxel.NorthUV()[1].y); + buffer.putInt(base + 56, voxel.SouthUV()[0].x); + buffer.putInt(base + 60, voxel.SouthUV()[0].y); + buffer.putInt(base + 64, voxel.SouthUV()[1].x); + buffer.putInt(base + 68, voxel.SouthUV()[1].y); + buffer.putInt(base + 72, voxel.EastUV()[0].x); + buffer.putInt(base + 76, voxel.EastUV()[0].y); + buffer.putInt(base + 80, voxel.EastUV()[1].x); + buffer.putInt(base + 84, voxel.EastUV()[1].y); + buffer.putInt(base + 88, voxel.WestUV()[0].x); + buffer.putInt(base + 92, voxel.WestUV()[0].y); + buffer.putInt(base + 96, voxel.WestUV()[1].x); + buffer.putInt(base + 100, voxel.WestUV()[1].y); + } + voxelRegistryBuffer.UnMapMemory(VkCtx); } public DescriptorSetLayout faceGraphicsLayout() { @@ -163,6 +262,12 @@ public class SharedVoxelTerrainResources { public String voxelGenerationDescriptorId() { return DESC_ID_VOXEL_GENERATION; } + public String voxelRegDescriptorID() { + return DESC_ID_VOXEL_REG; + } + public String biomeRegDescriptorID() { + return DESC_ID_BIOME_REG; + } public String resetDescriptorId() { return DESC_ID_RESET; @@ -181,9 +286,13 @@ public class SharedVoxelTerrainResources { voxelGenerationLayout.CleanUp(VkCtx); meshGenerationLayout.CleanUp(VkCtx); faceGraphicsLayout.CleanUp(VkCtx); + voxelDeclarationLayout.CleanUp(VkCtx); + biomeDeclarationLayout.CleanUp(VkCtx); voxelData.cleanup(VkCtx); counters.cleanup(VkCtx); + voxelRegistryBuffer.cleanup(VkCtx); + biomeRegistryBuffer.cleanup(VkCtx); meshPool.cleanup(VkCtx); } } \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/Voxel.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/Voxel.java new file mode 100644 index 0000000..c3a6e74 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/Voxel.java @@ -0,0 +1,6 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration; + +import org.joml.Vector2i; + +public record Voxel(int MaterialID, int BlockType, Vector2i[] UpUV, Vector2i[] DownUV, Vector2i[] NorthUV, Vector2i[] SouthUV, Vector2i[] EastUV, Vector2i[] WestUV) { +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java index 0430a45..e3698da 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelChunkGenerator.java @@ -38,16 +38,18 @@ public class VoxelChunkGenerator { pushConstants.putInt(8, chunk.position().z); pushConstants.putInt(12, chunk.slot()); pushConstants.putInt(16, faceOffset); - pushConstants.putInt(20, 0); + pushConstants.putInt(20, VoxelWorldManager.GetVoxelTypeCount()); pushConstants.putInt(24, indirectCommandIndex); - pushConstants.putInt(28, 0); + pushConstants.putInt(28, VoxelWorldManager.GetBiomeTypeCount()); 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()); + resources.voxelGenerationDescriptorId()).GetVkDescriptorSet(), + allocator.GetDescriptorSet(resources.biomeRegDescriptorID()).GetVkDescriptorSet()); + LongBuffer meshDescriptorSet = stack.longs( + allocator.GetDescriptorSet(resources.meshDescriptorId()).GetVkDescriptorSet(), + allocator.GetDescriptorSet(resources.voxelRegDescriptorID()).GetVkDescriptorSet()); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipeline()); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipelineLayout(),0, resetDescriptorSet,null ); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java index ca06519..3510b02 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Computing/VoxelTerrainGeneration/VoxelWorldManager.java @@ -10,6 +10,8 @@ import org.lwjgl.vulkan.VkCommandBuffer; import org.tinylog.Logger; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -17,7 +19,7 @@ import static org.lwjgl.vulkan.VK13.*; public class VoxelWorldManager { public static final int CHUNK_SIZE = 16; - private static final int MAX_RESIDENT_CHUNKS = 8192 * 2; + private static final int MAX_RESIDENT_CHUNKS = 8192 * 3; private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 128; private static final ConcurrentLinkedQueue RequestedChunks = new ConcurrentLinkedQueue<>(); @@ -25,6 +27,71 @@ public class VoxelWorldManager { private static final ConcurrentHashMap KnownChunks = new ConcurrentHashMap<>(); private static final ConcurrentHashMap CulledChunks = new ConcurrentHashMap<>(); + private static final List VoxelRegistry = new java.util.concurrent.CopyOnWriteArrayList<>(); + private static final ConcurrentHashMap VoxelNameToIndex = new ConcurrentHashMap<>(); + private static volatile boolean RegistryDirty = false; + + private static final List BiomeRegistry = new java.util.concurrent.CopyOnWriteArrayList<>(); + private static final ConcurrentHashMap BiomeNameToIndex = new ConcurrentHashMap<>(); + private static volatile boolean BiomeRegistryDirty = false; + + public static synchronized void AddVoxel(Voxel voxel, String name) { + Integer existing = VoxelNameToIndex.get(name); + if (existing != null) { + VoxelRegistry.set(existing, voxel); + } else { + VoxelNameToIndex.put(name, VoxelRegistry.size()); + VoxelRegistry.add(voxel); + } + RegistryDirty = true; + } + + public static List GetVoxelRegistry() { + return new ArrayList<>(VoxelRegistry); + } + + public static Voxel GetVoxel(String name) { + Integer idx = VoxelNameToIndex.get(name); + return idx == null ? null : VoxelRegistry.get(idx); + } + + public static int GetVoxelTypeID(String name) { + Integer idx = VoxelNameToIndex.get(name); + return idx == null ? -1 : idx + 1; + } + + public static int GetVoxelTypeCount() { + return VoxelRegistry.size(); + } + + public static synchronized void AddBiome(Biome biome, String name) { + Integer existing = BiomeNameToIndex.get(name); + if (existing != null) { + BiomeRegistry.set(existing, biome); + } else { + BiomeNameToIndex.put(name, BiomeRegistry.size()); + BiomeRegistry.add(biome); + } + BiomeRegistryDirty = true; + } + + public static List GetBiomeRegistry() { + return new ArrayList<>(BiomeRegistry); + } + + public static Biome GetBiome(String name) { + Integer idx = BiomeNameToIndex.get(name); + return idx == null ? null : BiomeRegistry.get(idx); + } + + public static int GetBiomeTypeID(String name) { + Integer idx = BiomeNameToIndex.get(name); + return idx == null ? -1 : idx + 1; + } + + public static int GetBiomeTypeCount() { + return BiomeRegistry.size(); + } private static SharedVoxelTerrainResources Resources; private static VoxelChunkGenerator Generator; @@ -59,7 +126,7 @@ public class VoxelWorldManager { public static int GenerationOffset = 0; public static Vector3i LastPosition = new Vector3i(0, 0, 0); - static int IterationX = 0; + static volatile int IterationX = 0; static Vector3i ChunkPos = new Vector3i(0, 0, 0); static Vector3i ChunkPos2 = new Vector3i(0, 0, 0); @@ -70,6 +137,11 @@ public class VoxelWorldManager { private static Vector3f min = new Vector3f(); private static Vector3f min2 = new Vector3f(); + public static synchronized void ResetIterationX() + { + IterationX = 0; + } + public static synchronized void GenerateChunks(Vector3i Position, Vector3i Radius, Matrix4f cameraView,Matrix4f projectionMatrix) { projectionMatrix.mul(cameraView, viewProjectionMatrix); @@ -118,6 +190,20 @@ public class VoxelWorldManager { Init(VkCtx); } + if (RegistryDirty) { + RegistryDirty = false; + Resources.UploadVoxelRegistry(VkCtx, GetVoxelRegistry()); + } + if (BiomeRegistryDirty) { + BiomeRegistryDirty = false; + Resources.UploadBiomeRegistry(VkCtx, GetBiomeRegistry()); + } + + if (VoxelRegistry.isEmpty()) { + return; // nothing to mesh against yet + } + + int generatedThisFrame = 0; while (!RequestedChunks.isEmpty() && generatedThisFrame < MAX_CHUNK_GENERATIONS_PER_FRAME) { @@ -206,19 +292,19 @@ public class VoxelWorldManager { KnownChunks.remove(pos); return true; } - 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; - } +// 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; }); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java index 5fd0dd8..7cb942b 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/DeferredRendering/DeferredSceneRender.java @@ -82,6 +82,8 @@ 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 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 PACKED_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/packed_scene_fragment_deferred.glsl"; + private static final String PACKED_FRAGMENT_SHADER_FILE_SPV = PACKED_FRAGMENT_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; @@ -246,11 +248,11 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){ if(EngineConfig.getInstance().RecompileShaders()){ 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 ? PACKED_FRAGMENT_SHADER_FILE_GLSL : 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[]{ 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 ? PACKED_FRAGMENT_SHADER_FILE_SPV : Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_SPV : FRAGMENT_SHADER_FILE_SPV,null) }; } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java index 18c6c6c..2441f62 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/RenderPasses/Forward/ForwardSceneRender.java @@ -66,6 +66,8 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering public static String SkyBoxID = "SKYBOX_TEXTURE"; private static final int PUSH_CONSTANTS_SIZE = VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.INT_SIZE; private final VulkanBuffer BufferProjectionMatrix; + private static final String PACKED_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/packed_scene_fragment.glsl"; + private static final String PACKED_FRAGMENT_SHADER_FILE_SPV = PACKED_FRAGMENT_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; @@ -293,11 +295,11 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){ if(EngineConfig.getInstance().RecompileShaders()){ 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 ? PACKED_FRAGMENT_SHADER_FILE_GLSL : 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[]{ 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 ? PACKED_FRAGMENT_SHADER_FILE_SPV : Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_SPV : FRAGMENT_SHADER_FILE_SPV,null) }; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DeviceLayers/Device.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DeviceLayers/Device.java index 3cd6bd7..91c9b2b 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DeviceLayers/Device.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DeviceLayers/Device.java @@ -54,6 +54,7 @@ public class Device { } var features12 = VkPhysicalDeviceVulkan12Features.calloc(MemStack) .sType$Default() + .shaderSampledImageArrayNonUniformIndexing(true) .scalarBlockLayout(true); var features13 = VkPhysicalDeviceVulkan13Features.calloc(MemStack)