From 0d41f3e15b8830db7f403e8effce671a055175eb Mon Sep 17 00:00:00 2001 From: Halbear Date: Sun, 30 Aug 2026 01:06:23 +0100 Subject: [PATCH] Shadows, broke OpenGL, broke graphics settings, Exception raised when closing software --- .../shaders/lighting_with_shadows_frag.glsl | 233 ++++++++++++ .../multi-sampled_post_process_frag.glsl.spv | Bin 3704 -> 3704 bytes .../EngineResources/shaders/shadow_frag.glsl | 50 ++- .../shaders/shadow_geometry.glsl | 26 +- .../shaders/shadow_vertex.glsl | 22 +- .../shaders/skybox_fragment.glsl | 4 +- .../shaders/skybox_fragment.glsl.spv | Bin 1156 -> 644 bytes .../shaders/skybox_vertex.glsl | 2 +- .../shaders/skybox_vertex.glsl.spv | Bin 2452 -> 2488 bytes .../EngineCore/Display/VulkanRenderer.java | 20 +- .../EngineCore/Logic/EngineConfig.java | 5 +- .../Logic/Physics/RigidBody/RigidBody.java | 2 + .../Logic/Physics/SpatialHashGrid.java | 12 + .../Logic/Physics/StaticSpatialHashGrid.java | 15 +- .../Logic/Physics/WorldPhysicsManager.java | 17 + .../Terrain4J/EngineCore/Main/GameCore.java | 145 +++++--- .../EngineCore/Main/Scene/Light.java | 2 + .../EngineCore/Main/Scene/Scene.java | 2 +- .../Main/Scene/SceneLightingManager.java | 2 +- .../Universal/Projection/Project3D.java | 8 +- .../DeferredRendering/LightRenderer.java | 85 ++++- .../DeferredRendering/LightSpecConsts.java | 56 +++ .../MultiRenderTargetAttachments.java | 10 +- .../Rendering/Pipeline/DefaultPipeline.java | 5 +- .../Rendering/Pipeline/Images/Attachment.java | 79 +++- .../Rendering/Pipeline/PipelineBuildInfo.java | 8 + .../Vulkan/Rendering/Shadows/CascadeData.java | 27 +- .../Rendering/Shadows/ShadowRenderer.java | 342 +++++++++++++++++- .../Vulkan/Rendering/Shadows/ShadowUtils.java | 166 +++++---- .../SpriteRendering/SpriteRenderer.java | 5 +- .../Vulkan/Structure/DeviceLayers/Device.java | 19 +- .../DisplayToScreen/DeferredSceneRender.java | 4 +- .../DisplayToScreen/ForwardSceneRender.java | 2 +- .../Structure/DisplayToScreen/ImageView.java | 6 + .../EngineCore/Threads/RenderThread.java | 19 +- terrain4j.properties | 6 +- 36 files changed, 1187 insertions(+), 219 deletions(-) create mode 100644 resources/EngineResources/shaders/lighting_with_shadows_frag.glsl create mode 100644 src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightSpecConsts.java diff --git a/resources/EngineResources/shaders/lighting_with_shadows_frag.glsl b/resources/EngineResources/shaders/lighting_with_shadows_frag.glsl new file mode 100644 index 0000000..7e3f672 --- /dev/null +++ b/resources/EngineResources/shaders/lighting_with_shadows_frag.glsl @@ -0,0 +1,233 @@ +#version 450 +#extension GL_EXT_scalar_block_layout: require + +// CREDITS: Most of the functions here have been obtained from this link: https://github.com/SaschaWillems/Vulkan +// developed by Sascha Willems, https://twitter.com/JoeyDeVriez, and licensed under the terms of the MIT License (MIT) + +layout (constant_id = 0) const int SHADOW_MAP_CASCADE_COUNT = 6; +layout (constant_id = 1) const int DEBUG_SHADOWS = 0; +const float PI = 3.14159265359; + +struct Light { + vec3 position; + uint directional; + float intensity; + vec3 color; +}; +struct CascadeShadow { + mat4 projViewMatrix; + vec4 splitDistance; +}; + +layout(location = 0) in vec2 inTextCoord; + +layout(location = 0) out vec4 outFragColor; + +layout(set = 0, binding = 0) uniform sampler2D posSampler; +layout(set = 0, binding = 1) uniform sampler2D albedoSampler; +layout(set = 0, binding = 2) uniform sampler2D normalsSampler; +layout(set = 0, binding = 3) uniform sampler2D pbrSampler; +layout(set = 0, binding = 4) uniform sampler2DArray shadowSampler; + +layout(scalar, set = 1, binding = 0) readonly buffer Lights { + Light lights[]; +} lights; +layout(set = 2, binding = 0) readonly buffer Shadows { + CascadeShadow cascadeshadows[]; +} shadows; +layout(scalar, set = 3, binding = 0) uniform SceneInfo { + vec3 camPos; + float ambientLightIntensity; + vec3 ambientLightColor; + uint numLights; + mat4 viewMatrix; +} sceneInfo; + +float chebyshevUpperBound(vec2 moments, float t) { + // Surface is fully lit if the current fragment is before the light occluder + if (t <= moments.x) + return 1.0; + + // Compute variance + float variance = moments.y - (moments.x * moments.x); + variance = max(variance, 0.00002); // Small epsilon to avoid divide by zero + + // Compute probabilistic upper bound + float d = t - moments.x; + float p_max = variance / (variance + d * d); + + // Reduce light bleeding + p_max = smoothstep(0.2, 1.0, p_max); + + return p_max; +} + +float calcVisibility(vec4 worldPosition, uint cascadeIndex) { + vec4 shadowMapPosition = shadows.cascadeshadows[cascadeIndex].projViewMatrix * worldPosition; + + shadowMapPosition.xyz /= shadowMapPosition.w; + + vec2 uv = vec2( + shadowMapPosition.x * 0.5 + 0.5, + shadowMapPosition.y * -0.5 + 0.5 + ); + + float depth = shadowMapPosition.z; + + if (uv.x < 0.0 || uv.x > 1.0 || + uv.y < 0.0 || uv.y > 1.0 || + depth < 0.0 || depth > 1.0) { + return 1.0; + } + + vec2 moments = texture(shadowSampler, vec3(uv, cascadeIndex)).rg; + + float visibility = chebyshevUpperBound(moments, depth); + return visibility; +} + +float distributionGGX(vec3 N, vec3 H, float roughness) { + float a = roughness * roughness; + float a2 = a * a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH * NdotH; + + float nom = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return nom / denom; +} + +float geometrySchlickGGX(float NdotV, float roughness) { + float r = (roughness + 1.0); + float k = (r * r) / 8.0; + + float nom = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return nom / denom; +} + +float geometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = geometrySchlickGGX(NdotV, roughness); + float ggx1 = geometrySchlickGGX(NdotL, roughness); + + return ggx1 * ggx2; +} + +vec3 fresnelSchlick(float cosTheta, vec3 F0) { + return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); +} + +vec3 calculatePointLight(Light light, vec3 worldPos, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) { + vec3 tmpSub = light.position - worldPos; + vec3 L = normalize(tmpSub); + vec3 H = normalize(V + L); + + // Calculate distance and attenuation + float distance = length(tmpSub); + float attenuation = 1.0 / (distance * distance); + float intensity = 10.0f; + vec3 radiance = light.color * light.intensity * attenuation; + + // Cook-Torrance BRDF + float NDF = distributionGGX(N, H, roughness); + float G = geometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); + + vec3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; + vec3 specular = numerator / denominator; + + vec3 kS = F; + vec3 kD = vec3(1.0) - kS; + kD *= 1.0 - metallic; + + float NdotL = max(dot(N, L), 0.0); + return (kD * albedo / PI + specular) * radiance * NdotL; +} + +vec3 calculateDirectionalLight(Light light, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) { + vec3 L = normalize(-light.position); + vec3 H = normalize(V + L); + + vec3 radiance = light.color * light.intensity; + + // Cook-Torrance BRDF + float NDF = distributionGGX(N, H, roughness); + float G = geometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); + + vec3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; + vec3 specular = numerator / denominator; + + vec3 kS = F; + vec3 kD = vec3(1.0) - kS; + kD *= 1.0 - metallic; + + float NdotL = max(dot(N, L), 0.0); + return (kD * albedo / PI + specular) * radiance * NdotL; +} + +void main() { + vec3 albedo = texture(albedoSampler, inTextCoord).rgb; + vec3 normal = texture(normalsSampler, inTextCoord).rgb; + vec4 worldPosW = texture(posSampler, inTextCoord); + vec3 worldPos = worldPosW.xyz; + vec3 pbr = texture(pbrSampler, inTextCoord).rgb; + + float roughness = pbr.g; + float metallic = pbr.b; + + vec3 N = normalize(normal); + vec3 V = normalize(sceneInfo.camPos - worldPos); + + vec3 F0 = vec3(0.04); + F0 = mix(F0, albedo, metallic); + + uint cascadeIndex = 0; + vec4 viewPos = sceneInfo.viewMatrix * worldPosW; + for (uint i = 0; i < SHADOW_MAP_CASCADE_COUNT - 1; ++i) { + if (viewPos.z < shadows.cascadeshadows[i].splitDistance.x) { + cascadeIndex = i + 1; + } + } + float shadow = calcVisibility(vec4(worldPos, 1), cascadeIndex); + + vec3 Lo = vec3(0.0); + for (uint i = 0; i < sceneInfo.numLights; i++) { + Light light = lights.lights[i]; + if (light.directional == 1) { + Lo += calculateDirectionalLight(light, V, N, F0, albedo, metallic, roughness) * shadow; + } else { + Lo += calculatePointLight(light, worldPos, V, N, F0, albedo, metallic, roughness); + } + } + vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity; + outFragColor = vec4(Lo + ambient, 1.0f); + + if (DEBUG_SHADOWS == 1) { + switch (cascadeIndex) { + case 0: + outFragColor.rgb *= vec3(1.0f, 0.25f, 0.25f); + break; + case 1: + outFragColor.rgb *= vec3(0.25f, 1.0f, 0.25f); + break; + case 2: + outFragColor.rgb *= vec3(0.25f, 0.25f, 1.0f); + break; + default: + outFragColor.rgb *= vec3(1.0f, 1.0f, 0.25f); + break; + } + } + if (length(normal) < 0.001) { + outFragColor = vec4(albedo,1.0f); + return; + } +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/multi-sampled_post_process_frag.glsl.spv b/resources/EngineResources/shaders/multi-sampled_post_process_frag.glsl.spv index 2cf3d79a272ff9ca6409715b5f6f718e50d76bde..1cce2dd893b88a6ffb0ea1f049ac8a4e735226ca 100644 GIT binary patch delta 17 Ycmew%^FwBX0}D&@fhhaUE-WTo075keHUIzs delta 17 Ycmew%^FwBX0}G4gmKS!LU06)G07DlBZ2$lO diff --git a/resources/EngineResources/shaders/shadow_frag.glsl b/resources/EngineResources/shaders/shadow_frag.glsl index 0afc2bd..b0619e1 100644 --- a/resources/EngineResources/shaders/shadow_frag.glsl +++ b/resources/EngineResources/shaders/shadow_frag.glsl @@ -1,5 +1,51 @@ #version 450 -void main() { +// Keep in sync manually with Java code +const int MAX_TEXTURES = 256; -} +layout (location = 0) in vec2 inTextCoords; +layout (location = 1) in flat uint inMaterialIdx; + +layout(location = 0) out vec2 outFragColor; + +struct Material { + vec4 diffuseColor; + uint hasTexture; + uint textureIdx; + uint hasNormalMap; + uint normalMapIdx; + uint hasRoughMap; + uint roughMapIdx; + float roughnessFactor; + float metallicFactor; +}; + +layout(set = 1, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES]; +layout(set = 2, binding = 0) readonly buffer MaterialUniform { + Material materials[]; +} matUniform; + +void main() +{ + Material material = matUniform.materials[inMaterialIdx]; + vec4 albedo; + if (material.hasTexture == 1) { + albedo = texture(textSampler[material.textureIdx], inTextCoords); + } else { + albedo = material.diffuseColor; + } + if (albedo.a < 0.5) { + discard; + } + + float depth = gl_FragCoord.z; + float moment1 = depth; + float moment2 = depth * depth; + + // Adjust moments to avoid light bleeding + float dx = dFdx(depth); + float dy = dFdy(depth); + moment2 += 0.25 * (dx * dx + dy * dy); + + outFragColor = vec2(moment1, moment2); +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/shadow_geometry.glsl b/resources/EngineResources/shaders/shadow_geometry.glsl index 0afc2bd..f96fc9e 100644 --- a/resources/EngineResources/shaders/shadow_geometry.glsl +++ b/resources/EngineResources/shaders/shadow_geometry.glsl @@ -1,5 +1,29 @@ #version 450 -void main() { +#define SHADOW_MAP_CASCADE_COUNT 6 +layout (triangles, invocations = SHADOW_MAP_CASCADE_COUNT) in; +layout (triangle_strip, max_vertices = 3) out; + +layout (location = 0) in vec2 inTextCoords[]; +layout (location = 1) in flat uint inMaterialIdx[]; + +layout (location = 0) out vec2 outTextCoords; +layout (location = 1) out flat uint outMaterialIdx; + +layout(set = 0, binding = 0) uniform ProjUniforms { +mat4 projViewMatrices[SHADOW_MAP_CASCADE_COUNT]; +} projUniforms; + +void main() +{ +for (int i = 0; i < 3; i++) +{ +outTextCoords = inTextCoords[i]; +outMaterialIdx = inMaterialIdx[i]; +gl_Layer = gl_InvocationID; +gl_Position = projUniforms.projViewMatrices[gl_InvocationID] * gl_in[i].gl_Position; +EmitVertex(); } +EndPrimitive(); +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/shadow_vertex.glsl b/resources/EngineResources/shaders/shadow_vertex.glsl index 0afc2bd..55e649f 100644 --- a/resources/EngineResources/shaders/shadow_vertex.glsl +++ b/resources/EngineResources/shaders/shadow_vertex.glsl @@ -1,5 +1,23 @@ #version 450 -void main() { +layout(location = 0) in vec3 entityPos; +layout(location = 1) in vec3 entityNormal; +layout(location = 2) in vec3 entityTangent; +layout(location = 3) in vec3 entityBitangent; +layout(location = 4) in vec2 entityTextCoords; -} +layout(push_constant) uniform matrices { + mat4 modelMatrix; + uint materialIdx; +} push_constants; + +layout (location = 0) out vec2 outTextCoord; +layout (location = 1) out flat uint outMaterialIdx; + +void main() +{ + outTextCoord = entityTextCoords; + outMaterialIdx = push_constants.materialIdx; + + gl_Position = push_constants.modelMatrix * vec4(entityPos, 1.0f); +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/skybox_fragment.glsl b/resources/EngineResources/shaders/skybox_fragment.glsl index 42aa7ea..4086d0e 100644 --- a/resources/EngineResources/shaders/skybox_fragment.glsl +++ b/resources/EngineResources/shaders/skybox_fragment.glsl @@ -7,7 +7,5 @@ layout(location = 1) out vec4 outColor; layout(set = 2, binding = 0) uniform samplerCube skyboxSampler; void main() { - vec3 textureIn = texture(skyboxSampler, outTexCoords).rgb; - vec3 adjusted =vec3(0.0,textureIn.y/200.0,textureIn.z/150.0); - outColor = vec4(adjusted, 1.0); + outColor = texture(skyboxSampler, outTexCoords);// * vec4(0.0,0.05,0.1,1); } \ No newline at end of file diff --git a/resources/EngineResources/shaders/skybox_fragment.glsl.spv b/resources/EngineResources/shaders/skybox_fragment.glsl.spv index 5d6b9f82e1a1c6bd7879a9467fcf640b8589b5ab..3f18f856e0c908a4713cec4136dc9dfde1bef76b 100644 GIT binary patch delta 243 zcmXYqF$%&!5JmrH6LpcO(SVJp!NO7t1wpV$kpn1*y>`MvG$7dK0%6bMU2Hsx;2%lx znfY(#&y=PNLha3(fI=G~;wsDn10bqSPh*RFYOgj&^_e6QDZ%0LNUhD!H(F%yA=_h0 zxwV=b*%Aj=s72zlnR2Jasww`#w)T?K?xpt2AxW36A%v1dk5y5^B_UpJ3v+L8kCLKSBaoYPlu<6~8Mn-<|lQ z^4w@i%6*8zSEStIhq^GssuT`*M;+ljl!BuOyEDfpO~8BPzo?#DJeGoSBi`Vin^N#= zafr7nj63|Y|FsH zzy_rKfEXkm2vh^&`%gCH6b=XgvOIv85r_jA*ntLuQ~+hcd attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments()); + attachments.add(shadowRender.getShadowAttachment()); + lightRenderer = new LightRenderer(RendererContext, attachments); PostProcessor = new PostProcess(RendererContext, lightRenderer.getAttachment()); + } else{ sceneRender = new ForwardSceneRender(RendererContext); PostProcessor = new PostProcess(RendererContext, sceneRender.GetAttachmentColour()); lightRenderer = null; + shadowRender = null; } spriteRenderer= new SpriteRenderer(engineInstance, RendererContext, PostProcessor.GetAttachment()); GuiRender = new GuiRenderer(engineInstance, RendererContext, GraphicsQueue, PostProcessor.GetAttachment()); @@ -152,6 +160,7 @@ public class VulkanRenderer implements Renderer { Logger.debug("Loaded {} models", Models.size()); sceneRender.LoadMaterials(RendererContext,materialsCache,textureCache); + shadowRender.loadMaterials(RendererContext, materialsCache, textureCache); spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache); spriteRenderer.LoadMaterials(RendererContext,materialsCache,textureCache); GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache); @@ -173,6 +182,7 @@ public class VulkanRenderer implements Renderer { RendererContext.GetDevice().waitIdle(); Logger.debug("Waiting Vulkan Context"); sceneRender.cleanup(RendererContext); + if(shadowRender != null)shadowRender.cleanup(RendererContext); if(lightRenderer != null)lightRenderer.cleanup(RendererContext); PostProcessor.CleanUp(RendererContext); swapChainRender.CleanUp(RendererContext); @@ -206,7 +216,9 @@ public class VulkanRenderer implements Renderer { RecordingStart(CommandPool, CommandBuffer); sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame); - lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), CurrentFrame); + shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); + lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), shadowRender.getShadowAttachment(), CurrentFrame, + shadowRender.getCascadeShadows(CurrentFrame)); PostProcessor.Render(RendererContext,CommandBuffer,lightRenderer.getAttachment()); spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame); GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment()); @@ -280,7 +292,9 @@ public class VulkanRenderer implements Renderer { engineInstance.scene().GetProjection().Resize(extend.width(),extend.height()); sceneRender.Resize(engineInstance,RendererContext); if(Deferred) { - lightRenderer.resize(RendererContext, sceneRender.GetMRTAttachments().GetAllAttachments()); + List attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments()); + attachments.add(shadowRender.getShadowAttachment()); + lightRenderer.resize(RendererContext, attachments); PostProcessor.Resize(RendererContext, lightRenderer.getAttachment()); } else{ PostProcessor.Resize(RendererContext, sceneRender.GetAttachmentColour()); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java index cbe5310..f0dd0ff 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java @@ -76,7 +76,7 @@ public class EngineConfig { public boolean AlphaToCoverage = false; public boolean CompatibilityMode = false; public Renderer renderer = Renderer.Forward; - public int ShadowMapSize = 16; + public int ShadowMapSize = 4096; public float Gamma = 0.8545f; public int MaxVulkanCrashesAllowed = 10; public boolean RenderCollisionMesh = true; @@ -322,7 +322,7 @@ public class EngineConfig { zFarPlane = (Float.parseFloat(EngineConfigVar.getOrDefault("z_far_plane", 100.0f).toString())); AAValue = (Integer.parseInt(EngineConfigVar.getOrDefault("anti_alias_mode", 1).toString())); renderer = Integer.parseInt(EngineConfigVar.getOrDefault("Renderer", 1).toString()) == 0 ? Renderer.Forward: Renderer.Deferred; - ShadowMapSize = Integer.parseInt(EngineConfigVar.getOrDefault("ShadowMapSize", 16).toString()); + ShadowMapSize = Integer.parseInt(EngineConfigVar.getOrDefault("ShadowMapSize", 4096).toString()); MaxVulkanCrashesAllowed = Integer.parseInt(EngineConfigVar.getOrDefault("MaxAllowedVulkanCrashes", 10).toString()); ServerPort = Integer.parseInt(EngineConfigVar.getOrDefault("server_port", 25565).toString()); CompatibilityMode = Boolean.parseBoolean(EngineConfigVar.getOrDefault("compatibility_mode", false).toString()); @@ -385,6 +385,7 @@ public class EngineConfig { EngineConfigVar.setProperty("MaxDescriptors","1000"); EngineConfigVar.setProperty("anti_alias_mode","1"); EngineConfigVar.setProperty("server","false"); + EngineConfigVar.setProperty("ShadowMapSize","4096"); EngineConfigVar.setProperty("LoadingScreenLocation",LoadingScreenLocation); EngineConfigVar.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file"); Logger.debug("Wrote New Config File [{}]", ConfigFile.getAbsolutePath()); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidBody.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidBody.java index 5dbfa0f..957c840 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidBody.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/RigidBody/RigidBody.java @@ -1,6 +1,7 @@ package net.halbear.Terrain4J.EngineCore.Logic.Physics.RigidBody; import net.halbear.Terrain4J.EngineCore.Logic.Physics.IPhysicsController; +import net.halbear.Terrain4J.EngineCore.Logic.Physics.StaticSpatialHashGrid; import org.joml.Matrix3f; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -80,6 +81,7 @@ public class RigidBody { InverseMassKG = 0f; InverseInertiaLocal.zero(); IsStatic = true; + StaticSpatialHashGrid.Insert(RigidBodyID, shape.GetWorldAABB()); } else { InverseMassKG = 1.0f / mass; IsStatic = false; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/SpatialHashGrid.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/SpatialHashGrid.java index aa761a1..ecf7c86 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/SpatialHashGrid.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/SpatialHashGrid.java @@ -31,6 +31,18 @@ public class SpatialHashGrid { } } + public static Map> Cells(){ + return Cells; + } + + public static List GetFromKey(long key){ + return Cells.getOrDefault(key, Collections.emptyList()); + } + + public static List GetAtXYZ(int x, int y, int z){ + long key = HashCell(x, y, z); + return Cells.getOrDefault(key, Collections.emptyList()); + } private static long HashCell(int x, int y, int z) { long xi = ((long) x) & 0x1FFFFFL; long yi = ((long) y) & 0x1FFFFFL; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/StaticSpatialHashGrid.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/StaticSpatialHashGrid.java index 0e7b7f2..76c2605 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/StaticSpatialHashGrid.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/StaticSpatialHashGrid.java @@ -5,7 +5,7 @@ import org.joml.primitives.AABBf; import java.util.*; public class StaticSpatialHashGrid { - public static float CellSize = 16f; + public static float CellSize = 3f; private static final Map> Cells = new HashMap<>(); @@ -31,6 +31,19 @@ public class StaticSpatialHashGrid { } } + public static Map> Cells(){ + return Cells; + } + + public static List GetFromKey(long key){ + return Cells.getOrDefault(key, Collections.emptyList()); + } + + + public static List GetAtXYZ(int x, int y, int z){ + long key = HashCell(x, y, z); + return Cells.getOrDefault(key, Collections.emptyList()); + } private static long HashCell(int x, int y, int z) { long xi = ((long) x) & 0x1FFFFFL; long yi = ((long) y) & 0x1FFFFFL; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java index ffb1b7b..ef247a4 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/Physics/WorldPhysicsManager.java @@ -117,6 +117,23 @@ public class WorldPhysicsManager { Set testedPairs = new HashSet<>(); +// SpatialHashGrid.Cells().forEach((key, bucket)->{ +// int size = bucket.size(); +// for (int i = 0; i < size; i++) { +// RigidBody a = RigidBody.RigidBodyRegister.get(bucket.get(i)); +// if (a == null) continue; +// for (int j = i + 1; j < size; j++) { +// RigidBody b = RigidBody.RigidBodyRegister.get(bucket.get(j)); +// if (b == null || a == b) continue; +// TryResolve(a, b, worldBounds, testedPairs); +// } +// StaticSpatialHashGrid.GetFromKey(key).forEach((id)->{ +// RigidBody b = RigidBody.RigidBodyRegister.get(id); +// if (b == null || a == b) return; +// TryResolve(a, b, worldBounds, testedPairs); +// }); +// } +// }); for (List bucket : SpatialHashGrid.Buckets()) { int size = bucket.size(); for (int i = 0; i < size; i++) { 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 bc994f9..ed6ca3a 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java @@ -47,13 +47,12 @@ import org.tinylog.Logger; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE; -import static org.lwjgl.glfw.GLFW.GLFW_KEY_F3; +import static org.lwjgl.glfw.GLFW.*; public class GameCore implements GameLogic { private static final float MOUSE_SENSITIVITY = 0.1f; - private static final float MOVEMENT_SPEED = 0.01f; + private static final float MOVEMENT_SPEED = 0.1f; public static boolean LoadingLevel = false; private Vector2f LastMousePos = new Vector2f(0,0); @@ -99,19 +98,31 @@ public class GameCore implements GameLogic { public InitData Initialise(EngineInstance engineInstance) { Scene scene = (Scene) engineInstance.scene(); List models = new ArrayList<>(); - ModelData SponzaData = ModelLoader.LoadModel("resources/models/Cafe/exterior.json"); - List SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Cafe/exterior_mat.json"); - ModelData SponzaData1 = ModelLoader.LoadModel("resources/models/Cafe/interior.json"); - List SponzaMaterial1= ModelLoader.LoadMaterials("resources/models/Cafe/interior_mat.json"); - scene.AddActor(new Actor3D("Sponza1", SponzaData.ID(), new Vector3f(0,0f,-5f)).SetScale(0.1f)); - scene.AddActor(new Actor3D("Sponza2", SponzaData1.ID(), new Vector3f(0,0f,-5f)).SetScale(0.1f)); + List materials = new ArrayList<>(); +// ModelData SponzaData = ModelLoader.LoadModel("resources/models/Cafe/exterior.json"); +// List SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Cafe/exterior_mat.json"); +// ModelData SponzaData1 = ModelLoader.LoadModel("resources/models/Cafe/interior.json"); +// List SponzaMaterial1= ModelLoader.LoadMaterials("resources/models/Cafe/interior_mat.json"); +// scene.AddActor(new Actor3D("Sponza1", SponzaData.ID(), new Vector3f(0,0f,-5f)).SetScale(0.1f)); +// scene.AddActor(new Actor3D("Sponza2", SponzaData1.ID(), new Vector3f(0,0f,-5f)).SetScale(0.1f)); +// ModelData treeModel = ModelLoader.LoadModel("resources/models/tree/tree.json"); +// models.add(treeModel); +// Actor3D treeEntity = new Actor3D("treeEntity", treeModel.ID(), new Vector3f(0.0f, 0.0f, 0.0f)); +// treeEntity.SetScale(0.05f); +// scene.AddActor(treeEntity); +// materials.addAll(ModelLoader.LoadMaterials("resources/models/tree/tree_mat.json")); +// ModelData treeModel = ModelLoader.LoadModel("resources/models/Forest/forest.json"); +// models.add(treeModel); +// Actor3D treeEntity = new Actor3D("treeEntity", treeModel.ID(), new Vector3f(0.0f, 0.0f, 0.0f)); +// treeEntity.SetScale(10f); +// scene.AddActor(treeEntity); +// materials.addAll(ModelLoader.LoadMaterials("resources/models/Forest/forest_mat.json")); MelonaData = ModelLoader.LoadModel("resources/models/cube/Cube.json"); CubeModelID = MelonaData.ID(); List MelonaMat = ModelLoader.LoadMaterials("resources/models/cube/Cube_mat.json"); var CollisionVisualisationData = ModelLoader.LoadModel("resources/models/VisualCollision/CollisionCube.json"); VisualisedCollisionActor3D.CollisionCubeModelID = CollisionVisualisationData.ID(); List CollisionVisualisationMat = ModelLoader.LoadMaterials("resources/models/VisualCollision/CollisionCube_mat.json"); - List materials = new ArrayList<>(); var Melona = ModelLoader.LoadModel("resources/models/melona/melona.json"); List MelonaMaterial = ModelLoader.LoadMaterials("resources/models/melona/melona_mat.json"); @@ -147,10 +158,10 @@ public class GameCore implements GameLogic { } boolean createOfflinePlayer = !PrimaryRuntime.IsServer && !ClientSideNetworkUtils.Connected; - materials.addAll(SponzaMaterial); - materials.addAll(SponzaMaterial1); - models.add(SponzaData); - models.add(SponzaData1); +// materials.addAll(SponzaMaterial); +// materials.addAll(SponzaMaterial1); +// models.add(SponzaData); +// models.add(SponzaData1); materials.addAll(MelonaMat); materials.addAll(CollisionVisualisationMat); materials.addAll(MelonaMaterial); @@ -179,47 +190,50 @@ public class GameCore implements GameLogic { guiTextures.add(guiTexture); } - //scene.GetLightingManager().GetAmbientLightColour().set(1.0f, 0.9f, 0.75f); - //scene.GetLightingManager().SetAmbientLightIntensity(0.6f); - scene.GetLightingManager().GetAmbientLightColour().set(0.3f, 0.35f, 0.5f); - scene.GetLightingManager().SetAmbientLightIntensity(0.01f); - - // SkyLight = new Light(new Vector3f(1.5f, 1.20f, 1.0f),new Vector3f(0.0f, -1.0f, 0.3f), true, 2.00f); - SkyLight = new Light(new Vector3f(0.25f, 1.0f, 1.5f),new Vector3f(0.0f, -1.0f, 0.0f), true, 1.70f); + scene.GetLightingManager().GetAmbientLightColour().set(1.0f, 0.9f, 0.75f); + scene.GetLightingManager().SetAmbientLightIntensity(0.3f); +// scene.GetLightingManager().GetAmbientLightColour().set(0.3f, 0.35f, 0.5f); +// scene.GetLightingManager().SetAmbientLightIntensity(0.075f); +// + SkyLight = new Light(new Vector3f(1.5f, 1.20f, 1.0f),new Vector3f(0.0f, -1.0f, 0.3f), true, 2.00f); +// SkyLight = new Light(new Vector3f(0.25f, 1.0f, 1.5f),new Vector3f(0.0f, -1.0f, 0.0f), true, 6.0f); SkyLight.SetType(Light.LightType.Directional); List lights = new ArrayList<>(); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-433, 445f, -424f).div(10.0f),false,3000.0f+ (float)(Math.random() * 100.0))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-210, 445f, 460f).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-966, 445f, 204f).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-176, 445f, 1000f).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(777, 445f, 858).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(376, 445f, -2136).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,2.0f),new Vector3f(2163, 445f, 1880).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3334, 445f, 2405).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3509, 445f, 1825).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3877, 445f, 3378).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(4925, 445f, 3430).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); - lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-2083, 445f, -1826).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-433, 445f, -424f).div(10.0f),false,3000.0f+ (float)(Math.random() * 100.0))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-210, 445f, 460f).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-966, 445f, 204f).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-176, 445f, 1000f).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(777, 445f, 858).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(376, 445f, -2136).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,2.0f),new Vector3f(2163, 445f, 1880).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3334, 445f, 2405).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3509, 445f, 1825).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3877, 445f, 3378).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(4925, 445f, 3430).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-2083, 445f, -1826).div(10.0f),false,700.0f + (float)(Math.random() * 150.0f))); +// +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(2076, 410, 1272).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(2446, 465, 2303).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-842, 410, -1141).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-207, 410, -1830).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(899, 460, -2015).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(1775, 460, -3448).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(1800, 460, -4154).div(10.0f),false,1000.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1727, 410, -387).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1198, 410, -964).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1778, 410, -1502).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2692, 333, -2109).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2849, 333, -1724).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2019, 410, -729).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1727, 410, -389).div(10.0f),false,100.0f)); +// lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1337, 410, 122).div(10.0f),false,100.0f)); +// +// +// lights.add(new Light(new Vector3f(0.75f,2.0f,0.75f),new Vector3f(1086, 425, -3375).div(10.0f),false,500.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(2076, 410, 1272).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(2446, 465, 2303).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-842, 410, -1141).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-207, 410, -1830).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(899, 460, -2015).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(1775, 460, -3448).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(1800, 460, -4154).div(10.0f),false,1000.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1727, 410, -387).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1198, 410, -964).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1778, 410, -1502).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2692, 333, -2109).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2849, 333, -1724).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2019, 410, -729).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1727, 410, -389).div(10.0f),false,100.0f)); - lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1337, 410, 122).div(10.0f),false,100.0f)); - - - lights.add(new Light(new Vector3f(0.75f,2.0f,0.75f),new Vector3f(1086, 425, -3375).div(10.0f),false,500.0f)); + //lights.add(new Light(new Vector3f(3.0f,2.25f,0.0f),new Vector3f(350.0f, 1525.0f, -420.0f),false,4000.0f)); + //lights.add(new Light(new Vector3f(3.0f,2.25f,0.0f),new Vector3f(400.0f, 1570.0f, -350.0f),false,1000.0f)); lights.add(SkyLight); ILight[] lightArr = new ILight[lights.size()]; @@ -232,7 +246,12 @@ public class GameCore implements GameLogic { } //if(PrimaryRuntime.IsServer) { permutation.GeneratePermutationArray(5783904701859L); - //GenerateChunk(new Vector3i(0, 0, 0), 16); + for(int x = -1; x < 2; x++){ + for(int y = -1; y < 2; y++){ + GenerateChunk(new Vector3i(x, 0, y), 16); + + } + } for(int i = 0; i < 20; i++){ SpawnNewActor(engineInstance, new Vector3f(-5 + (float)Math.random() * 10,10 + (float)Math.random() * 10, -5 + (float)Math.random() * 10), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1)); } @@ -241,6 +260,18 @@ public class GameCore implements GameLogic { Settings.UsernameBuffer.set("Player"); return new InitData(models,materials,guiTextures); } + public static float lightAngle = 70; + + private void updateDirLight() { + float zValue = (float) Math.cos(Math.toRadians(lightAngle)); + float yValue = (float) Math.sin(Math.toRadians(lightAngle)); + Vector3f lightDirection = SkyLight.GetPosition(); + lightDirection.x = 0; + lightDirection.y = yValue; + lightDirection.z = zValue; + lightDirection.normalize(); + SkyLight.GetPosition().set(lightDirection); + } public void Reset(){ EngineInstance instance = PrimaryRuntime.GetEngineInstance(); @@ -465,6 +496,8 @@ public class GameCore implements GameLogic { } if(CumulativeFrameTime >= 16_000_000) { HandleGui(engineInstance, FrameDiffNanoSeconds); + // lightAngle = (lightAngle + 0.15f) % 360; + // updateDirLight(); CumulativeFrameTime = 0; } } @@ -479,6 +512,14 @@ public class GameCore implements GameLogic { if(input.keySinglePress(GLFW_KEY_F3)){ Scene.GUI_MODE = (Scene.GUI_MODE + 1) % 2; } + if(input.keyPressed(GLFW_KEY_UP)){ + lightAngle = (lightAngle + 0.5f) % 360; + updateDirLight(); + } + if(input.keyPressed(GLFW_KEY_DOWN)){ + lightAngle = (lightAngle - 0.5f) % 360; + updateDirLight(); + } if (input.keySinglePress(GLFW_KEY_ESCAPE)) { StartMenuActive = !StartMenuActive; StartMenu.GameStarted = StartMenuActive; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Light.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Light.java index b0c2e7c..12b8e01 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Light.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Light.java @@ -10,6 +10,8 @@ public class Light implements ILight{ public void SetType(LightType type) { this.type = type; + if(type == LightType.Directional) + Directional = true; } public enum LightType{ diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java index e21d5f3..470790e 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/Scene.java @@ -156,7 +156,7 @@ public class Scene implements IScene { if(!PrimaryRuntime.IsServer && !RenderThread.Headless) { GUIReg.put("PerformanceOverlay",new PerformanceOverlay()); - // ActiveGUIs.add("PerformanceOverlay"); + ActiveGUIs.add("PerformanceOverlay"); GUIReg.put("ChatLog",new GameChat()); ActiveGUIs.add("ChatLog"); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/SceneLightingManager.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/SceneLightingManager.java index 2df3d3f..e46f822 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/SceneLightingManager.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/Scene/SceneLightingManager.java @@ -7,7 +7,7 @@ import java.util.Arrays; import java.util.List; public class SceneLightingManager implements ISceneLightingManager { - public static int SHADOW_MAP_CASCADE_COUNT = 10; + public static int SHADOW_MAP_CASCADE_COUNT = 6; public static int MaxLights; private Vector3f AmbientLightingColour; private float AmbientLightIntensity; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Universal/Projection/Project3D.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Universal/Projection/Project3D.java index b718cc0..be94eeb 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Universal/Projection/Project3D.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Universal/Projection/Project3D.java @@ -18,8 +18,8 @@ public class Project3D { this.FOV = FOV; OriginalNear = zNear; OriginalFar = zFar; - this.ZFarPlane = EngineConfig.getInstance().GetRenderingAPI() == EngineConfig.RenderAPI.OpenGL ? zNear : zFar; - this.ZNearPlane = EngineConfig.getInstance().GetRenderingAPI() == EngineConfig.RenderAPI.OpenGL ? zFar : zNear; + this.ZFarPlane = zFar; + this.ZNearPlane = zNear; ProjectionMatrix = new Matrix4f(); Resize(Width, Height); LastWidth = Width; @@ -27,8 +27,8 @@ public class Project3D { } public void SetFarPlanes(){ - ZFarPlane = EngineConfig.getInstance().GetRenderingAPI() == EngineConfig.RenderAPI.OpenGL ? OriginalNear : OriginalFar; - ZNearPlane = EngineConfig.getInstance().GetRenderingAPI() == EngineConfig.RenderAPI.OpenGL ? OriginalFar : OriginalNear; + ZFarPlane =OriginalFar; + ZNearPlane = OriginalNear; Resize(LastWidth,LastHeight); } 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 ae8d2d2..5b102d6 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 @@ -13,6 +13,8 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.I import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PipelineBuildInfo; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shadows.CascadeData; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shadows.CascadeShadows; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView; @@ -31,15 +33,18 @@ import java.util.ArrayList; import java.util.Arrays; 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.VK10.*; import static org.lwjgl.vulkan.VK13.*; public class LightRenderer { private static final int COLOUR_FORMAT = VK_FORMAT_R32G32B32A32_SFLOAT; private static final String DESC_ID_ATT = "LIGHT_DESC_ID_ATT"; + private static final String DESC_ID_SHADOW_MATRICES = "LIGHT_DESC_ID_SHADOW_MATRICES"; private static final String DESC_ID_LIGHTS = "LIGHT_DESC_ID_LIGHTS"; private static final String DESC_ID_SCENE = "LIGHT_DESC_ID_SCENE "; - private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/lighting_frag.glsl"; + private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/lighting_with_shadows_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/lighting_vertex.glsl"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; @@ -53,8 +58,10 @@ public class LightRenderer { private VkRenderingInfo RenderInfo; private final VulkanBuffer[] LightBuffer; private final VulkanBuffer[] SceneBuffer; + private final LightSpecConsts lightSpecConsts; private final DescriptorSetLayout SceneDescriptorSetLayout; private final DescriptorSetLayout StorageDescriptorSetLayout; + private final VulkanBuffer[] shadowMatrices; public LightRenderer(VulkanContext VkCtx, List attachments){ ClearValueColour = VkClearValue.calloc().color( @@ -64,18 +71,18 @@ public class LightRenderer { AttachmentInfoColour = CreateColourAttachmentInfo(AttachmentColour, ClearValueColour); RenderInfo = CreateRenderInfo(AttachmentColour, AttachmentInfoColour); - ShaderModule[] shaderModules = CreateShaderModules(VkCtx); + lightSpecConsts = new LightSpecConsts(); + ShaderModule[] shaderModules = CreateShaderModules(VkCtx, lightSpecConsts); var textureSamplerInfo = new TextureSamplerInfo(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_BORDER_COLOR_INT_OPAQUE_BLACK, 1, true); textureSampler = new TextureSampler(VkCtx, textureSamplerInfo); int numAttachments = attachments.size(); - DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments]; - for (int i = 0; i < numAttachments; i++) { + DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments + 1]; + for (int i = 0; i < numAttachments + 1; i++) { descSetLayouts[i] = new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, i, 1, VK_SHADER_STAGE_FRAGMENT_BIT); } AttachmentDescriptorSetLayout = new DescriptorSetLayout(VkCtx, descSetLayouts); - CreateAttachmentDescriptorSet(VkCtx, AttachmentDescriptorSetLayout, attachments, textureSampler); StorageDescriptorSetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, 1, @@ -86,16 +93,32 @@ public class LightRenderer { SceneDescriptorSetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, 1, VK_SHADER_STAGE_FRAGMENT_BIT)); - buffSize = VulkanUtils.VEC3_SIZE * 2 + VulkanUtils.FLOAT_SIZE + VulkanUtils.INT_SIZE; + buffSize = VulkanUtils.VEC3_SIZE * 2 + VulkanUtils.FLOAT_SIZE + VulkanUtils.INT_SIZE + VulkanUtils.MATRIX4X4_SIZE; SceneBuffer = VulkanUtils.CreateHostVisibleBuffers(VkCtx, buffSize, VulkanUtils.MAX_IN_FLIGHT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESC_ID_SCENE, SceneDescriptorSetLayout); - + shadowMatrices = CreateShadowMatrixBuffers(VkCtx, StorageDescriptorSetLayout); pipeline = createPipeline(VkCtx, shaderModules, new DescriptorSetLayout[]{AttachmentDescriptorSetLayout, StorageDescriptorSetLayout, - SceneDescriptorSetLayout}); + StorageDescriptorSetLayout, SceneDescriptorSetLayout}); Logger.debug("Light Renderer Pipeline -> [{}]",pipeline.GetVulkanPipeline()); Arrays.asList(shaderModules).forEach(s -> s.CleanUp(VkCtx)); } + private static VulkanBuffer[] CreateShadowMatrixBuffers(VulkanContext vkCtx, DescriptorSetLayout layout) { + int numBuffs = VulkanUtils.MAX_IN_FLIGHT; + VulkanBuffer[] buffers = new VulkanBuffer[numBuffs]; + Device device = vkCtx.GetDevice(); + DescriptorSet[] descSets = vkCtx.GetDescriptorAllocator().AddDescriptorSets(device, DESC_ID_SHADOW_MATRICES, numBuffs, layout); + for (int i = 0; i < numBuffs; i++) { + long buffSize = (long) (VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.VEC4_SIZE) * SceneLightingManager.SHADOW_MAP_CASCADE_COUNT; + buffers[i] = new VulkanBuffer(vkCtx, buffSize, + 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); + descSets[i].SetBuffer(device, buffers[i], buffers[i].GetRequestedSize(), + layout.GetLayoutInfo().Binding(), layout.GetLayoutInfo().DescriptorType()); + } + return buffers; + } + private static void CreateAttachmentDescriptorSet(VulkanContext VkCtx, DescriptorSetLayout descSetLayout, List attachments, TextureSampler sampler) { DescriptorAllocator descAllocator = VkCtx.GetDescriptorAllocator(); @@ -110,7 +133,7 @@ public class LightRenderer { SwapChain swapChain = VkCtx.GetSwapChain(); VkExtent2D swapChainExtent = swapChain.GetSwapChainExtent(); return new Attachment(VkCtx, swapChainExtent.width(), swapChainExtent.height(), - COLOUR_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + COLOUR_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,1); } private static VkRenderingAttachmentInfo.Buffer CreateColourAttachmentInfo(Attachment attachment, VkClearValue clearValue) { @@ -153,19 +176,19 @@ public class LightRenderer { return result; } - private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx) { + private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, LightSpecConsts lightSpecConsts) { 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), + new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, FRAGMENT_SHADER_FILE_SPV, lightSpecConsts.getSpecInfo()), }; } - 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 shadowAttachment, int CurrentFrame, CascadeShadows cascadeShadows) { try (var stack = MemoryStack.stackPush()) { VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer(); @@ -176,7 +199,6 @@ public class LightRenderer { VK_IMAGE_ASPECT_COLOR_BIT); List attachments = mrtAttachments.GetColourAttachments(); - // Logger.debug("Colour Attachments -> \n1: [{}]\n 2:[{}] \n3:[{}]\n 4:[{}]",attachments.get(0),attachments.get(1),attachments.get(2),attachments.get(3)); int numAttachments = attachments.size(); for (int i = 0; i < numAttachments; i++) { Attachment attachment = attachments.get(i); @@ -187,11 +209,19 @@ public class LightRenderer { VK_IMAGE_ASPECT_COLOR_BIT); } VulkanUtils.ImageBarrier(stack, cmdHandle, mrtAttachments.GetDepthAttachment().GetVkImage().getVulkanImage(), - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_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_DEPTH_BIT); + VulkanUtils.ImageBarrier(stack, cmdHandle, shadowAttachment.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); + + UpdateCascadeShadowMatrices(VkCtx, cascadeShadows, CurrentFrame); + vkCmdBeginRendering(cmdHandle, RenderInfo); vkCmdBindPipeline(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.GetVulkanPipeline()); @@ -215,10 +245,11 @@ public class LightRenderer { vkCmdSetScissor(cmdHandle, 0, scissor); DescriptorAllocator descAllocator = VkCtx.GetDescriptorAllocator(); - LongBuffer descriptorSets = stack.mallocLong(3) + LongBuffer descriptorSets = stack.mallocLong(4) .put(0, descAllocator.GetDescriptorSet(DESC_ID_ATT).GetVkDescriptorSet()) .put(1, descAllocator.GetDescriptorSet(DESC_ID_LIGHTS, CurrentFrame).GetVkDescriptorSet()) - .put(2, descAllocator.GetDescriptorSet(DESC_ID_SCENE, CurrentFrame).GetVkDescriptorSet()); + .put(2, descAllocator.GetDescriptorSet(DESC_ID_SHADOW_MATRICES, CurrentFrame).GetVkDescriptorSet()) + .put(3, descAllocator.GetDescriptorSet(DESC_ID_SCENE, CurrentFrame).GetVkDescriptorSet()); IScene scene = engineInstance.scene(); UpdateSceneInfo(VkCtx, scene, CurrentFrame); UpdateLights(VkCtx, scene, CurrentFrame); @@ -231,6 +262,22 @@ public class LightRenderer { } } + private void UpdateCascadeShadowMatrices(VulkanContext vkCtx, CascadeShadows cascadeShadows, int currentFrame) { + VulkanBuffer buff = shadowMatrices[currentFrame]; + long mappedMemory = buff.MapMemory(vkCtx); + ByteBuffer dataBuff = MemoryUtil.memByteBuffer(mappedMemory, (int) buff.GetRequestedSize()); + int offset = 0; + List cascadeDataList = cascadeShadows.GetCascadeData(); + int numCascades = cascadeDataList.size(); + for (int i = 0; i < numCascades; i++) { + CascadeData cascadeData = cascadeDataList.get(i); + cascadeData.GetProjViewMatrix().get(offset, dataBuff); + dataBuff.putFloat(offset + VulkanUtils.MATRIX4X4_SIZE, cascadeData.GetSplitDistance()); + offset += VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.VEC4_SIZE; + } + buff.UnMapMemory(vkCtx); + } + public void UpdateSceneInfo(VulkanContext VkCtx, IScene scene, int CurrentFrame){ VulkanBuffer buffer = SceneBuffer[CurrentFrame]; long MappedMemory = buffer.MapMemory(VkCtx); @@ -249,6 +296,10 @@ public class LightRenderer { ILight[] lights = scene.GetLightingManager().GetLights(); int LightCount = lights != null ? lights.length : 0; dataBuffer.putInt(Offset, LightCount); + Offset += VulkanUtils.INT_SIZE; + + scene.GetCamera().GetViewMatrix().get(Offset, dataBuffer); + buffer.UnMapMemory(VkCtx); } public void UpdateLights(VulkanContext VkCtx, IScene scene, int CurrentFrame){ @@ -291,11 +342,13 @@ public class LightRenderer { public void cleanup(VulkanContext VkCtx) { StorageDescriptorSetLayout.CleanUp(VkCtx); Arrays.asList(LightBuffer).forEach(b -> b.cleanup(VkCtx)); + Arrays.asList(shadowMatrices).forEach(b -> b.cleanup(VkCtx)); SceneDescriptorSetLayout.CleanUp(VkCtx); Arrays.asList(SceneBuffer).forEach(b -> b.cleanup(VkCtx)); pipeline.CleanUp(VkCtx); AttachmentDescriptorSetLayout.CleanUp(VkCtx); textureSampler.CleanUp(VkCtx); + lightSpecConsts.cleanup(); RenderInfo.free(); AttachmentColour.CleanUp(VkCtx); AttachmentInfoColour.free(); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightSpecConsts.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightSpecConsts.java new file mode 100644 index 0000000..a093c28 --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/DeferredRendering/LightSpecConsts.java @@ -0,0 +1,56 @@ +package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering; + +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; +import net.halbear.Terrain4J.EngineCore.Main.Scene.SceneLightingManager; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.vulkan.VkSpecializationInfo; +import org.lwjgl.vulkan.VkSpecializationMapEntry; + +import java.nio.ByteBuffer; + +public class LightSpecConsts { + private final ByteBuffer data; + private final VkSpecializationMapEntry.Buffer specEntryMap; + private final VkSpecializationInfo specInfo; + + public LightSpecConsts() { + var engCfg = EngineConfig.getInstance(); + data = MemoryUtil.memAlloc(VulkanUtils.INT_SIZE * 2); + data.putInt(SceneLightingManager.SHADOW_MAP_CASCADE_COUNT); + data.putInt(engCfg.DebugShaders() ? 1 : 0); + data.flip(); + + specEntryMap = VkSpecializationMapEntry.calloc(2); + int offset = 0; + int pos = 0; + int size = VulkanUtils.INT_SIZE; + specEntryMap.get(pos) + .constantID(pos) + .size(size) + .offset(offset); + offset += size; + pos++; + + size = VulkanUtils.INT_SIZE; + specEntryMap.get(pos) + .constantID(pos) + .size(size) + .offset(offset); + + specInfo = VkSpecializationInfo.calloc(); + specInfo.pData(data) + .pMapEntries(specEntryMap); + } + + public void cleanup() { + MemoryUtil.memFree(specEntryMap); + specInfo.free(); + MemoryUtil.memFree(data); + } + + public VkSpecializationInfo getSpecInfo() { + return specInfo; + } +} 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 6ece964..8931415 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 @@ -28,18 +28,18 @@ public class MultiRenderTargetAttachments { ColourAttachments = new ArrayList<>(); //Position - var Attachment = new Attachment(VkCtx, Width, Height, POSITION_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + var Attachment = new Attachment(VkCtx, Width, Height, POSITION_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 1); ColourAttachments.add(Attachment); //albedo - Attachment = new Attachment(VkCtx, Width, Height, ALBEDO_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + Attachment = new Attachment(VkCtx, Width, Height, ALBEDO_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 1); ColourAttachments.add(Attachment); //Normals - Attachment = new Attachment(VkCtx, Width, Height, NORMAL_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + Attachment = new Attachment(VkCtx, Width, Height, NORMAL_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 1); ColourAttachments.add(Attachment); //PBR - Attachment = new Attachment(VkCtx, Width, Height, PBR_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + Attachment = new Attachment(VkCtx, Width, Height, PBR_FORMAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 1); ColourAttachments.add(Attachment); - DepthAttachment = new Attachment(VkCtx, Width, Height, DEPTH_FORMAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + DepthAttachment = new Attachment(VkCtx, Width, Height, DEPTH_FORMAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 1); } public int GetWidth(){return Width;} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/DefaultPipeline.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/DefaultPipeline.java index 9df7b4b..fb57993 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/DefaultPipeline.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/DefaultPipeline.java @@ -67,10 +67,11 @@ public class DefaultPipeline implements Pipeline { .viewportCount(1) .scissorCount(1); var RasterizationStateCreateInfo = VkPipelineRasterizationStateCreateInfo.calloc(MemStack) - .sType(VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO) + .sType$Default() .polygonMode(VK_POLYGON_MODE_FILL) .cullMode(VK_CULL_MODE_NONE) .frontFace(VK_FRONT_FACE_CLOCKWISE) + .depthClampEnable(BuildInfo.DepthClamp()) .lineWidth(1.0f); int sampleCount = EngineConfig.getInstance().GetRenderSampleCount(); var MultisampleStateCreateInfo = VkPipelineMultisampleStateCreateInfo.calloc(MemStack) @@ -88,7 +89,7 @@ public class DefaultPipeline implements Pipeline { .sType(VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO) .depthTestEnable(BuildInfo.GetDepthTest()) .depthWriteEnable(BuildInfo.performDepthWrite()) - .depthCompareOp(VK_COMPARE_OP_GREATER_OR_EQUAL) + .depthCompareOp(VK_COMPARE_OP_LESS_OR_EQUAL) .depthBoundsTestEnable(false) .stencilTestEnable(false); } 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 1af25f6..a90d0b7 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 @@ -9,24 +9,85 @@ public class Attachment { private final Image VkImage; private final ImageView VkImageView; private boolean DepthAttachment; - - public Attachment(VulkanContext VkCtx, int Width, int Height, int Format, int Usage){ + 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()); - int AspectMask = 0; - if((Usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) > 0){ - AspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + int aspectMask = 0; + if ((Usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) > 0) { + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; ImageData.Usage(Usage | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); DepthAttachment = false; } - if((Usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) > 0){ + if ((Usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) > 0) { ImageData.Usage(Usage | VK_IMAGE_USAGE_SAMPLED_BIT); - AspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; DepthAttachment = true; } + int layers = 1; + if (layers > 0) { + ImageData.ArrayLayers(layers); + } VkImage = new Image(VkCtx, ImageData); - var ImageViewData = new ImageView.ImageViewData().Format(VkImage.GetFormat()).AspectMask(AspectMask); - VkImageView = new ImageView(VkCtx.GetDevice(), VkImage.getVulkanImage(), ImageViewData,DepthAttachment); + + var imageViewData = new ImageView.ImageViewData().Format(VkImage.GetFormat()).AspectMask(aspectMask); + if (layers > 1) { + imageViewData.ViewType(VK_IMAGE_VIEW_TYPE_2D_ARRAY); + imageViewData.LayerCount(layers); + } + VkImageView = new ImageView(VkCtx.GetDevice(), VkImage.getVulkanImage(), imageViewData, DepthAttachment); + } + public Attachment(VulkanContext VkCtx, int Width, int Height, int Format, int Usage){ + var ImageData = new Image.ImageData().Width(Width).Height(Height).Format(Format).SampleCount(VK_SAMPLE_COUNT_1_BIT); + + int aspectMask = 0; + if ((Usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) > 0) { + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + ImageData.Usage(Usage | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + DepthAttachment = false; + } + if ((Usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) > 0) { + ImageData.Usage(Usage | VK_IMAGE_USAGE_SAMPLED_BIT); + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + DepthAttachment = true; + } + int layers = 1; + if (layers > 0) { + ImageData.ArrayLayers(layers); + } + VkImage = new Image(VkCtx, ImageData); + + var imageViewData = new ImageView.ImageViewData().Format(VkImage.GetFormat()).AspectMask(aspectMask); + if (layers > 1) { + imageViewData.ViewType(VK_IMAGE_VIEW_TYPE_2D_ARRAY); + imageViewData.LayerCount(layers); + } + VkImageView = new ImageView(VkCtx.GetDevice(), VkImage.getVulkanImage(), imageViewData, DepthAttachment); + } + public Attachment(VulkanContext VkCtx, int Width, int Height, int Format, int Usage,int layers){ + var ImageData = new Image.ImageData().Width(Width).Height(Height).Format(Format).SampleCount(VK_SAMPLE_COUNT_1_BIT); + + int aspectMask = 0; + if ((Usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) > 0) { + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + ImageData.Usage(Usage | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + DepthAttachment = false; + } + if ((Usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) > 0) { + ImageData.Usage(Usage | VK_IMAGE_USAGE_SAMPLED_BIT); + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + DepthAttachment = true; + } + if (layers > 0) { + ImageData.ArrayLayers(layers); + } + VkImage = new Image(VkCtx, ImageData); + + var imageViewData = new ImageView.ImageViewData().Format(VkImage.GetFormat()).AspectMask(aspectMask); + if (layers > 1) { + imageViewData.ViewType(VK_IMAGE_VIEW_TYPE_2D_ARRAY); + imageViewData.LayerCount(layers); + } + VkImageView = new ImageView(VkCtx.GetDevice(), VkImage.getVulkanImage(), imageViewData, DepthAttachment); } public Image GetVkImage(){return VkImage;} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java index 2e9f019..aae2347 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java @@ -14,6 +14,7 @@ public class PipelineBuildInfo { private DescriptorSetLayout[] DescriptorSetLayouts; private boolean useBlend; private boolean DepthWrite = true; + private boolean DepthClamp = false; private boolean DepthTest = true; private boolean DualPass = false; private boolean alphaToCoverage = false; @@ -27,6 +28,13 @@ public class PipelineBuildInfo { DepthFormat = VK_FORMAT_UNDEFINED; useBlend = true; } + public boolean DepthClamp() { + return DepthClamp; + } + public PipelineBuildInfo SetDepthClamp(boolean depthClamp) { + this.DepthClamp = depthClamp; + return this; + } public PipelineBuildInfo SetBlendingMethod(int in){ BlendingMethod = in; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/CascadeData.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/CascadeData.java index 5b53f5d..a26efd4 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/CascadeData.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/CascadeData.java @@ -3,19 +3,26 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shadows; import org.joml.Matrix4f; public class CascadeData { - private final Matrix4f ProjectionViewMatrix; - private float SplitDistance; + private final Matrix4f projViewMatrix; + private float splitDistance; - public CascadeData(){ - ProjectionViewMatrix = new Matrix4f(); + public CascadeData() { + projViewMatrix = new Matrix4f(); } - public Matrix4f GetProjectionViewMatrix(){return ProjectionViewMatrix;} - public float GetSplitDistance(){return SplitDistance;} - public void SetProjectionViewMatrix(Matrix4f ProjViewMat){ - this.ProjectionViewMatrix.set(ProjViewMat); + public Matrix4f GetProjViewMatrix() { + return projViewMatrix; } - public void SetSplitDistance(float splitDistance){ - this.SplitDistance = splitDistance; + + public float GetSplitDistance() { + return splitDistance; + } + + public void SetProjectionViewMatrix(Matrix4f projViewMatrix) { + this.projViewMatrix.set(projViewMatrix); + } + + public void SetSplitDistance(float splitDistance) { + this.splitDistance = splitDistance; } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowRenderer.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowRenderer.java index 5bb8f68..889b9bc 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowRenderer.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowRenderer.java @@ -1,9 +1,70 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shadows; +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.Actor.Actor3D; +import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene; +import net.halbear.Terrain4J.EngineCore.Main.Scene.SceneLightingManager; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.ITexture; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Texture; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.TextureCache; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PipelineBuildInfo; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VertexBufferStructure; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.*; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView; +import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer; import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils; +import org.joml.Matrix4f; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.util.shaderc.Shaderc; +import org.lwjgl.vulkan.*; +import org.tinylog.Logger; -import static org.lwjgl.vulkan.VK10.VK_FORMAT_D32_SFLOAT; -import static org.lwjgl.vulkan.VK10.VK_FORMAT_R32G32_SFLOAT; +import java.nio.ByteBuffer; +import java.nio.LongBuffer; +import java.util.Arrays; +import java.util.List; + +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK10.VK_ATTACHMENT_LOAD_OP_CLEAR; +import static org.lwjgl.vulkan.VK10.VK_ATTACHMENT_STORE_OP_DONT_CARE; +import static org.lwjgl.vulkan.VK10.VK_ATTACHMENT_STORE_OP_STORE; +import static org.lwjgl.vulkan.VK10.VK_BORDER_COLOR_INT_OPAQUE_BLACK; +import static org.lwjgl.vulkan.VK10.VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; +import static org.lwjgl.vulkan.VK10.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; +import static org.lwjgl.vulkan.VK10.VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; +import static org.lwjgl.vulkan.VK10.VK_IMAGE_ASPECT_COLOR_BIT; +import static org.lwjgl.vulkan.VK10.VK_IMAGE_ASPECT_DEPTH_BIT; +import static org.lwjgl.vulkan.VK10.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; +import static org.lwjgl.vulkan.VK10.VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; +import static org.lwjgl.vulkan.VK10.VK_IMAGE_LAYOUT_UNDEFINED; +import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; +import static org.lwjgl.vulkan.VK10.VK_INDEX_TYPE_UINT32; +import static org.lwjgl.vulkan.VK10.VK_PIPELINE_BIND_POINT_GRAPHICS; +import static org.lwjgl.vulkan.VK10.VK_SAMPLER_ADDRESS_MODE_REPEAT; +import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_FRAGMENT_BIT; +import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_GEOMETRY_BIT; +import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_VERTEX_BIT; +import static org.lwjgl.vulkan.VK10.vkCmdBindDescriptorSets; +import static org.lwjgl.vulkan.VK10.vkCmdBindIndexBuffer; +import static org.lwjgl.vulkan.VK10.vkCmdBindPipeline; +import static org.lwjgl.vulkan.VK10.vkCmdBindVertexBuffers; +import static org.lwjgl.vulkan.VK10.vkCmdDrawIndexed; +import static org.lwjgl.vulkan.VK10.vkCmdPushConstants; +import static org.lwjgl.vulkan.VK10.vkCmdSetScissor; +import static org.lwjgl.vulkan.VK10.vkCmdSetViewport; +import static org.lwjgl.vulkan.VK12.VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; +import static org.lwjgl.vulkan.VK13.*; public class ShadowRenderer { public static final int DEPTH_FORMAT = VK_FORMAT_D32_SFLOAT; @@ -19,4 +80,281 @@ public class ShadowRenderer { private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/shadow_vertex.glsl"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; + private final CascadeShadows[] cascadeShadows; + private final VkClearValue ClearValueColour; + private final VkClearValue ClearValueDepth; + private final Attachment colorAttachment; + private final VkRenderingAttachmentInfo.Buffer colorAttachmentInfo; + private final Attachment depthAttachment; + private final VkRenderingAttachmentInfo depthAttachmentInfo; + private final DescriptorSetLayout descLayoutFrgStorage; + private final Pipeline pipeline; + private final VulkanBuffer[] prjBuffers; + private final ByteBuffer pushConstBuff; + private final VkRenderingInfo renderingInfo; + private final DescriptorSetLayout textDescriptorSetLayout; + private final TextureSampler textureSampler; + private final DescriptorSetLayout uniformGeomDescriptorSetLayout; + + public ShadowRenderer(VulkanContext VulkanContext) { + ClearValueColour = VkClearValue.calloc().color( + c -> c.float32(0, 0.0f).float32(1, 0.0f).float32(2, 0.0f).float32(3, 0.0f)); + ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 1.0f)); + + depthAttachment = createDepthAttachment(VulkanContext); + depthAttachmentInfo = createDepthAttachmentInfo(depthAttachment, ClearValueDepth); + + colorAttachment = createColorAttachment(VulkanContext); + colorAttachmentInfo = createColorAttachmentInfo(colorAttachment, ClearValueColour); + + pushConstBuff = MemoryUtil.memAlloc(PUSH_CONSTANTS_SIZE); + + renderingInfo = createRenderInfo(colorAttachmentInfo, depthAttachmentInfo); + ShaderModule[] shaderModules = createShaderModules(VulkanContext); + + uniformGeomDescriptorSetLayout = new DescriptorSetLayout(VulkanContext, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, 1, VK_SHADER_STAGE_GEOMETRY_BIT)); + long buffSize = (long) VulkanUtils.MATRIX4X4_SIZE * SceneLightingManager.SHADOW_MAP_CASCADE_COUNT; + prjBuffers = VulkanUtils.CreateHostVisibleBuffers(VulkanContext, buffSize, VulkanUtils.MAX_IN_FLIGHT, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESCRIPTOR_ID_PRJ, uniformGeomDescriptorSetLayout); + + descLayoutFrgStorage = new DescriptorSetLayout(VulkanContext, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + 0, 1, VK_SHADER_STAGE_FRAGMENT_BIT)); + + var textureSamplerInfo = new TextureSamplerInfo(VK_SAMPLER_ADDRESS_MODE_REPEAT, + VK_BORDER_COLOR_INT_OPAQUE_BLACK, 1, true); + textureSampler = new TextureSampler(VulkanContext, textureSamplerInfo); + textDescriptorSetLayout = new DescriptorSetLayout(VulkanContext, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0, TextureCache.MAX_TEXTURES, VK_SHADER_STAGE_FRAGMENT_BIT)); + + pipeline = createPipeline(VulkanContext, shaderModules, new DescriptorSetLayout[]{uniformGeomDescriptorSetLayout, textDescriptorSetLayout, + descLayoutFrgStorage}); + Arrays.asList(shaderModules).forEach(s -> s.CleanUp(VulkanContext)); + + cascadeShadows = new CascadeShadows[VulkanUtils.MAX_IN_FLIGHT]; + for (int i = 0; i < VulkanUtils.MAX_IN_FLIGHT; i++) { + cascadeShadows[i] = new CascadeShadows(); + } + } + + private static Attachment createColorAttachment(VulkanContext VulkanContext) { + int shadowMapSize = EngineConfig.getInstance().GetShadowMapSize(); + return new Attachment(VulkanContext, shadowMapSize, shadowMapSize, + ATTACHMENT_FORMATT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, SceneLightingManager.SHADOW_MAP_CASCADE_COUNT); + } + + private static VkRenderingAttachmentInfo.Buffer createColorAttachmentInfo(Attachment srcAttachment, VkClearValue clearValue) { + return VkRenderingAttachmentInfo.calloc(1) + .sType$Default() + .imageView(srcAttachment.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 Attachment createDepthAttachment(VulkanContext VulkanContext) { + int shadowMapSize = EngineConfig.getInstance().GetShadowMapSize(); + return new Attachment(VulkanContext, shadowMapSize, shadowMapSize, + DEPTH_FORMAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, SceneLightingManager.SHADOW_MAP_CASCADE_COUNT); + } + + private static VkRenderingAttachmentInfo createDepthAttachmentInfo(Attachment depthAttachment, VkClearValue clearValue) { + return VkRenderingAttachmentInfo.calloc() + .sType$Default() + .imageView(depthAttachment.GetVkImageView().GetVulkanImageView()) + .imageLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + .loadOp(VK_ATTACHMENT_LOAD_OP_CLEAR) + .storeOp(VK_ATTACHMENT_STORE_OP_DONT_CARE) + .clearValue(clearValue); + } + + private static Pipeline createPipeline(VulkanContext VulkanContext, ShaderModule[] shaderModules, DescriptorSetLayout[] DescriptorSetLayouts) { + var vtxBuffStruct = new VertexBufferStructure(); + var buildInfo = new PipelineBuildInfo(shaderModules, vtxBuffStruct.getVertexInput(), new int[]{ATTACHMENT_FORMATT}) + .SetDepthFormat(DEPTH_FORMAT) + .SetPushConstantRanges( + new PushConstantsRange[]{ + new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT, 0, PUSH_CONSTANTS_SIZE) + }) + .SetDescriptorSetLayouts(DescriptorSetLayouts) + .SetDescriptorSetLayouts(DescriptorSetLayouts) + .SetDepthClamp(VulkanContext.GetDevice().getDepthClamp()); + var pipeline = new DefaultPipeline(VulkanContext, buildInfo); + vtxBuffStruct.cleanup(); + return pipeline; + } + + private static VkRenderingInfo createRenderInfo(VkRenderingAttachmentInfo.Buffer colorAttachmentInfo, + VkRenderingAttachmentInfo depthAttachments) { + var result = VkRenderingInfo.calloc().sType$Default(); + try (var stack = MemoryStack.stackPush()) { + int shadowMapSize = EngineConfig.getInstance().GetShadowMapSize(); + VkExtent2D extent = VkExtent2D.calloc(stack); + extent.width(shadowMapSize); + extent.height(shadowMapSize); + var renderArea = VkRect2D.calloc(stack).extent(extent); + result.renderArea(renderArea) + .layerCount(SceneLightingManager.SHADOW_MAP_CASCADE_COUNT) + .pColorAttachments(colorAttachmentInfo) + .pDepthAttachment(depthAttachments); + } + return result; + } + + private static ShaderModule[] createShaderModules(VulkanContext VulkanContext) { + if (EngineConfig.getInstance().RecompileShaders()) { + ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader); + ShaderCompiler.CompileGLSLShaderOnChange(SHADOW_GEOMETRY_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_geometry_shader); + ShaderCompiler.CompileGLSLShaderOnChange(FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_fragment_shader); + } + return new ShaderModule[]{ + new ShaderModule(VulkanContext, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV, null), + new ShaderModule(VulkanContext, VK_SHADER_STAGE_GEOMETRY_BIT, SHADOW_GEOMETRY_SHADER_FILE_SPV, null), + new ShaderModule(VulkanContext, VK_SHADER_STAGE_FRAGMENT_BIT, FRAGMENT_SHADER_FILE_SPV, null), + }; + } + + public void cleanup(VulkanContext VulkanContext) { + pipeline.CleanUp(VulkanContext); + uniformGeomDescriptorSetLayout.CleanUp(VulkanContext); + descLayoutFrgStorage.CleanUp(VulkanContext); + textDescriptorSetLayout.CleanUp(VulkanContext); + textureSampler.CleanUp(VulkanContext); + Arrays.asList(prjBuffers).forEach(b -> b.cleanup(VulkanContext)); + renderingInfo.free(); + depthAttachmentInfo.free(); + depthAttachment.CleanUp(VulkanContext); + colorAttachmentInfo.free(); + colorAttachment.CleanUp(VulkanContext); + MemoryUtil.memFree(pushConstBuff); + ClearValueColour.free(); + ClearValueDepth.free(); + } + + public CascadeShadows getCascadeShadows(int currentFrame) { + return cascadeShadows[currentFrame]; + } + + public Attachment getShadowAttachment() { + return colorAttachment; + } + + public void loadMaterials(VulkanContext VulkanContext, MaterialsCache materialsCache, TextureCache textureCache) { + DescriptorAllocator descAllocator = VulkanContext.GetDescriptorAllocator(); + Device device = VulkanContext.GetDevice(); + DescriptorSet descSet = descAllocator.AddDescriptorSet(device, DESCRIPTOR_ID_MAT, descLayoutFrgStorage); + DescriptorSetLayout.LayoutInformation layoutInfo = descLayoutFrgStorage.GetLayoutInfo(); + var buffer = materialsCache.GetMaterialsBuffer(); + descSet.SetBuffer(device, buffer, buffer.GetRequestedSize(), layoutInfo.Binding(), layoutInfo.DescriptorType()); + + List imageViews = textureCache.GetTextureList().stream().map(ITexture::GetImageView).toList(); + descSet = VulkanContext.GetDescriptorAllocator().AddDescriptorSet(device, DESCRIPTOR_ID_TEXT, textDescriptorSetLayout); + descSet.SetImageArray(device, imageViews, textureSampler, 0); + } + + public void render(EngineInstance engCtx, VulkanContext VulkanContext, CommandBuffer cmdBuffer, ModelsCache modelsCache, + MaterialsCache materialsCache, int currentFrame) { + try (var stack = MemoryStack.stackPush()) { + IScene scene = engCtx.scene(); + + ShadowUtils.updateCascadeShadows(cascadeShadows[currentFrame], scene); + + VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer(); + + VulkanUtils.ImageBarrier(stack, cmdHandle, colorAttachment.GetVkImage().getVulkanImage(), + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_2_NONE, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + VulkanUtils.ImageBarrier(stack, cmdHandle, depthAttachment.GetVkImage().getVulkanImage(), + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, + VK_ACCESS_2_NONE, + VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_IMAGE_ASPECT_DEPTH_BIT); + + vkCmdBeginRendering(cmdHandle, renderingInfo); + + vkCmdBindPipeline(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.GetVulkanPipeline()); + + int shadowMapSize = EngineConfig.getInstance().GetShadowMapSize(); + int width = shadowMapSize; + int height = shadowMapSize; + 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); + + updateProjBuffer(VulkanContext, currentFrame); + DescriptorAllocator descAllocator = VulkanContext.GetDescriptorAllocator(); + LongBuffer descriptorSets = stack.mallocLong(3) + .put(0, descAllocator.GetDescriptorSet(DESCRIPTOR_ID_PRJ, currentFrame).GetVkDescriptorSet()) + .put(1, descAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet()) + .put(2, descAllocator.GetDescriptorSet(DESCRIPTOR_ID_MAT).GetVkDescriptorSet()); + vkCmdBindDescriptorSets(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.GetVulkanPipelineLayout(), + 0, descriptorSets, null); + + LongBuffer vertexBuffer = stack.mallocLong(1); + LongBuffer offsets = stack.mallocLong(1).put(0, 0L); + + List entities = scene.GetActors(); + int numEntities = entities.size(); + for (int i = 0; i < numEntities; i++) { + var entity = entities.get(i); + VulkanModel model = modelsCache.GetModel(entity.GetModelID()); + List vulkanMeshList = model.GetVkMeshList(); + int numMeshes = vulkanMeshList.size(); + for (int j = 0; j < numMeshes; j++) { + var vulkanMesh = vulkanMeshList.get(j); + String materialId = vulkanMesh.MaterialID(); + int materialIdx = materialsCache.GetPosition(materialId); + VulkanMaterial vulkanMaterial = materialsCache.GetMaterial(materialId); + if (vulkanMaterial == null) { + Logger.warn("Mesh [{}] in model [{}] does not have material", j, model.GetID()); + continue; + } + setPushConstants(cmdHandle, entity.GetModelMatrix(), materialIdx); + vertexBuffer.put(0, vulkanMesh.VerticesBuffer().GetBuffer()); + + vkCmdBindVertexBuffers(cmdHandle, 0, vertexBuffer, offsets); + vkCmdBindIndexBuffer(cmdHandle, vulkanMesh.IndicesBuffer().GetBuffer(), 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdHandle, vulkanMesh.IndicesCount(), 1, 0, 0, 0); + } + } + + vkCmdEndRendering(cmdHandle); + } + } + + private void setPushConstants(VkCommandBuffer cmdHandle, Matrix4f modelMatrix, int materialIdx) { + modelMatrix.get(0, pushConstBuff); + pushConstBuff.putInt(VulkanUtils.MATRIX4X4_SIZE, materialIdx); + vkCmdPushConstants(cmdHandle, pipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, pushConstBuff); + } + + private void updateProjBuffer(VulkanContext VulkanContext, int currentFrame) { + int offset = 0; + List cascadeDataList = cascadeShadows[currentFrame].GetCascadeData(); + int numCascades = cascadeDataList.size(); + VulkanBuffer vkBuffer = prjBuffers[currentFrame]; + long mappedMemory = vkBuffer.MapMemory(VulkanContext); + ByteBuffer buff = MemoryUtil.memByteBuffer(mappedMemory, (int) vkBuffer.GetRequestedSize()); + for (int i = 0; i < numCascades; i++) { + CascadeData cascadeData = cascadeDataList.get(i); + cascadeData.GetProjViewMatrix().get(offset, buff); + offset += VulkanUtils.MATRIX4X4_SIZE; + } + vkBuffer.UnMapMemory(VulkanContext); + } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowUtils.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowUtils.java index 0f49bdd..ec83742 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowUtils.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Rendering/Shadows/ShadowUtils.java @@ -15,58 +15,65 @@ import java.util.List; public class ShadowUtils { private static final float LAMBDA = 0.95f; - private static final Vector3f Up = new Vector3f(0.0f,1.0f,0.0f); - private static final Vector3f UpAlt = new Vector3f(0.0f,0.0f,1.0f); - - private ShadowUtils(){ + private static final Vector3f UP = new Vector3f(0.0f, 1.0f, 0.0f); + private static final Vector3f UP_ALT = new Vector3f(0.0f, 0.0f, 1.0f); + private ShadowUtils() { } - public static void UpdateCascadeShadows(CascadeShadows shadows, IScene scene){ + public static void updateCascadeShadows(CascadeShadows cascadeShadows, IScene scene) { Camera camera = scene.GetCamera(); - Matrix4f ViewMatrix = camera.GetViewMatrix(); + Matrix4f viewMatrix = camera.GetViewMatrix(); Project3D projection = scene.GetProjection(); - Matrix4f ProjectionMatrix = projection.GetProjectionMatrix(); + Matrix4f projMatrix = projection.GetProjectionMatrix(); ILight[] lights = scene.GetLightingManager().GetLights(); - int LightCount = lights.length; - ILight SkyLight = null; - for(int i = 0; i < LightCount; i++){ - if(lights[i].IsDirectional()){ - SkyLight = lights[i]; + int numLights = lights.length; + ILight dirLight = null; + for (int i = 0; i < numLights; i++) { + if (lights[i].IsDirectional()) { + dirLight = lights[i]; break; } } - if(SkyLight == null){ - throw new RuntimeException("No SkyLight on scene"); + if (dirLight == null) { + throw new RuntimeException("Could not find directional light"); } - Vector4f LightPosition = new Vector4f(SkyLight.GetPosition(),0.0f); - float[] CascadeSplits = new float[SceneLightingManager.SHADOW_MAP_CASCADE_COUNT]; - float NearClip = Math.min(projection.GetNearZ(), projection.GetFarZ()); - float FarClip = Math.max(projection.GetNearZ(), projection.GetFarZ()); - float ClipRange = FarClip - NearClip; + Vector3f lightPos = dirLight.GetPosition(); - float MinZ = NearClip; - float MaxZ = NearClip + ClipRange; + float[] cascadeSplits = new float[SceneLightingManager.SHADOW_MAP_CASCADE_COUNT]; - float Range = MaxZ - MinZ; - float Ratio = MaxZ/MinZ; + float nearClip = projection.GetNearZ(); + float farClip = projection.GetFarZ(); + float clipRange = farClip - nearClip; - List cascadeDataList = shadows.GetCascadeData(); - int CascadeCount = cascadeDataList.size(); + if (nearClip <= 0.0f || farClip <= nearClip) { + //throw new IllegalStateException("Invalid projection near/far planes for shadow cascades: near=" + nearClip + ", far=" + farClip); + } - for(int i = 0; i < CascadeCount; i++){ + float minZ = nearClip; + float maxZ = nearClip + clipRange; + + float range = maxZ - minZ; + float ratio = maxZ / minZ; + + List cascadeDataList = cascadeShadows.GetCascadeData(); + int numCascades = cascadeDataList.size(); + + // Calculate split depths based on view camera frustum + // Based on method presented in https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch10.html + for (int i = 0; i < numCascades; i++) { float p = (i + 1) / (float) (SceneLightingManager.SHADOW_MAP_CASCADE_COUNT); - float Log = (float) (MinZ * Math.pow(Ratio, p)); - float Uniform = MinZ + Range * p; - float d = LAMBDA * (Log - Uniform) + Uniform; - CascadeSplits[i] = (d - NearClip) / ClipRange; + float log = (float) (minZ * java.lang.Math.pow(ratio, p)); + float uniform = minZ + range * p; + float d = LAMBDA * (log - uniform) + uniform; + cascadeSplits[i] = (d - nearClip) / clipRange; } - float LastSplitDist = 0.0f; - for(int i = 0; i < CascadeCount; i++){ - float SplitDist = CascadeSplits[i]; + float lastSplitDist = 0.0f; + for (int i = 0; i < numCascades; i++) { + float splitDist = cascadeSplits[i]; - Vector3f[] FustrumCorners = new Vector3f[]{ + Vector3f[] frustumCorners = new Vector3f[]{ new Vector3f(-1.0f, 1.0f, 0.0f), new Vector3f(1.0f, 1.0f, 0.0f), new Vector3f(1.0f, -1.0f, 0.0f), @@ -74,70 +81,73 @@ public class ShadowUtils { new Vector3f(-1.0f, 1.0f, 1.0f), new Vector3f(1.0f, 1.0f, 1.0f), new Vector3f(1.0f, -1.0f, 1.0f), - new Vector3f(-1.0f, -1.0f, 1.0f) + new Vector3f(-1.0f, -1.0f, 1.0f), }; - var InvertedCam = (new Matrix4f(ProjectionMatrix).mul(ViewMatrix)).invert(); - for(int j = 0; j < 8; j++){ - Vector4f InvertedCorner = new Vector4f(FustrumCorners[j],1.0f).mul(InvertedCam); - FustrumCorners[j] = new Vector3f(InvertedCorner.x,InvertedCorner.y,InvertedCorner.z).div(InvertedCorner.w); + // Project frustum corners into world space + var invCam = (new Matrix4f(projMatrix).mul(viewMatrix)).invert(); + for (int j = 0; j < 8; j++) { + Vector4f invCorner = new Vector4f(frustumCorners[j], 1.0f).mul(invCam); + frustumCorners[j] = new Vector3f(invCorner.x, invCorner.y, invCorner.z).div(invCorner.w); } - for(int j = 0; j < 4; j++){ - var Distance = new Vector3f(FustrumCorners[j + 4]).sub(FustrumCorners[j]); - FustrumCorners[j + 4] = new Vector3f(FustrumCorners[j]).add(new Vector3f(Distance).mul(SplitDist)); - FustrumCorners[j] = new Vector3f(FustrumCorners[j]).add(new Vector3f(Distance).mul(LastSplitDist)); + for (int j = 0; j < 4; j++) { + var dist = new Vector3f(frustumCorners[j + 4]).sub(frustumCorners[j]); + frustumCorners[j + 4] = new Vector3f(frustumCorners[j]).add(new Vector3f(dist).mul(splitDist)); + frustumCorners[j] = new Vector3f(frustumCorners[j]).add(new Vector3f(dist).mul(lastSplitDist)); } - var FustrumCenter = new Vector3f(0.0f); - for(int j = 0; j < 8; j++){ - FustrumCenter.add(FustrumCorners[j]); + var frustumCenter = new Vector3f(0.0f); + for (int j = 0; j < 8; j++) { + frustumCenter.add(frustumCorners[j]); } - FustrumCenter.div(8); + frustumCenter.div(8.0f); - var up = Up; - float SphereRadius = 0.0f; - for(int j = 0; j < 8; j++){ - float Distance = new Vector3f(FustrumCorners[j]).sub(FustrumCenter).length(); - SphereRadius = Math.max(SphereRadius,Distance); + var up = UP; + float sphereRadius = 0.0f; + for (int j = 0; j < 8; j++) { + float dist = new Vector3f(frustumCorners[j]).sub(frustumCenter).length(); + sphereRadius = java.lang.Math.max(sphereRadius, dist); } - SphereRadius = (float)Math.ceil(SphereRadius * 16.0f) / 16.0f; + sphereRadius = (float) java.lang.Math.ceil(sphereRadius * 16.0f) / 16.0f; - var MaxExtents = new Vector3f(SphereRadius); - var MinExtents = new Vector3f(-SphereRadius); + var maxExtents = new Vector3f(sphereRadius, sphereRadius, sphereRadius); + var minExtents = new Vector3f(maxExtents).mul(-1.0f); - var LightDirection = new Vector3f(LightPosition.x, LightPosition.y, LightPosition.z); - var ShadowCamPosition = new Vector3f(FustrumCenter).add(LightDirection.mul(MinExtents.z)); + var lightDir = new Vector3f(lightPos.x, lightPos.y, lightPos.z); + var shadowCameraPos = new Vector3f(frustumCenter).add(lightDir.mul(minExtents.z)); - float Dot = Math.abs(new Vector3f(LightPosition.x, LightPosition.y, LightPosition.z).dot(up)); - if(Dot == 1.0f){ - up = UpAlt; + float dot = java.lang.Math.abs(new Vector3f(lightPos.x, lightPos.y, lightPos.z).dot(up)); + if (dot == 1.0f) { + up = UP_ALT; } - var LightViewMatrix = new Matrix4f().lookAt(ShadowCamPosition,FustrumCenter,up); - var LightOrthoMatrix = new Matrix4f().ortho(MinExtents.x,MaxExtents.x,MinExtents.y,MaxExtents.y,0.0f,MaxExtents.z - MinExtents.z,true); + var lightViewMatrix = new Matrix4f().lookAt(shadowCameraPos, frustumCenter, up); + var lightOrthoMatrix = new Matrix4f().ortho + (minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, 0.0f, maxExtents.z - minExtents.z, true); - int ShadowMapSize = EngineConfig.getInstance().GetShadowMapSize(); - Vector4f ShadowOrigin = new Vector4f(0f,0f,0f,1f); - LightViewMatrix.transform(ShadowOrigin); - ShadowOrigin.mul(ShadowMapSize/2.0f); + int shadowMapSize = EngineConfig.getInstance().GetShadowMapSize(); + Vector4f shadowOrigin = new Vector4f(0.0f, 0.0f, 0.0f, 1.0f); + lightViewMatrix.transform(shadowOrigin); + shadowOrigin.mul(shadowMapSize / 2.0f); - Vector4f RoundedOrigin = new Vector4f(ShadowOrigin).round(); - Vector4f RoundOffset = RoundedOrigin.sub(ShadowOrigin); - RoundOffset.mul(2.0f/ShadowMapSize); - RoundOffset.z = 0.0f; - RoundOffset.w = 0.0f; + Vector4f roundedOrigin = new Vector4f(shadowOrigin).round(); + Vector4f roundOffset = roundedOrigin.sub(shadowOrigin); + roundOffset.mul(2.0f / shadowMapSize); + roundOffset.z = 0.0f; + roundOffset.w = 0.0f; - LightOrthoMatrix.m30(LightOrthoMatrix.m30() + RoundOffset.x); - LightOrthoMatrix.m31(LightOrthoMatrix.m31() + RoundOffset.y); - LightOrthoMatrix.m32(LightOrthoMatrix.m32() + RoundOffset.z); - LightOrthoMatrix.m33(LightOrthoMatrix.m33() + RoundOffset.w); + lightOrthoMatrix.m30(lightOrthoMatrix.m30() + roundOffset.x); + lightOrthoMatrix.m31(lightOrthoMatrix.m31() + roundOffset.y); + lightOrthoMatrix.m32(lightOrthoMatrix.m32() + roundOffset.z); + lightOrthoMatrix.m33(lightOrthoMatrix.m33() + roundOffset.w); + // Store split distance and matrix in cascade CascadeData cascadeData = cascadeDataList.get(i); - cascadeData.SetSplitDistance((NearClip + SplitDist * ClipRange) * -1.0f); - cascadeData.SetProjectionViewMatrix(LightOrthoMatrix.mul(LightViewMatrix)); + cascadeData.SetSplitDistance((nearClip + splitDist * clipRange) * -1.0f); + cascadeData.SetProjectionViewMatrix(lightOrthoMatrix.mul(lightViewMatrix)); - LastSplitDist = CascadeSplits[i]; + lastSplitDist = cascadeSplits[i]; } } } 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 88d0063..8b39f45 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 @@ -157,10 +157,7 @@ public class SpriteRenderer { .SetDepthWrite(DepthWrite) .SetPushConstantRanges( new PushConstantsRange[]{ - new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,0,VulkanUtils.VEC2_SIZE), - new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,VulkanUtils.VEC2_SIZE,VulkanUtils.VEC2_SIZE), - new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,VulkanUtils.VEC2_SIZE * 2,VulkanUtils.VEC2_SIZE), - new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,VulkanUtils.VEC2_SIZE * 3,VulkanUtils.FLOAT_SIZE), + new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,0,VulkanUtils.VEC2_SIZE * 3 + VulkanUtils.FLOAT_SIZE), new PushConstantsRange(VK_SHADER_STAGE_FRAGMENT_BIT,VulkanUtils.VEC2_SIZE * 3 + VulkanUtils.FLOAT_SIZE,VulkanUtils.INT_SIZE) }) .SetDescriptorSetLayouts(DescriptorSetLayouts) 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 517b02c..903ad96 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 @@ -20,6 +20,7 @@ import static org.lwjgl.vulkan.KHRPortabilitySubset.VK_KHR_PORTABILITY_SUBSET_EX import static org.lwjgl.vulkan.VK13.*; public class Device { + private final boolean depthClamp; private final VkDevice VulkanDevice; private final boolean SamplesAnisotropy; @@ -37,14 +38,15 @@ public class Device { .queueFamilyIndex(i) .pQueuePriorities(Priorities); } + var features12 = VkPhysicalDeviceVulkan12Features.calloc(MemStack) + .sType$Default() + .scalarBlockLayout(true); var features13 = VkPhysicalDeviceVulkan13Features.calloc(MemStack) .sType$Default() .dynamicRendering(true) .synchronization2(true); - var features12 = VkPhysicalDeviceVulkan12Features.calloc(MemStack) - .sType$Default() - .scalarBlockLayout(true); + var features2 = VkPhysicalDeviceFeatures2.calloc(MemStack).sType$Default(); var features = features2.features(); @@ -53,8 +55,11 @@ public class Device { if(SamplesAnisotropy){ features.samplerAnisotropy(true); } - features2.pNext(features13.address()); - features13.pNext(features12.address()); + features.geometryShader(true); + depthClamp = SupportedFeatures.depthClamp(); + features.depthClamp(depthClamp); + features2.pNext(features12.address()); + features12.pNext(features13.address()); var DeviceCreateInfo = VkDeviceCreateInfo.calloc(MemStack) .sType$Default() @@ -75,6 +80,10 @@ public class Device { } } + public boolean getDepthClamp() { + return depthClamp; + } + private static PointerBuffer CreateRequiredExtensions(PhysicalDevice PhysDevice, MemoryStack MemStack){ Set DeviceExtensions = GetDeviceExtensions(PhysDevice); //cross platform support for that fuckass Metal API mac uses diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java index d4b8e28..08261b5 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/DeferredSceneRender.java @@ -108,7 +108,7 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering public DeferredSceneRender(VulkanContext vulkanContext, EngineInstance engineInstance){ ClearValueColour = VkClearValue.calloc().color( c -> c.float32(0, 0.0f).float32(1, 0.0f).float32(2, 0.0f).float32(3, 0.0f)); - ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 0.0f)); + ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 1.0f)); MRTAttachments = new MultiRenderTargetAttachments(vulkanContext); AttachmentInfoColour = CreateColourAttachmentInfo(MRTAttachments, ClearValueColour); AttachmentInfoDepth = CreateDepthAttachmentInfo(MRTAttachments, ClearValueDepth); @@ -267,7 +267,7 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering .SetDepthTest(true) .SetPushConstantRanges(new PushConstantsRange[0]) .SetDescriptorSetLayouts(DescriptorSetLayouts) - .BlendingIsUsed(true) + .BlendingIsUsed(false) .SetDualPass(false) .SetAlphaToCoverage(false); var pipeline = new DefaultPipeline(VkCtx, BuildInfo); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java index 9f45e4d..82d7664 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ForwardSceneRender.java @@ -117,7 +117,7 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering public ForwardSceneRender(VulkanContext vulkanContext){ ClearValueColour = VkClearValue.calloc().color( c -> c.float32(0, R).float32(1, G).float32(2, B).float32(3, 1.0f)); - ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 0.0f)); + ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 1.0f)); CreateRenderAttachments(vulkanContext); PushConstBuffer = (MemoryUtil.memAlloc(PUSH_CONSTANTS_SIZE)); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ImageView.java b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ImageView.java index d4567a3..f7c4b98 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ImageView.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/RenderingAPI/Vulkan/Structure/DisplayToScreen/ImageView.java @@ -17,12 +17,14 @@ public class ImageView { private final long VulkanImage; private final long VulkanImageView; private final boolean DepthImage; + private final int layerCount; public ImageView(Device device, long vulkanImage, ImageViewData imageViewData, boolean DepthImage){ this.AspectMask = imageViewData.AspectMask; this.MipLevels = imageViewData.MipLevels; this.VulkanImage = vulkanImage; this.DepthImage = DepthImage; + this.layerCount = imageViewData.LayerCount; try(var MemStack = MemoryStack.stackPush()){ LongBuffer LongPointer = MemStack.mallocLong(1); var ViewCreateInfo = VkImageViewCreateInfo.calloc(MemStack) @@ -46,6 +48,10 @@ public class ImageView { vkDestroyImageView(device.FetchVulkanDevice(), VulkanImageView, null); } + public int GetLayerCount() { + return layerCount; + } + public int GetAspectMask(){ return AspectMask; } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java index ed9d455..dd7ff71 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java @@ -37,15 +37,16 @@ public class RenderThread extends EngineThread { public InitData GetInitData(){return initData;} public void RestartCrashedRenderer(){ - if(Headless) return; - if(VulkanCrashCount < EngineConfig.getInstance().GetMaxVulkanCrashes()){ - RefreshRenderer(); - VulkanCrashCount++; - }else{ - Logger.error("MAX API CRASHES REACHED, CLOSING SOFTWARE"); - PrimaryRuntime.GetEngineInstance().window().setShouldClose(); - PrimaryRuntime.CloseRuntime(); - } + throw new IllegalStateException("Vulkan device lost; terminating renderer instead of hot-restarting"); +// if(Headless) return; +// if(VulkanCrashCount < EngineConfig.getInstance().GetMaxVulkanCrashes()){ +// RefreshRenderer(); +// VulkanCrashCount++; +// }else{ +// Logger.error("MAX API CRASHES REACHED, CLOSING SOFTWARE"); +// PrimaryRuntime.GetEngineInstance().window().setShouldClose(); +// PrimaryRuntime.CloseRuntime(); +// } } public Renderer GetRenderer(){return render;} diff --git a/terrain4j.properties b/terrain4j.properties index cfd03fa..a6e6515 100644 --- a/terrain4j.properties +++ b/terrain4j.properties @@ -11,7 +11,7 @@ Renderer=1 RenderingAPI=Vulkan RequestedImages=3 ShaderRecompiling=true -ShadowMapSize=2048 +ShadowMapSize=4096 Software_Icon=ProgramIcon.png Software_Icon_Path=/WindowResources/Icon/ Software_Title=Terrain4J Game Engine @@ -35,5 +35,5 @@ throttle_on_unfocus=false user_display_name=TheSigma vkValidated=true vsync=false -z_far_plane=0.1f -z_near_plane=10000.0f +z_near_plane=0.1f +z_far_plane=10000.0f