diff --git a/.gitignore b/.gitignore index 966c12c..c725741 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,6 @@ fabric.properties /.idea/ /.gradle/buildOutputCleanup/ /.gradle/ +/resources/models/bistrohd/ +/resources/models/Cafe/ +/resources/models/Forest/ diff --git a/resources/EngineResources/SpriteShaders/sprite_fragment.glsl b/resources/EngineResources/SpriteShaders/sprite_fragment.glsl index ea509ee..1cd34ea 100644 --- a/resources/EngineResources/SpriteShaders/sprite_fragment.glsl +++ b/resources/EngineResources/SpriteShaders/sprite_fragment.glsl @@ -1,6 +1,6 @@ #version 450 -const int MAX_TEXTURES = 128; +const int MAX_TEXTURES = 512; const float GAMMA_CONST = 0.4545; layout(location = 0) in vec2 inUV; @@ -16,9 +16,12 @@ vec4 gamma(vec4 color){ } void main() { + if (push_constants.textureIndex >= MAX_TEXTURES){ + outColor = vec4(0.0,0.0,1.0,1.0); + return; + } vec4 tex = texture(spriteTextures[push_constants.textureIndex], inUV); outColor = gamma(tex); - if (outColor.a <= 0.09) { discard; } diff --git a/resources/EngineResources/shaders/lighting_vertex.glsl b/resources/EngineResources/shaders/basic_screen_vertex.glsl similarity index 100% rename from resources/EngineResources/shaders/lighting_vertex.glsl rename to resources/EngineResources/shaders/basic_screen_vertex.glsl diff --git a/resources/EngineResources/shaders/lighting_frag.glsl b/resources/EngineResources/shaders/lighting_frag.glsl index 8108408..6fe8fc3 100644 --- a/resources/EngineResources/shaders/lighting_frag.glsl +++ b/resources/EngineResources/shaders/lighting_frag.glsl @@ -26,6 +26,7 @@ layout(set = 0, binding = 3) uniform sampler2D pbrSampler; layout(set = 0, binding = 4) uniform sampler2D emissiveSampler; layout(set = 0, binding = 5) uniform sampler2D TranslucencySampler; layout(set = 0, binding = 6) uniform sampler2D OpacitySampler; +layout(set = 0, binding = 7) uniform sampler2D ssaoBlur; layout(scalar, set = 1, binding = 0) readonly buffer Lights { Light lights[]; @@ -134,6 +135,10 @@ void main() { vec3 translucency = texture(TranslucencySampler, inTextCoord).rgb; float emissiveness = emissive.r; +// outFragColor = vec4(vec3(texture(ssaoBlur, inTextCoord).r), 1); +// return; + + float ssao = texture(ssaoBlur, inTextCoord).r; float roughness = pbr.g; float metallic = pbr.b; @@ -153,8 +158,10 @@ void main() { Lo += calculatePointLight(light, worldPos, V, N, F0, albedo, metallic, roughness); } } - vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity; - outFragColor = vec4(Lo + ambient + vec3(emissiveness), 1.0f); + vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity * vec3(ssao,ssao,ssao);; + if(emissive.x > 0 || emissive.y > 0 || emissive.z > 0) ambient = emissive; + outFragColor = vec4(Lo + ambient, 1.0f); + outFragColor = vec4(outFragColor.xyz/2 + (outFragColor.xyz/2) * vec3(ssao,ssao,ssao),1); // outFragColor = vec4(color, 1.0f); if (length(normal) < 0.001) { diff --git a/resources/EngineResources/shaders/lighting_frag.glsl.spv b/resources/EngineResources/shaders/lighting_frag.glsl.spv index 067478a..caffa84 100644 Binary files a/resources/EngineResources/shaders/lighting_frag.glsl.spv and b/resources/EngineResources/shaders/lighting_frag.glsl.spv differ diff --git a/resources/EngineResources/shaders/lighting_vertex.glsl.spv b/resources/EngineResources/shaders/lighting_vertex.glsl.spv deleted file mode 100644 index 60c1597..0000000 Binary files a/resources/EngineResources/shaders/lighting_vertex.glsl.spv and /dev/null differ diff --git a/resources/EngineResources/shaders/lighting_with_shadows_frag.glsl b/resources/EngineResources/shaders/lighting_with_shadows_frag.glsl index 81c739c..17d3d13 100644 --- a/resources/EngineResources/shaders/lighting_with_shadows_frag.glsl +++ b/resources/EngineResources/shaders/lighting_with_shadows_frag.glsl @@ -30,7 +30,8 @@ layout(set = 0, binding = 3) uniform sampler2D pbrSampler; layout(set = 0, binding = 4) uniform sampler2D emissiveSampler; layout(set = 0, binding = 5) uniform sampler2D TranslucencySampler; layout(set = 0, binding = 6) uniform sampler2D OpacitySampler; -layout(set = 0, binding = 7) uniform sampler2DArray shadowSampler; +layout(set = 0, binding = 7) uniform sampler2D ssaoBlur; +layout(set = 0, binding = 8) uniform sampler2DArray shadowSampler; layout(scalar, set = 1, binding = 0) readonly buffer Lights { @@ -203,6 +204,7 @@ void main() { float emissiveness = emissive.r; float translucencyf = translucency.r; + float ssao = texture(ssaoBlur, inTextCoord).r; // outFragColor = vec4(emissive,1); // return; @@ -240,9 +242,10 @@ void main() { Lo += calculatePointLight(light, worldPos, V, N, F0, albedo, metallic, roughness); } } - vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity; + vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity * vec3(ssao,ssao,ssao);; if(emissive.x > 0 || emissive.y > 0 || emissive.z > 0) ambient = emissive; outFragColor = vec4(Lo + ambient, 1.0f); + outFragColor = vec4(outFragColor.xyz/2 + (outFragColor.xyz/2) * vec3(ssao,ssao,ssao),1); if (DEBUG_SHADOWS == 1) { switch (cascadeIndex) { diff --git a/resources/EngineResources/shaders/post_process_vtx.glsl b/resources/EngineResources/shaders/post_process_vtx.glsl deleted file mode 100644 index bcc462a..0000000 --- a/resources/EngineResources/shaders/post_process_vtx.glsl +++ /dev/null @@ -1,9 +0,0 @@ -#version 450 - -layout(location = 0 ) out vec2 outTextCoord; - -void main() -{ - outTextCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outTextCoord.x * 2.0f - 1.0f, outTextCoord.y * -2.0f + 1.0f,0.0f,1.0f); -} \ No newline at end of file diff --git a/resources/EngineResources/shaders/post_process_vtx.glsl.spv b/resources/EngineResources/shaders/post_process_vtx.glsl.spv deleted file mode 100644 index 3f2126a..0000000 Binary files a/resources/EngineResources/shaders/post_process_vtx.glsl.spv and /dev/null differ diff --git a/resources/EngineResources/shaders/scene_fragment.glsl b/resources/EngineResources/shaders/scene_fragment.glsl index 87eb92c..5b3d90b 100644 --- a/resources/EngineResources/shaders/scene_fragment.glsl +++ b/resources/EngineResources/shaders/scene_fragment.glsl @@ -1,6 +1,6 @@ #version 450 -const int MAX_TEXTURES = 256; +const int MAX_TEXTURES = 512; layout(location = 0) in vec4 inPos; layout(location = 1) in vec3 inNormal; @@ -44,7 +44,12 @@ layout(push_constant) uniform pc{ void main() { - + Material material = matUniform.materials[inMaterialIdx]; + int textureIndex = int(material.textureIdx); + if (textureIndex >= MAX_TEXTURES){ + outAlbedo = vec4(0.0,0.0,1.0,1.0); + return; + } Material material = matUniform.materials[push_constants.materialIdx]; if(material.hasTexture == 1){ vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords); diff --git a/resources/EngineResources/shaders/scene_fragment_deferred.glsl b/resources/EngineResources/shaders/scene_fragment_deferred.glsl index 2392663..32093e7 100644 --- a/resources/EngineResources/shaders/scene_fragment_deferred.glsl +++ b/resources/EngineResources/shaders/scene_fragment_deferred.glsl @@ -1,6 +1,7 @@ #version 450 -const int MAX_TEXTURES = 256; +const int MAX_TEXTURES = 512; + layout(location = 0) in vec4 inPos; layout(location = 1) in vec3 inNormal; @@ -62,6 +63,16 @@ void main() outPos = inPos; Material material = matUniform.materials[push_constants.materialIdx]; + int textureIndex = int(material.textureIdx); + if (textureIndex >= 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[material.textureIdx], inTextCoords); } else { diff --git a/resources/EngineResources/shaders/scene_fragment_deferred.glsl.spv b/resources/EngineResources/shaders/scene_fragment_deferred.glsl.spv index 2e37b81..4240da6 100644 Binary files a/resources/EngineResources/shaders/scene_fragment_deferred.glsl.spv and b/resources/EngineResources/shaders/scene_fragment_deferred.glsl.spv differ diff --git a/resources/EngineResources/shaders/scene_opaque_fragment.glsl b/resources/EngineResources/shaders/scene_opaque_fragment.glsl index f8290eb..e981d77 100644 --- a/resources/EngineResources/shaders/scene_opaque_fragment.glsl +++ b/resources/EngineResources/shaders/scene_opaque_fragment.glsl @@ -1,6 +1,7 @@ #version 450 -const int MAX_TEXTURES = 256; +const int MAX_TEXTURES = 512; + layout(location = 0) in vec4 inPos; layout(location = 1) in vec3 inNormal; @@ -44,6 +45,11 @@ layout(push_constant) uniform pc{ void main() { Material material = matUniform.materials[push_constants.materialIdx]; + int textureIndex = int(material.textureIdx); + if (textureIndex >= MAX_TEXTURES){ + outAlbedo = vec4(0.0,0.0,1.0,1.0); + return; + } if(material.hasTexture == 1){ vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords); outAlbedo = texColor; diff --git a/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl b/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl index d91d780..01df0da 100644 --- a/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl +++ b/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl @@ -1,6 +1,6 @@ #version 450 -const int MAX_TEXTURES = 256; +const int MAX_TEXTURES = 512; layout(location = 0) in vec4 inPos; layout(location = 1) in vec3 inNormal; @@ -69,6 +69,16 @@ void main() outPos = inPos; Material material = matUniform.materials[push_constants.materialIdx]; + int textureIndex = int(material.textureIdx); + if (textureIndex >= 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[material.textureIdx], inTextCoords); } else { diff --git a/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl.spv b/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl.spv index a4f90f2..34ff06d 100644 Binary files a/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl.spv and b/resources/EngineResources/shaders/scene_opaque_fragment_deferred.glsl.spv differ diff --git a/resources/EngineResources/shaders/scene_translucent_fragment.glsl b/resources/EngineResources/shaders/scene_translucent_fragment.glsl index 847195f..9af83fc 100644 --- a/resources/EngineResources/shaders/scene_translucent_fragment.glsl +++ b/resources/EngineResources/shaders/scene_translucent_fragment.glsl @@ -1,6 +1,6 @@ #version 450 -const int MAX_TEXTURES = 256; +const int MAX_TEXTURES = 512; layout(location = 0) in vec4 inPos; layout(location = 1) in vec3 inNormal; @@ -43,6 +43,11 @@ layout(push_constant) uniform pc{ void main() { Material material = matUniform.materials[push_constants.materialIdx]; + int textureIndex = int(material.textureIdx); + if (textureIndex >= MAX_TEXTURES){ + outAlbedo = vec4(0.0,0.0,1.0,1.0); + return; + } if(material.hasTexture == 1){ vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords); outAlbedo = texColor; @@ -60,4 +65,5 @@ void main() if(opacityf >= 0.9){discard;} outAlbedo = vec4(outAlbedo.rgb, opacityf); + } \ No newline at end of file diff --git a/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl b/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl index 58d8529..ce01b25 100644 --- a/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl +++ b/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl @@ -1,6 +1,6 @@ #version 450 -const int MAX_TEXTURES = 256; +const int MAX_TEXTURES = 512; layout(location = 0) in vec4 inPos; layout(location = 1) in vec3 inNormal; @@ -69,8 +69,17 @@ layout(push_constant) uniform pc { void main() { outPos = inPos; - Material material = matUniform.materials[push_constants.materialIdx]; + int textureIndex = int(material.textureIdx); + if (textureIndex >= 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[material.textureIdx], inTextCoords); } else { diff --git a/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl.spv b/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl.spv index 960f751..054991c 100644 Binary files a/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl.spv and b/resources/EngineResources/shaders/scene_translucent_fragment_deferred.glsl.spv differ diff --git a/resources/EngineResources/shaders/screen_space_fog.glsl b/resources/EngineResources/shaders/screen_space_fog.glsl new file mode 100644 index 0000000..3741c8f --- /dev/null +++ b/resources/EngineResources/shaders/screen_space_fog.glsl @@ -0,0 +1,104 @@ +#version 450 + +layout(location = 0) in vec2 inTextCoord; +layout(location = 0) out float outAO; + +layout(set = 0, binding = 0) uniform sampler2D posSampler; +layout(set = 0, binding = 1) uniform sampler2D normalSampler; +layout(set = 0, binding = 2) uniform sampler2D noiseSampler; + +layout(set = 1, binding = 0) readonly buffer SSAOKernel { + vec4 samples[]; +} kernel; + +layout(set = 2, binding = 0) uniform SSAOInfo { + mat4 projection; //64 + mat4 view; //128 + vec2 screenSize; // 136 + float radius; //140 + float bias; //144 + int kernelSize; //160 +} ssao; + +void main() { + vec2 uv = inTextCoord; + + vec3 worldPos = texture(posSampler, uv).xyz; + vec3 worldNormal = normalize(texture(normalSampler, uv).xyz); + + + if (length(worldNormal) < 0.001) { + outAO = 1.0; + return; + } + + vec3 fragPos = vec3(ssao.view * vec4(worldPos, 1.0)); + vec3 normal = normalize(mat3(ssao.view) * worldNormal); + + vec2 noiseScale = ssao.screenSize / 4.0; + vec3 randomVec = normalize(texture(noiseSampler, inTextCoord * noiseScale).xyz); + + + vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 TBN = mat3(tangent, bitangent, normal); + + float occlusion = 0.0; + float validSamples = 0.0;; + + for (int i = 0; i < ssao.kernelSize; i++) { + vec3 samplePos = TBN * kernel.samples[i].xyz; + samplePos = fragPos + samplePos * ssao.radius; + + vec4 offset = vec4(samplePos, 1.0); + offset = ssao.projection * offset; + offset.xyz /= offset.w; + offset.xyz = offset.xyz * 0.5 + 0.5; + + vec2 sampleUV = offset.xy; + sampleUV.y = 1.0 - sampleUV.y; + + if (sampleUV.x < 0.0 || sampleUV.x > 1.0 || + sampleUV.y < 0.0 || sampleUV.y > 1.0) { + continue; + } + + vec3 sampleWorldPos = texture(posSampler, sampleUV).xyz; + vec3 sampleWorldNormal = texture(normalSampler, sampleUV).xyz; + + if (length(sampleWorldNormal) < 0.001) { + continue; + } + + vec3 sampleViewPos = vec3(ssao.view * vec4(sampleWorldPos, 1.0)); + + float depthDelta = abs(fragPos.z - sampleViewPos.z); + + occlusion += abs(fragPos.z)/200.0f; + validSamples += 1.0; + continue; + + if (depthDelta > ssao.radius) { + continue; + } + + float rangeCheck = 1.0 - depthDelta / ssao.radius; + rangeCheck = rangeCheck * rangeCheck * (3.0 - 2.0 * rangeCheck); + + + + if (sampleViewPos.z >= samplePos.z + ssao.bias) { + occlusion += rangeCheck; + } + + validSamples += 1.0; + } + + if (validSamples <= 0.0) { + outAO = 1.0; + return; + } + + occlusion = 1.0 - occlusion / validSamples; + outAO = clamp(occlusion, 0.0, 1.0); +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/shadow_frag.glsl b/resources/EngineResources/shaders/shadow_frag.glsl index 0ba66bb..c65bc1a 100644 --- a/resources/EngineResources/shaders/shadow_frag.glsl +++ b/resources/EngineResources/shaders/shadow_frag.glsl @@ -1,7 +1,7 @@ #version 450 // Keep in sync manually with Java code -const int MAX_TEXTURES = 256; +const int MAX_TEXTURES = 512; layout (location = 0) in vec2 inTextCoords; layout (location = 1) in flat uint inMaterialIdx; @@ -36,6 +36,11 @@ layout(set = 2, binding = 0) readonly buffer MaterialUniform { void main() { Material material = matUniform.materials[inMaterialIdx]; + int textureIndex = int(material.textureIdx); + if (textureIndex >= MAX_TEXTURES){ + outFragColor = vec2(0.0,0.0); + return; + } vec4 albedo; if (material.hasTexture == 1) { albedo = texture(textSampler[material.textureIdx], inTextCoords); diff --git a/resources/EngineResources/shaders/ssao_blur_frag.glsl b/resources/EngineResources/shaders/ssao_blur_frag.glsl new file mode 100644 index 0000000..c16af41 --- /dev/null +++ b/resources/EngineResources/shaders/ssao_blur_frag.glsl @@ -0,0 +1,21 @@ +#version 450 + +layout(location = 0) in vec2 inTextCoord; +layout(location = 0) out float outAO; + +layout(set = 0, binding = 0) uniform sampler2D ssaoSampler; + +void main() { + + vec2 texelSize = 1.0 / vec2(textureSize(ssaoSampler, 0)); + float result = 0.0; + + for (int x = -2; x <= 2; x++) { + for (int y = -2; y <= 2; y++) { + vec2 offset = vec2(float(x), float(y)) * texelSize; + result += texture(ssaoSampler, vec2(inTextCoord.x,inTextCoord.y) + offset).r; + } + } + + outAO = result / 25.0; +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/ssao_frag.glsl b/resources/EngineResources/shaders/ssao_frag.glsl new file mode 100644 index 0000000..7c0e5f0 --- /dev/null +++ b/resources/EngineResources/shaders/ssao_frag.glsl @@ -0,0 +1,95 @@ +#version 450 + +layout(location = 0) in vec2 inTextCoord; +layout(location = 0) out float outAO; + +layout(set = 0, binding = 0) uniform sampler2D posSampler; +layout(set = 0, binding = 1) uniform sampler2D normalSampler; +layout(set = 0, binding = 2) uniform sampler2D noiseSampler; + +layout(set = 1, binding = 0) readonly buffer SSAOKernel { + vec4 samples[]; +} kernel; + +layout(set = 2, binding = 0) uniform SSAOInfo { + mat4 projection; //64 + mat4 view; //128 + vec2 screenSize; // 136 + float radius; //140 + float bias; //144 + int kernelSize; //160 +} ssao; + +void main() { + vec2 uv = inTextCoord; + + vec3 worldPos = texture(posSampler, uv).xyz; + vec3 worldNormal = normalize(texture(normalSampler, uv).xyz); + + vec2 noiseScale = ssao.screenSize / 4.0; + + if (length(worldNormal) < 0.001) { + outAO = 1.0; + return; + } + + vec3 fragPos = vec3(ssao.view * vec4(worldPos, 1.0)); + vec3 normal = normalize(mat3(ssao.view) * worldNormal); + + vec3 randomVec = normalize(texture(noiseSampler, inTextCoord * noiseScale).xyz); + + vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 TBN = mat3(tangent, bitangent, normal); + + float occlusion = 0.0; + float validSamples = 0.0;; + + for (int i = 0; i < ssao.kernelSize; i++) { + vec3 samplePos = TBN * kernel.samples[i].xyz; + samplePos = fragPos + samplePos * ssao.radius; + + vec4 offset = vec4(samplePos, 1.0); + offset = ssao.projection * offset; + offset.xyz /= offset.w; + offset.xyz = offset.xyz * 0.5 + 0.5; + + vec2 sampleUV = offset.xy; + sampleUV.y = 1 - sampleUV.y; + + if (sampleUV.x < 0.0 || sampleUV.x > 1.0 || + sampleUV.y < 0.0 || sampleUV.y > 1.0) { + continue; + } + + vec3 sampleWorldPos = texture(posSampler, sampleUV).xyz; + vec3 sampleWorldNormal = texture(normalSampler, sampleUV).xyz; + + if (length(sampleWorldNormal) < 0.001) { + continue; + } + + vec3 sampleViewPos = vec3(ssao.view * vec4(sampleWorldPos, 1.0)); + + float depthDelta = abs(fragPos.z - sampleViewPos.z); + if (depthDelta > ssao.radius) { + continue; + } + + float rangeCheck = 1.0 - depthDelta / ssao.radius; + rangeCheck = rangeCheck * rangeCheck * (3.0 - 2.0 * rangeCheck); + + if (sampleViewPos.z >= samplePos.z + ssao.bias) { + occlusion += rangeCheck; + } + validSamples += 1; + } + + if (validSamples <= 0.0) { + outAO = 1.0; + return; + } + + occlusion = 1.0 - occlusion / validSamples; + outAO = occlusion * pow(occlusion, 3.0); +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/swap_vtx.glsl b/resources/EngineResources/shaders/swap_vtx.glsl deleted file mode 100644 index ebbaca0..0000000 --- a/resources/EngineResources/shaders/swap_vtx.glsl +++ /dev/null @@ -1,8 +0,0 @@ -#version 450 - -layout(location = 0) out vec2 outTextCoord; - -void main() { - outTextCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outTextCoord.x * 2.0f - 1.0f, outTextCoord.y * -2.0f + 1.0f,0.0f,1.0f); -} diff --git a/resources/EngineResources/shaders/swap_vtx.glsl.spv b/resources/EngineResources/shaders/swap_vtx.glsl.spv deleted file mode 100644 index 3f2126a..0000000 Binary files a/resources/EngineResources/shaders/swap_vtx.glsl.spv and /dev/null differ 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 a1a9ebc..adac3c7 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/VulkanRenderer.java @@ -12,6 +12,7 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRe import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.TextureCache; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.PostProcessing.PostProcess; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.ScreenSpace.AmbientOcclusionRenderer; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shadows.ShadowRenderer; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.*; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.SpriteRendering.SpriteRenderer; @@ -51,6 +52,7 @@ public class VulkanRenderer implements Renderer { private final Queue.PresentQueue PresentQueue; private final Semaphore[] RenderCompleteSemaphores; private final SceneRenderer sceneRender; + private final AmbientOcclusionRenderer ssaoRenderer; private final SpriteRenderer spriteRenderer; private final LightRenderer lightRenderer; private final PostProcess PostProcessor; @@ -110,13 +112,16 @@ public class VulkanRenderer implements Renderer { if(Deferred) { sceneRender = new DeferredSceneRender(RendererContext, engineInstance); shadowRender = new ShadowRenderer(RendererContext); + ssaoRenderer = new AmbientOcclusionRenderer(RendererContext,sceneRender.GetMRTAttachments().GetColourAttachments(), GraphicsQueue); List attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments()); + attachments.add(ssaoRenderer.getSSAOBlurAttachment()); attachments.add(shadowRender.getShadowAttachment()); lightRenderer = new LightRenderer(RendererContext, attachments); PostProcessor = new PostProcess(RendererContext, lightRenderer.getAttachment()); } else{ sceneRender = new ForwardSceneRender(RendererContext); + ssaoRenderer = null; PostProcessor = new PostProcess(RendererContext, sceneRender.GetAttachmentColour()); lightRenderer = null; shadowRender = null; @@ -189,6 +194,7 @@ public class VulkanRenderer implements Renderer { RendererContext.GetDevice().waitIdle(); Logger.debug("Waiting Vulkan Context"); sceneRender.cleanup(RendererContext); + if(ssaoRenderer != null)ssaoRenderer.cleanup(RendererContext); if(shadowRender != null)shadowRender.cleanup(RendererContext); if(lightRenderer != null)lightRenderer.cleanup(RendererContext); PostProcessor.CleanUp(RendererContext); @@ -231,16 +237,15 @@ public class VulkanRenderer implements Renderer { sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame); boolean RenderShadows = ShadowRenderer.AllowShadowRendering() && EngineConfig.getInstance().RenderShadows(); - //lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), shadowRender.getShadowAttachment(), CurrentFrame, shadowRender.getCascadeShadows(CurrentFrame)); + if(RenderShadows) {shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); } + ssaoRenderer.Render(RendererContext,engineInstance, CommandBuffer, sceneRender.GetMRTAttachments(), CurrentFrame); if(RenderShadows) { - shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); - lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), shadowRender.getShadowAttachment(), CurrentFrame, shadowRender.getCascadeShadows(CurrentFrame)); - } else lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(),CurrentFrame); + lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), + shadowRender.getShadowAttachment(), ssaoRenderer.getSSAOBlurAttachment(), CurrentFrame, shadowRender.getCascadeShadows(CurrentFrame)); + } else lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(),ssaoRenderer.getSSAOBlurAttachment(),CurrentFrame); PostProcessor.Render(RendererContext,CommandBuffer,lightRenderer.getAttachment()); spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame); GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment()); - - swapChainRender.Render(RendererContext,CommandBuffer,PostProcessor.GetAttachment(),ImageIndex); RecordingStop(CommandBuffer); @@ -302,6 +307,7 @@ public class VulkanRenderer implements Renderer { shadowRender.RebuildPipelineAndRenderingAttachments(RendererContext); List attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments()); + attachments.add(ssaoRenderer.getSSAOBlurAttachment()); attachments.add(shadowRender.getShadowAttachment()); lightRenderer.updateAttachmentDescriptors(RendererContext, attachments); @@ -332,6 +338,11 @@ public class VulkanRenderer implements Renderer { sceneRender.Resize(engineInstance,RendererContext); if(Deferred) { List attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments()); + List ssaoAttachments = new ArrayList<>(); + ssaoAttachments.add(attachments.get(0)); + ssaoAttachments.add(attachments.get(2)); + ssaoRenderer.resize(RendererContext, ssaoAttachments); + attachments.add(ssaoRenderer.getSSAOBlurAttachment()); attachments.add(shadowRender.getShadowAttachment()); lightRenderer.resize(RendererContext, attachments); PostProcessor.Resize(RendererContext, lightRenderer.getAttachment()); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Rendering/ModelCompiler.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Rendering/ModelCompiler.java index 4053f10..e542260 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Rendering/ModelCompiler.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Rendering/ModelCompiler.java @@ -122,6 +122,7 @@ public class ModelCompiler { String NormalTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_NORMALS); String EmissiveTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_EMISSIVE); String TranslucencyTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_TRANSMISSION); + String SpecularTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_SPECULAR); String MetallicRoughTexture = ProcessTexture(aiScene, aiMaterial, BaseDirectory, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); String OpacityTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_OPACITY); @@ -132,6 +133,18 @@ public class ModelCompiler { MetallicArray = new float[]{0.0f}; } + float[] SpecularArray = new float[]{0.0f}; + Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_SPECULAR_FACTOR,aiTextureType_NONE,0,SpecularArray,MaxPointer); + if(Result != aiReturn_SUCCESS){ + SpecularArray = new float[]{0.0f}; + } + + if(MetallicArray[0] == 0.0f && SpecularArray[0] != 0.0f) + MetallicArray[0] = SpecularArray[0]; + if(MetallicRoughTexture.isEmpty()){ + MetallicRoughTexture = SpecularTexture; + } + float[] RoughnessArray = new float[]{0.0f}; Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_ROUGHNESS_FACTOR,aiTextureType_NONE,0,RoughnessArray,MaxPointer); if(Result != aiReturn_SUCCESS){ @@ -151,13 +164,32 @@ public class ModelCompiler { } float[] OpacityArray = new float[]{0.0f}; - Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_OPACITY,aiTextureType_NONE,0,OpacityArray,MaxPointer); if(Result != aiReturn_SUCCESS){ OpacityArray = new float[]{0.0f}; } - return new MaterialData(ModelName + "-mat-" + Position,DiffuseTexture,NormalTexture, MetallicRoughTexture,diffuse,RoughnessArray[0],MetallicArray[0], EmissiveTexture,emissiveColour, TranslucencyTexture, TranslucencyArray[0], OpacityTexture, OpacityArray[0]); + float[] RefractionArray = new float[]{0.0f}; + Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_REFRACTI,aiTextureType_NONE,0,RefractionArray,MaxPointer); + if(Result != aiReturn_SUCCESS){ + RefractionArray = new float[]{0.0f}; + } + + float[] ReflectionArray = new float[]{0.0f}; + Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_REFLECTIVITY,aiTextureType_NONE,0,ReflectionArray,MaxPointer); + if(Result != aiReturn_SUCCESS){ + ReflectionArray = new float[]{0.0f}; + } + + AIColor4D colour_transparency = AIColor4D.create(); + Vector4f ColorTransparency = new Vector4f(); + + Result = aiGetMaterialColor(aiMaterial,AI_MATKEY_COLOR_TRANSPARENT,aiTextureType_NONE,0,colour_transparency); + if(Result != aiReturn_SUCCESS){ + ColorTransparency.set(colour_transparency.r(),colour_transparency.g(),colour_transparency.b(),colour_transparency.a()); + } + + return new MaterialData(ModelName + "-mat-" + Position,DiffuseTexture,NormalTexture, MetallicRoughTexture,diffuse,RoughnessArray[0],MetallicArray[0], EmissiveTexture,emissiveColour, TranslucencyTexture, TranslucencyArray[0], OpacityTexture, OpacityArray[0],ColorTransparency,RefractionArray[0], ReflectionArray[0]); } public static MeshData ProcessMesh(AIMesh aiMesh, List MaterialList, int MeshPosition, ModelBinaryData BinaryData) throws IOException { diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Universal/SSAO/SSAO_Utils.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Universal/SSAO/SSAO_Utils.java new file mode 100644 index 0000000..1621056 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Universal/SSAO/SSAO_Utils.java @@ -0,0 +1,52 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Universal.SSAO; + +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; +import org.joml.Vector4f; +import org.lwjgl.BufferUtils; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.Random; + +public class SSAO_Utils { + + public static FloatBuffer GenerateSampleKernel(int size, long MappedMemory) { + FloatBuffer kernel = MemoryUtil.memFloatBuffer(MappedMemory,size * 4); // vec4 alignment + Random rnd = new Random(); + + for (int i = 0; i < size; i++) { + + Vector4f sample = new Vector4f(rnd.nextFloat() * 2.0f - 1.0f,rnd.nextFloat() * 2.0f - 1.0f,rnd.nextFloat(),0); + sample = sample.normalize(); + + float scale = (float) i / (float) size; + scale = Lerp(0.1f, 1.0f, scale * scale); + sample.mul(scale); + kernel.put(sample.x); + kernel.put(sample.y); + kernel.put(sample.z); + kernel.put(0.0f); + } + return kernel; + } + + public static ByteBuffer GenerateNoiseTexture() { + ByteBuffer buffer = BufferUtils.createByteBuffer(16 * 4 * Float.BYTES); + Random rnd = new Random(); + for (int i = 0; i < 16; i++) { + float x = rnd.nextFloat() * 2.0f - 1.0f; + float y = rnd.nextFloat() * 2.0f - 1.0f; + buffer.putFloat(x); + buffer.putFloat(y); + buffer.putFloat(0.0f); + buffer.putFloat(0.0f); + } + buffer.flip(); + return buffer; + } + + private static float Lerp(float a, float b, float f) { + return a + f * (b - a); + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightRenderer.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightRenderer.java index 0423e96..76c6e93 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightRenderer.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightRenderer.java @@ -50,7 +50,7 @@ public class LightRenderer { private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv"; private static final String NO_SHADOWS_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/lighting_frag.glsl"; private static final String NO_SHADOWS_FRAGMENT_SHADER_FILE_SPV = NO_SHADOWS_FRAGMENT_SHADER_FILE_GLSL + ".spv"; - private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/lighting_vertex.glsl"; + private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; private final DescriptorSetLayout AttachmentDescriptorSetLayout; @@ -69,6 +69,8 @@ public class LightRenderer { private final DescriptorSetLayout StorageDescriptorSetLayout; private final VulkanBuffer[] shadowMatrices; + private int MinimumAttachments = 9; // shadow + ssaoBlur + public LightRenderer(VulkanContext VkCtx, List attachments){ ClearValueColour = VkClearValue.calloc().color( c -> c.float32(0, 0.0f).float32(1, 0.0f).float32(2, 0.0f).float32(3, 0.0f)); @@ -84,8 +86,9 @@ public class LightRenderer { VK_BORDER_COLOR_INT_OPAQUE_BLACK, 1, true); textureSampler = new TextureSampler(VkCtx, textureSamplerInfo); int numAttachments = attachments.size(); - DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments + 1]; - for (int i = 0; i < numAttachments + 1; i++) { + if(numAttachments < MinimumAttachments) numAttachments = MinimumAttachments; + DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments]; + for (int i = 0; i < numAttachments; i++) { descSetLayouts[i] = new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, i, 1, VK_SHADER_STAGE_FRAGMENT_BIT); } AttachmentDescriptorSetLayout = new DescriptorSetLayout(VkCtx, descSetLayouts); @@ -209,7 +212,7 @@ public class LightRenderer { } - public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments,Attachment shadowAttachment, int CurrentFrame, CascadeShadows cascadeShadows) { + public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments,Attachment shadowAttachment, Attachment ssaoBlurAttachment, int CurrentFrame, CascadeShadows cascadeShadows) { try (var stack = MemoryStack.stackPush()) { VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer(); @@ -219,16 +222,6 @@ public class LightRenderer { VK_ACCESS_2_NONE, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT); - List attachments = mrtAttachments.GetColourAttachments(); - int numAttachments = attachments.size(); - for (int i = 0; i < numAttachments; i++) { - Attachment attachment = attachments.get(i); - VulkanUtils.ImageBarrier(stack, cmdHandle, attachment.GetVkImage().getVulkanImage(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, - VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, - VK_IMAGE_ASPECT_COLOR_BIT); - } VulkanUtils.ImageBarrier(stack, cmdHandle, mrtAttachments.GetDepthAttachment().GetVkImage().getVulkanImage(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, @@ -285,7 +278,7 @@ public class LightRenderer { } } - public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments, int CurrentFrame) { + public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments, Attachment SSAOattachment, int CurrentFrame) { try (var stack = MemoryStack.stackPush()) { VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer(); @@ -295,16 +288,6 @@ public class LightRenderer { VK_ACCESS_2_NONE, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT); - List attachments = mrtAttachments.GetColourAttachments(); - int numAttachments = attachments.size(); - for (int i = 0; i < numAttachments; i++) { - Attachment attachment = attachments.get(i); - VulkanUtils.ImageBarrier(stack, cmdHandle, attachment.GetVkImage().getVulkanImage(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, - VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, - VK_IMAGE_ASPECT_COLOR_BIT); - } VulkanUtils.ImageBarrier(stack, cmdHandle, mrtAttachments.GetDepthAttachment().GetVkImage().getVulkanImage(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, @@ -422,7 +405,7 @@ public class LightRenderer { DescriptorSet noShadowDescSet = VkCtx.GetDescriptorAllocator().GetDescriptorSet(DESC_ID_NOSHADOW_ATT); var noShadowImageViews = new ArrayList(); - for (int i = 0; i < attachments.size() - 1; i++) { + for (int i = 0; i < attachments.size(); i++) { noShadowImageViews.add(attachments.get(i).GetVkImageView()); } noShadowDescSet.SetImages(VkCtx.GetDevice(), noShadowImageViews, textureSampler, 0); @@ -444,7 +427,7 @@ public class LightRenderer { DescriptorSet noShadowDescSet = VkCtx.GetDescriptorAllocator().GetDescriptorSet(DESC_ID_NOSHADOW_ATT); var noShadowImageViews = new ArrayList(); - for (int i = 0; i < attachments.size() - 1; i++) { + for (int i = 0; i < attachments.size(); i++) { noShadowImageViews.add(attachments.get(i).GetVkImageView()); } noShadowDescSet.SetImages(VkCtx.GetDevice(), noShadowImageViews, textureSampler, 0); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/MultiRenderTargetAttachments.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/MultiRenderTargetAttachments.java index f542079..107ecb5 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/MultiRenderTargetAttachments.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/MultiRenderTargetAttachments.java @@ -18,7 +18,9 @@ public class MultiRenderTargetAttachments { public static final int EMISSIVE_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT; public static final int TRANSLUCECNY_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT; public static final int OPACITY_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT; - public static final int POSITION_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT; + public static final int POSITION_FORMAT = VK_FORMAT_R32G32B32A32_SFLOAT; + public static final int SSAO_RAW_ATTACHMENT = VK_FORMAT_R8_UNORM; + public static final int SSAO_BLUR_ATTACHMENT = VK_FORMAT_R8_UNORM; private final List ColourAttachments; private final Attachment DepthAttachment; private final int Height; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Attachment.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Attachment.java index a90d0b7..72c7f68 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Attachment.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Attachment.java @@ -3,12 +3,20 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline. import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView; +import org.w3c.dom.Text; import static org.lwjgl.vulkan.VK13.*; public class Attachment { private final Image VkImage; private final ImageView VkImageView; private boolean DepthAttachment; + + public Attachment(VulkanContext VkCtx, Texture ExistingImage){ + VkImageView = ExistingImage.GetImageView(); + VkImage = ExistingImage.GetImage(); + DepthAttachment = VkImageView.IsDepthImage(); + } + public Attachment(VulkanContext VkCtx, int Width, int Height, int Format, int Usage, boolean MultiSamples){ var ImageData = new Image.ImageData().Width(Width).Height(Height).Format(Format).SampleCount(EngineConfig.getInstance().GetRenderSampleCount()); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Texture.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Texture.java index fbc604d..a5e3657 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Texture.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/Texture.java @@ -44,6 +44,7 @@ public class Texture implements ITexture { .AspectMask(VK_IMAGE_ASPECT_COLOR_BIT).MipLevels(MipMapLevels); imageView = new ImageView(VkCtx.GetDevice(), image.getVulkanImage(), ImageViewData, false); } + public Image GetImage(){return image;} public boolean HasTransparency(){return Transparent;} public void SetTransparency(ByteBuffer data){ int PixelCount = data.capacity()/4; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/TextureCache.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/TextureCache.java index 552777f..149e3d9 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/TextureCache.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/Images/TextureCache.java @@ -18,7 +18,7 @@ import java.util.UUID; import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8G8B8A8_SRGB; public class TextureCache implements ITextureCache { - public static final int MAX_TEXTURES = 256; + public static final int MAX_TEXTURES = 512; private final IndexedLinkedHashMap TextureMap; private final IndexedLinkedHashMap CubemapTextures; private final List ActualTextures; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/PostProcessing/PostProcess.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/PostProcessing/PostProcess.java index 7084d99..3cc77d3 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/PostProcessing/PostProcess.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/PostProcessing/PostProcess.java @@ -35,7 +35,7 @@ public class PostProcess { private static final String MULTI_PASS_FRAGMENT_SHADER_FILE_SPV = MULTI_PASS_FRAGMENT_SHADER_FILE_GLSL + ".spv"; private static final String SINGLE_PASS_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/post_process_frag.glsl"; private static final String SINGLE_PASS_FRAGMENT_SHADER_FILE_SPV = SINGLE_PASS_FRAGMENT_SHADER_FILE_GLSL + ".spv"; - private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/post_process_vtx.glsl"; + private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; private final DescriptorSetLayout AttachmentDescriptorSetLayout; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/ScreenSpace/AmbientOcclusionRenderer.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/ScreenSpace/AmbientOcclusionRenderer.java new file mode 100644 index 0000000..552ac70 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/ScreenSpace/AmbientOcclusionRenderer.java @@ -0,0 +1,442 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.ScreenSpace; + +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; +import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; +import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Universal.SSAO.SSAO_Utils; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.EmptyVertexBufferStruct; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Image; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.ImageSrc; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Texture; +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.Shader.*; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandPool; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Queues.Queue; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.SwapChain; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.util.shaderc.Shaderc; +import org.lwjgl.vulkan.*; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.LongBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments.SSAO_BLUR_ATTACHMENT; +import static net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments.SSAO_RAW_ATTACHMENT; +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_FRAGMENT_BIT; +import static org.lwjgl.vulkan.VK13.*; + +public class AmbientOcclusionRenderer { + + private static final long SSAO_INFO_BUFFER_SIZE = + VulkanUtils.MATRIX4X4_SIZE + // projection + VulkanUtils.MATRIX4X4_SIZE + // view + VulkanUtils.VEC4_SIZE + // screenSize.xy, radius, bias + VulkanUtils.VEC4_SIZE; // kernelSize + padding + private static final int SSAO_KERNEL_SIZE = 32; + private static final float SSAO_RADIUS = 5.0f; + private static final float SSAO_BIAS = 0.15f; + private static final long SSAO_KERNEL_BUFFER_SIZE = SSAO_KERNEL_SIZE * 4L * VulkanUtils.FLOAT_SIZE; + + private static final String DESC_ID_SSAO_ATTACHMENTS = "SSAO_DESC_ID_ATTACHMENTS"; + private static final String DESC_ID_SSAO_KERNEL = "SSAO_DESC_ID_KERNEL"; + private static final String DESC_ID_SSAO_INFO = "SSAO_DESC_ID_INFO"; + private static final String DESC_ID_SSAO_BLUR_INPUT = "SSAO_DESC_ID_BLUR_INPUT"; + + private static final String BLUR_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/ssao_blur_frag.glsl"; + private static final String BLUR_FRAGMENT_SHADER_FILE_SPV = BLUR_FRAGMENT_SHADER_FILE_GLSL + ".spv"; + private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/ssao_frag.glsl"; + private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv"; + private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl"; + private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; + private Attachment ssaoAttachment; + private VkRenderingAttachmentInfo.Buffer ssaoAttachmentInfo; + private Attachment ssaoBlurAttachment; + private VkRenderingAttachmentInfo.Buffer ssaoBlurAttachmentInfo; + private final Attachment[] SSAO_ATTACHMENTS = new Attachment[2]; + + private final Pipeline ssaoPipeline; + private final Pipeline blurPipeline; + private final TextureSampler textureSampler; + + private DescriptorSetLayout ssaoAttachmentDescriptorLayout; + private DescriptorSetLayout ssaoKernelDescriptorLayout; + private DescriptorSetLayout ssaoInfoDescriptorLayout; + private DescriptorSetLayout blurDescriptorLayout; + + private final VkClearValue clearColour; + private VulkanBuffer sampleKernelBuffer; + private VkRenderingInfo ssaoRenderInfo; + private VkRenderingInfo ssaoBlurRenderInfo; + + private VulkanBuffer[] ssaoInfoBuffers; + + private Texture NoiseTexture; + private Attachment NoiseImageAttachment; + + public AmbientOcclusionRenderer(VulkanContext VkCtx, List MRTAttachments, Queue queue) { + List attachments = new ArrayList<>(); + attachments.add(MRTAttachments.get(0)); // position + attachments.add(MRTAttachments.get(2)); // normal + CreateAttachments(VkCtx); + clearColour = VkClearValue.calloc().color( + c -> c.float32(0, 0.0f).float32(1, 0.0f).float32(2, 0.0f).float32(3, 0.0f)); + ssaoAttachmentInfo = CreateColourAttachmentInfo(ssaoAttachment, clearColour); + ssaoBlurAttachmentInfo = CreateColourAttachmentInfo(ssaoBlurAttachment, clearColour); + var textureSamplerInfo = new TextureSamplerInfo(VK_SAMPLER_ADDRESS_MODE_REPEAT, + VK_BORDER_COLOR_INT_OPAQUE_BLACK, 1, true); + textureSampler = new TextureSampler(VkCtx, textureSamplerInfo); + + ByteBuffer NoiseTexturedata = SSAO_Utils.GenerateNoiseTexture(); + ImageSrc imageSrc = new ImageSrc(NoiseTexturedata, 4, 4,4); + NoiseTexture = new Texture(VkCtx,"SSAO_NOISE_SAMPLE", imageSrc,VK_FORMAT_R32G32B32A32_SFLOAT); + + var commandPool = new CommandPool(VkCtx, queue.GetQueueFamilyIndex(), false); + var commandBuffer = new CommandBuffer(VkCtx, commandPool, true, true); + commandBuffer.BeginRecording(); + NoiseTexture.RecordTextureTransition(commandBuffer); + commandBuffer.EndRecording(); + commandBuffer.SubmitAndWait(VkCtx, queue); + commandBuffer.cleanup(VkCtx,commandPool); + commandPool.cleanup(VkCtx); + + NoiseImageAttachment = new Attachment(VkCtx, NoiseTexture); + + attachments.add(NoiseImageAttachment); + + ssaoKernelDescriptorLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + 0, 1, VK_SHADER_STAGE_FRAGMENT_BIT)); + sampleKernelBuffer = VulkanUtils.CreateHostVisibleBuffer(VkCtx, SSAO_KERNEL_BUFFER_SIZE, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + DESC_ID_SSAO_KERNEL, ssaoKernelDescriptorLayout); + long MappedMemory = sampleKernelBuffer.MapMemory(VkCtx); + FloatBuffer KernelBuffer = SSAO_Utils.GenerateSampleKernel(SSAO_KERNEL_SIZE, MappedMemory); + sampleKernelBuffer.UnMapMemory(VkCtx); + + int numAttachments = attachments.size(); + DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments]; + for (int i = 0; i < numAttachments; i++) { + descSetLayouts[i] = new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, i, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + } + ssaoAttachmentDescriptorLayout = new DescriptorSetLayout(VkCtx, descSetLayouts); + CreateSSAOAttachmentDescriptorSet(VkCtx, attachments); + + ssaoInfoDescriptorLayout = new DescriptorSetLayout(VkCtx,new DescriptorSetLayout.LayoutInformation( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0,1,VK_SHADER_STAGE_FRAGMENT_BIT )); + + blurDescriptorLayout = new DescriptorSetLayout(VkCtx,new DescriptorSetLayout.LayoutInformation( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0,1,VK_SHADER_STAGE_FRAGMENT_BIT )); + + CreateBlurDescriptorSet(VkCtx); + + ssaoInfoBuffers = VulkanUtils.CreateHostVisibleBuffers(VkCtx,SSAO_INFO_BUFFER_SIZE, VulkanUtils.MAX_IN_FLIGHT, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESC_ID_SSAO_INFO,ssaoInfoDescriptorLayout); + + ssaoRenderInfo = CreateRenderInfo(ssaoAttachment, ssaoAttachmentInfo); + ssaoBlurRenderInfo = CreateRenderInfo(ssaoBlurAttachment, ssaoBlurAttachmentInfo); + + ShaderModule[] shaderModules = CreateRawShaderModules(VkCtx); + ssaoPipeline = CreatePipeline(VkCtx, shaderModules, + new DescriptorSetLayout[]{ + ssaoAttachmentDescriptorLayout, + ssaoKernelDescriptorLayout, + ssaoInfoDescriptorLayout + },false); + Arrays.stream(shaderModules).toList().forEach(shaderModule -> shaderModule.CleanUp(VkCtx)); + + shaderModules = CreateBlurShaderModules(VkCtx); + blurPipeline = CreatePipeline( VkCtx, shaderModules, + new DescriptorSetLayout[]{ blurDescriptorLayout }, + true ); + Arrays.stream(shaderModules).toList().forEach(shaderModule -> shaderModule.CleanUp(VkCtx)); + } + + + private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] shaderModules, DescriptorSetLayout[] descSetLayouts, boolean blur) { + var vtxBuffStruct = new EmptyVertexBufferStruct(); + var buildInfo = new PipelineBuildInfo(shaderModules, vtxBuffStruct.GetVertexInput(),new int[]{blur ? SSAO_BLUR_ATTACHMENT : SSAO_RAW_ATTACHMENT}) + .SetDescriptorSetLayouts(descSetLayouts) + .BlendingIsUsed(false) + .SetDepthWrite(false) + .SetDepthTest(false); + var pipeline = new DefaultPipeline(VkCtx, buildInfo); + vtxBuffStruct.CleanUp(); + return pipeline; + } + + private static ShaderModule[] CreateRawShaderModules(VulkanContext VkCtx) { + if (EngineConfig.getInstance().RecompileShaders()) { + ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader); + ShaderCompiler.CompileGLSLShaderOnChange( FRAGMENT_SHADER_FILE_GLSL , Shaderc.shaderc_glsl_fragment_shader); + } + return new ShaderModule[]{ + new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV, null), + new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, FRAGMENT_SHADER_FILE_SPV, null), + }; + } + + private static ShaderModule[] CreateBlurShaderModules(VulkanContext VkCtx) { + if (EngineConfig.getInstance().RecompileShaders()) { + ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader); + ShaderCompiler.CompileGLSLShaderOnChange( BLUR_FRAGMENT_SHADER_FILE_GLSL , Shaderc.shaderc_glsl_fragment_shader); + } + return new ShaderModule[]{ + new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV, null), + new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, BLUR_FRAGMENT_SHADER_FILE_SPV, null), + }; + } + + private static VkRenderingAttachmentInfo.Buffer CreateColourAttachmentInfo(Attachment attachment, VkClearValue clearValue) { + return VkRenderingAttachmentInfo.calloc(1) + .sType$Default() + .imageView(attachment.GetVkImageView().GetVulkanImageView()) + .imageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .loadOp(VK_ATTACHMENT_LOAD_OP_CLEAR) + .storeOp(VK_ATTACHMENT_STORE_OP_STORE) + .clearValue(clearValue); + } + + private static VkRenderingInfo CreateRenderInfo(Attachment attachment, VkRenderingAttachmentInfo.Buffer attachmentInfo) { + return VkRenderingInfo.calloc() + .sType$Default() + .renderArea(area -> area + .offset(offset -> offset.x(0).y(0)) + .extent(extent -> extent + .width(attachment.GetVkImage().GetWidth()) + .height(attachment.GetVkImage().GetHeight()))) + .layerCount(1) + .pColorAttachments(attachmentInfo); + } + + private void CreateSSAOAttachmentDescriptorSet(VulkanContext vkCtx, List Attachments ) { + DescriptorSet descSet = vkCtx.GetDescriptorAllocator().AddDescriptorSet( + vkCtx.GetDevice(), DESC_ID_SSAO_ATTACHMENTS,ssaoAttachmentDescriptorLayout ); + + List imageViews = new ArrayList<>(); + Attachments.forEach(a -> imageViews.add(a.GetVkImageView())); + + descSet.SetImages(vkCtx.GetDevice(), imageViews, textureSampler, 0); + } + + + private void CreateBlurDescriptorSet(VulkanContext vkCtx) { + DescriptorSet descSet = vkCtx.GetDescriptorAllocator().AddDescriptorSet( + vkCtx.GetDevice(),DESC_ID_SSAO_BLUR_INPUT, blurDescriptorLayout); + + descSet.SetImage(vkCtx.GetDevice(), ssaoAttachment.GetVkImageView(), + textureSampler,0); + } + + private void CreateAttachments(VulkanContext VkCtx){ + SwapChain swapChain = VkCtx.GetSwapChain(); + VkExtent2D swapChainExtent = swapChain.GetSwapChainExtent(); + //SSAO Raw + ssaoAttachment = new Attachment(VkCtx, swapChainExtent.width(), swapChainExtent.height(), SSAO_RAW_ATTACHMENT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1); + SSAO_ATTACHMENTS[0] = ssaoAttachment; + //SSAO Blur + ssaoBlurAttachment = new Attachment(VkCtx, swapChainExtent.width(), swapChainExtent.height(), SSAO_BLUR_ATTACHMENT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1); + SSAO_ATTACHMENTS[1] = ssaoBlurAttachment; + } + + public void Render(VulkanContext VkCtx,EngineInstance engineInstance, CommandBuffer cmdBuffer, MultiRenderTargetAttachments MRT,int CurrentFrame) { + try (var stack = MemoryStack.stackPush()) { + + + VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer(); + + UpdateSSAOInfo(VkCtx, engineInstance, CurrentFrame); + + VulkanUtils.ImageBarrier(stack, cmdHandle, ssaoAttachment.GetVkImage().getVulkanImage(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_2_SHADER_READ_BIT, + VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + + TransitionMRTtoReadOnly(stack, cmdHandle, MRT); + + + vkCmdBeginRendering(cmdHandle, ssaoRenderInfo); + + vkCmdBindPipeline(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, ssaoPipeline.GetVulkanPipeline()); + + SetViewportAndScissor(stack, cmdHandle, ssaoAttachment); + + DescriptorAllocator descAllocator = VkCtx.GetDescriptorAllocator(); + LongBuffer descriptorSets = stack.mallocLong(3) + .put(0, descAllocator.GetDescriptorSet(DESC_ID_SSAO_ATTACHMENTS).GetVkDescriptorSet()) + .put(1, descAllocator.GetDescriptorSet(DESC_ID_SSAO_KERNEL).GetVkDescriptorSet()) + .put(2, descAllocator.GetDescriptorSet(DESC_ID_SSAO_INFO, CurrentFrame).GetVkDescriptorSet()); + + vkCmdBindDescriptorSets(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, + ssaoPipeline.GetVulkanPipelineLayout(), 0, descriptorSets, null); + + vkCmdDraw(cmdHandle, 3, 1, 0, 0); + + vkCmdEndRendering(cmdHandle); + + //blur pass + VulkanUtils.ImageBarrier(stack, cmdHandle, ssaoAttachment.GetVkImage().getVulkanImage(), + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_2_SHADER_READ_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + + VulkanUtils.ImageBarrier(stack, cmdHandle, ssaoBlurAttachment.GetVkImage().getVulkanImage(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_2_SHADER_READ_BIT, + VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + + vkCmdBeginRendering(cmdHandle, ssaoBlurRenderInfo); + + vkCmdBindPipeline(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, blurPipeline.GetVulkanPipeline()); + + SetViewportAndScissor(stack, cmdHandle, ssaoBlurAttachment); + + LongBuffer blurDescriptorSets = stack.mallocLong(1) + .put(0, descAllocator.GetDescriptorSet(DESC_ID_SSAO_BLUR_INPUT).GetVkDescriptorSet()); + + vkCmdBindDescriptorSets(cmdHandle,VK_PIPELINE_BIND_POINT_GRAPHICS, + blurPipeline.GetVulkanPipelineLayout(),0, blurDescriptorSets,null ); + + vkCmdDraw(cmdHandle, 3, 1, 0, 0); + + vkCmdEndRendering(cmdHandle); + + VulkanUtils.ImageBarrier( stack, cmdHandle, ssaoBlurAttachment.GetVkImage().getVulkanImage(), + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_2_SHADER_READ_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + } + } + + private static void TransitionMRTtoReadOnly(MemoryStack stack,VkCommandBuffer cmdHandle, MultiRenderTargetAttachments MRT) { + List attachments = MRT.GetColourAttachments(); + + for (Attachment attachment : attachments) { + VulkanUtils.ImageBarrier( stack,cmdHandle, attachment.GetVkImage().getVulkanImage(), + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_2_SHADER_READ_BIT, + VK_IMAGE_ASPECT_COLOR_BIT + ); + } + } + + private void SetViewportAndScissor(MemoryStack stack, VkCommandBuffer cmdHandle, Attachment attachment){ + Image ColourImage = attachment.GetVkImage(); + int width = ColourImage.GetWidth(); + int height = ColourImage.GetHeight(); + var viewport = VkViewport.calloc(1, stack) + .x(0) + .y(height) + .height(-height) + .width(width) + .minDepth(0.0f) + .maxDepth(1.0f); + vkCmdSetViewport(cmdHandle, 0, viewport); + + var scissor = VkRect2D.calloc(1, stack) + .extent(it -> it.width(width).height(height)) + .offset(it -> it.x(0).y(0)); + vkCmdSetScissor(cmdHandle, 0, scissor); + } + + private void UpdateSSAOInfo(VulkanContext vkCtx, EngineInstance engineInstance, int currentFrame) { + VulkanBuffer buffer = ssaoInfoBuffers[currentFrame]; + long mappedMemory = buffer.MapMemory(vkCtx); + ByteBuffer data = MemoryUtil.memByteBuffer(mappedMemory, (int) buffer.GetRequestedSize()); + + int offset = 0; + + engineInstance.scene().GetProjection().GetProjectionMatrix().get(offset, data); + offset += VulkanUtils.MATRIX4X4_SIZE; + + engineInstance.scene().GetCamera().GetViewMatrix().get(offset, data); + offset += VulkanUtils.MATRIX4X4_SIZE; + + data.putFloat(offset, ssaoAttachment.GetVkImage().GetWidth()); + data.putFloat(offset + VulkanUtils.FLOAT_SIZE, ssaoAttachment.GetVkImage().GetHeight()); + data.putFloat(offset + VulkanUtils.FLOAT_SIZE * 2, SSAO_RADIUS); + data.putFloat(offset + VulkanUtils.FLOAT_SIZE * 3, SSAO_BIAS); + offset += VulkanUtils.VEC4_SIZE; + + data.putInt(offset, SSAO_KERNEL_SIZE); + + buffer.UnMapMemory(vkCtx); + } + + public Attachment getSSAOBlurAttachment() { + return ssaoBlurAttachment; + } + + public void resize(VulkanContext VkCtx, List attachments) { + ssaoRenderInfo.free(); + ssaoBlurRenderInfo.free(); + ssaoAttachmentInfo.free(); + ssaoAttachment.CleanUp(VkCtx); + ssaoBlurAttachmentInfo.free(); + ssaoBlurAttachment.CleanUp(VkCtx); + + CreateAttachments(VkCtx); + + ssaoAttachmentInfo = CreateColourAttachmentInfo(ssaoAttachment, clearColour); + ssaoBlurAttachmentInfo = CreateColourAttachmentInfo(ssaoBlurAttachment, clearColour); + ssaoRenderInfo = CreateRenderInfo(ssaoAttachment, ssaoAttachmentInfo); + ssaoBlurRenderInfo = CreateRenderInfo(ssaoBlurAttachment, ssaoBlurAttachmentInfo); + + attachments.add(NoiseImageAttachment); + + CreateSSAOAttachmentDescriptorSet(VkCtx,attachments); + CreateBlurDescriptorSet(VkCtx); + } + + public void cleanup(VulkanContext VkCtx) { + ssaoRenderInfo.free(); + ssaoBlurRenderInfo.free(); + ssaoAttachmentInfo.free(); + ssaoAttachment.CleanUp(VkCtx); + ssaoBlurAttachmentInfo.free(); + ssaoBlurAttachment.CleanUp(VkCtx); + ssaoPipeline.CleanUp(VkCtx); + blurPipeline.CleanUp(VkCtx); + clearColour.free(); + Arrays.stream(ssaoInfoBuffers).toList().forEach(b -> b.cleanup(VkCtx)); + sampleKernelBuffer.cleanup(VkCtx); + ssaoAttachmentDescriptorLayout.CleanUp(VkCtx); + blurDescriptorLayout.CleanUp(VkCtx); + ssaoInfoDescriptorLayout.CleanUp(VkCtx); + ssaoKernelDescriptorLayout.CleanUp(VkCtx); + NoiseTexture.CleanUp(VkCtx); + textureSampler.CleanUp(VkCtx); + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java index fb5d281..41e990f 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shader/DescriptorSet.java @@ -1,5 +1,6 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.TextureCache; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer; @@ -100,9 +101,19 @@ public class DescriptorSet { public void SetImageArray(Device device, List imageViews, TextureSampler textureSampler, int BaseBinding){ try(var MemStack = MemoryStack.stackPush()){ int ImageCount = imageViews.size(); + if (textureSampler == null || textureSampler.GetVkSampler() == 0) { + throw new NullPointerException("The provided TextureSampler is uninitialized or null!"); + } VkDescriptorImageInfo.Buffer imageInfos = VkDescriptorImageInfo.calloc(ImageCount,MemStack); for(int i = 0; i < ImageCount; i++){ + ImageView imageView = imageViews.get(i); + if (imageView == null || imageView.GetVulkanImageView() == 0) { + Logger.error("Texture or ImageView at index " + i + " is NULL! Check your material cache loading."); + imageView = imageViews.getFirst(); + if(imageView == null || imageView.GetVulkanImageView() == 0) throw new NullPointerException("The provided TextureSampler is uninitialized or null!"); + } + VkDescriptorImageInfo imageInfo = imageInfos.get(i); imageInfo.imageView(imageView.GetVulkanImageView()).sampler(textureSampler.GetVkSampler()); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/VkModel/MaterialData.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/VkModel/MaterialData.java index b9407bc..2a90378 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/VkModel/MaterialData.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/VkModel/MaterialData.java @@ -2,5 +2,5 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel; import org.joml.Vector4f; -public record MaterialData(String ID, String TexturePath,String NormalTexturePath,String MetalRoughnessMap, Vector4f DiffuseColour,float Roughness, float Metallic, String EmissiveTexture,Vector4f EmissiveColour, String TranslucencyTexture, float Translucency, String OpacityTexture, float Opacity) { +public record MaterialData(String ID, String TexturePath,String NormalTexturePath,String MetalRoughnessMap, Vector4f DiffuseColour,float Roughness, float Metallic, String EmissiveTexture,Vector4f EmissiveColour, String TranslucencyTexture, float Translucency, String OpacityTexture, float Opacity, Vector4f ColorTransparency, float Refractiveness, float Reflectiveness) { } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/SpriteRendering/SpriteRenderer.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/SpriteRendering/SpriteRenderer.java index 2ffc790..f4553a5 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/SpriteRendering/SpriteRenderer.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/SpriteRendering/SpriteRenderer.java @@ -205,9 +205,11 @@ public class SpriteRenderer { public void LoadMaterials(VulkanContext VkCtx, MaterialsCache materialsCache, TextureCache textureCache){ DescriptorAllocator descriptorAllocator = VkCtx.GetDescriptorAllocator(); Device device = VkCtx.GetDevice(); - List imageViews = new ArrayList<>(textureCache.GetAll2DTextures().stream().map(ITexture::GetImageView).toList()); ImageView fallback = textureCache.GetTexture("resources/EngineResources/Texture/NoTexture.png").GetImageView(); + List imageViews = new ArrayList<>(); + imageViews.add(fallback); + imageViews.addAll(textureCache.GetAll2DTextures().stream().map(ITexture::GetImageView).toList()); while (imageViews.size() < TextureCache.MAX_TEXTURES) { imageViews.add(fallback); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/SwapChain/SwapChainRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/SwapChain/SwapChainRender.java index 86d40a8..4a7a869 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/SwapChain/SwapChainRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/SwapChain/SwapChainRender.java @@ -29,7 +29,7 @@ public class SwapChainRender { private static final String DESCRIPTOR_ID_ATTACHMENT = "FWD_DESC_ID_ATT"; private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/swap_frag.glsl"; private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv"; - private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/swap_vtx.glsl"; + private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; private final DescriptorSetLayout AttachmentDescriptorSetLayout; private final VkClearValue ClearValueColour; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java index 83f3e41..dbb6c87 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Util/VulkanUtils.java @@ -160,7 +160,7 @@ public class VulkanUtils { descriptorAllocator.AddDescriptorSets(device, ID, BufferCount, layout); DescriptorSetLayout.LayoutInformation LayoutInfo = layout.GetLayoutInfo(); for(int i = 0; i < BufferCount; i++){ - Result[i] = new VulkanBuffer(VkCtx, BufferSize, Usage,VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + Result[i] = new VulkanBuffer(VkCtx, BufferSize, Usage,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); DescriptorSet descriptorSet = descriptorAllocator.GetDescriptorSet(ID, i); descriptorSet.SetBuffer(device, Result[i], Result[i].GetRequestedSize(), layout.GetLayoutInfo().Binding(),layout.GetLayoutInfo().DescriptorType());