From 5943effa4e39afe2ac20624158bb66191710ddeb Mon Sep 17 00:00:00 2001 From: Halbear Date: Sat, 13 Jun 2026 00:12:13 +0100 Subject: [PATCH] rendering settings and dual pipeline transparency rendering --- .../shaders/scene_opaque_fragment.glsl | 35 ++++ .../shaders/scene_translucent_fragment.glsl | 35 ++++ .../Terrain4J/EngineCore/Display/Render.java | 6 + .../EngineCore/Logic/EngineConfig.java | 24 +++ .../Terrain4J/EngineCore/Main/GameCore.java | 170 +++++++++++++----- .../EngineCore/Threads/RenderThread.java | 9 +- .../Rendering/Pipeline/DefaultPipeline.java | 4 +- .../Rendering/Pipeline/PipelineBuildInfo.java | 21 +++ .../DisplayToScreen/SceneRender.java | 106 ++++++++--- terrain4j.properties | 2 +- 10 files changed, 340 insertions(+), 72 deletions(-) create mode 100644 resources/EngineResources/shaders/scene_opaque_fragment.glsl create mode 100644 resources/EngineResources/shaders/scene_translucent_fragment.glsl diff --git a/resources/EngineResources/shaders/scene_opaque_fragment.glsl b/resources/EngineResources/shaders/scene_opaque_fragment.glsl new file mode 100644 index 0000000..847ccf1 --- /dev/null +++ b/resources/EngineResources/shaders/scene_opaque_fragment.glsl @@ -0,0 +1,35 @@ +#version 450 + +const int MAX_TEXTURES = 500; + +layout(location = 0) in vec2 inTextCoords; +layout(location = 0) out vec4 outFragColor; + +struct Material{ + vec4 diffuseColor; + uint hasTexture; + uint textureIdx; + uint padding[2]; +}; + +layout(set = 2, binding = 0) readonly buffer MaterialUniform{ + Material materials[]; +} matUniform; + +layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES]; + +layout(push_constant) uniform pc{ + layout(offset = 64) uint materialIdx; +} push_constants; + +void main() +{ + Material material = matUniform.materials[push_constants.materialIdx]; + if(material.hasTexture == 1){ + vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords); + if(texColor.a < 0.9){discard;} + outFragColor = texColor; + } else{ + outFragColor = material.diffuseColor; + } +} \ No newline at end of file diff --git a/resources/EngineResources/shaders/scene_translucent_fragment.glsl b/resources/EngineResources/shaders/scene_translucent_fragment.glsl new file mode 100644 index 0000000..3f38520 --- /dev/null +++ b/resources/EngineResources/shaders/scene_translucent_fragment.glsl @@ -0,0 +1,35 @@ +#version 450 + +const int MAX_TEXTURES = 500; + +layout(location = 0) in vec2 inTextCoords; +layout(location = 0) out vec4 outFragColor; + +struct Material{ + vec4 diffuseColor; + uint hasTexture; + uint textureIdx; + uint padding[2]; +}; + +layout(set = 2, binding = 0) readonly buffer MaterialUniform{ + Material materials[]; +} matUniform; + +layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES]; + +layout(push_constant) uniform pc{ + layout(offset = 64) uint materialIdx; +} push_constants; + +void main() +{ + Material material = matUniform.materials[push_constants.materialIdx]; + if(material.hasTexture == 1){ + vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords); + if(texColor.a < 0.05 || texColor.a >= 0.9){discard;} + outFragColor = texColor; + } else{ + outFragColor = material.diffuseColor; + } +} \ No newline at end of file diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Render.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Render.java index bd86643..1138a2c 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Render.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Render.java @@ -1,5 +1,6 @@ package net.halbear.Terrain4J.EngineCore.Display; +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; import net.halbear.Terrain4J.EngineCore.Logic.InitData; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; @@ -52,11 +53,15 @@ public class Render { private List Models = new ArrayList<>(); private final MaterialsCache materialsCache; private TextureCache textureCache; + private EngineConfig.AntiAliasType CurrentAAMode; public TextureCache GetTextureCache(){return textureCache;} public MaterialsCache GetMaterialsCache(){return materialsCache;} public VulkanContext GetVulkanContext(){return RendererContext;} + public EngineConfig.AntiAliasType GetCurrentAAMode(){return CurrentAAMode;} + public SceneRender GetSceneRender(){return (SceneRender) sceneRender;} + public Render(EngineInstance engineInstance) { RendererContext = new VulkanContext(engineInstance.window()); CurrentFrame = 0; @@ -85,6 +90,7 @@ public class Render { materialsCache = new MaterialsCache(); modelsCache = new ModelsCache(); Resize = false; + CurrentAAMode = EngineConfig.getInstance().RenderAAType(); } public void Initialise(InitData initData){ 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 84db53f..22cb4b5 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java @@ -68,7 +68,10 @@ public class EngineConfig { public String CPU_NAME = "Vulkan compatible device"; public int CPU_CORE_COUNT = 0; public String CPU_DETAILS = ""; + public boolean AlphaToCoverage = false; + public boolean AlphaToCoverage(){return AlphaToCoverage;} + public void SetAlphaToCoverage(boolean AlphaToCoverage){this.AlphaToCoverage = AlphaToCoverage;} public String GetGPU(){return GPU_NAME;} public void SetGPU(String Gpu){GPU_NAME = Gpu;} public void SetCPU(String Name, int CoreCount){ @@ -91,6 +94,27 @@ public class EngineConfig { public List GetSystemProfiling(){return SystemProfiling;} public void SetMemoryProfiling(List memory){MemoryProfiling = memory;} public void SetSystemProfiling(List Profiling){SystemProfiling = Profiling;} + public void SetRenderAAType(int type){ + AAValue = type; + switch(type){ + case 0: + AAMode = AntiAliasType.NONE; + break; + case 2: + AAMode = AntiAliasType.MSAAx2; + break; + case 3: + AAMode = AntiAliasType.MSAAx4; + break; + case 4: + AAMode = AntiAliasType.MSAAx8; + break; + case 1: + default: + AAMode = AntiAliasType.FXAA; + break; + } + } public enum AntiAliasType{ NONE, 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 6dd1599..760d46a 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/GameCore.java @@ -2,6 +2,7 @@ package net.halbear.Terrain4J.EngineCore.Main; import imgui.ImGui; import imgui.ImGuiIO; +import imgui.ImGuiViewport; import imgui.ImVec2; import imgui.flag.ImGuiCond; import imgui.flag.ImGuiWindowFlags; @@ -18,6 +19,7 @@ import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler; import net.halbear.Terrain4J.EngineCore.Vulkan.GUI.GuiTexture; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MaterialData; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData; +import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.SceneRender; import org.joml.Vector2f; import org.joml.Vector3f; @@ -30,7 +32,7 @@ import static org.lwjgl.glfw.GLFW.*; public class GameCore implements GameLogic { private static final float MOUSE_SENSITIVITY = 0.1f; - private static final float MOVEMENT_SPEED = 1f; + private static final float MOVEMENT_SPEED = 0.05f; private final Vector3f rotatingAngle = new Vector3f(0, 1, 0); private float angle = 180; private List angles = new ArrayList<>(); @@ -45,6 +47,10 @@ public class GameCore implements GameLogic { private List PerformanceMetrics = new ArrayList<>(); private List SettingPerformanceMetrics = new ArrayList<>(); private boolean FetchingMetrics = false; + private boolean ChangeGraphicsSettings = false; + private int NextAAMode = -1; + private long LastFrameTime = 0; + private long CoolDown = 1000; @Override public void cleanup() { @@ -56,38 +62,38 @@ public class GameCore implements GameLogic { Scene scene = engineInstance.scene(); List models = new ArrayList<>(); - //ModelData SponzaData = ModelLoader.LoadModel("resources/models/Sponza/Sponza.json"); - //List SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Sponza/Sponza_mat.json"); - 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"); + ModelData SponzaData = ModelLoader.LoadModel("resources/models/Forest/forest.json"); + List SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Forest/forest_mat.json"); + //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 Actor("Sponza1", SponzaData.ID(), new Vector3f(0,0,-5f))); - scene.AddActor(new Actor("Sponza2", SponzaData1.ID(), new Vector3f(0,0,-5f))); + //scene.AddActor(new Actor("Sponza2", SponzaData1.ID(), new Vector3f(0,0,-5f))); - //models.add(ModelLoader.LoadModel("resources/models/Metro/OBJ/MetroLeadCar.json")); - //models.add(ModelLoader.LoadModel("resources/models/melona/melona.json")); - //models.add(ModelLoader.LoadModel("resources/models/Alice/Welsh040Alice.json")); - //models.add(ModelLoader.LoadModel("resources/models/Sloop/SloopOBJ.json")); - //models.add(ModelLoader.LoadModel("resources/models/Corvette/corvetteclass.json")); - //for(int i = 0; i < 0; i++) { - // CubeActors.add(new Actor("AdvancedModel" + i, models.get((int)Math.round(Math.min(Math.max(Math.random() *(Math.random() * models.size() - 1),0),models.size() - 1))).ID(), new Vector3f((float)(-200 + Math.random() * 400), (float)(-50 + Math.random() * 100), (float)(250 + Math.random() * -500)))); - // angles.add((float)(Math.random() * 360)); - // rotatingAngles.add(new Vector3f((float)(Math.random()*2), (float)(Math.random()*2), (float)(Math.random()*2))); - // Velocities.add(new Vector3f((float)(-2 + Math.random()*4), -2 + (float)(Math.random()*4), -2 + (float)(Math.random()*4))); - // } + models.add(ModelLoader.LoadModel("resources/models/Metro/OBJ/MetroLeadCar.json")); + models.add(ModelLoader.LoadModel("resources/models/melona/melona.json")); + models.add(ModelLoader.LoadModel("resources/models/Alice/Welsh040Alice.json")); + models.add(ModelLoader.LoadModel("resources/models/Sloop/SloopOBJ.json")); + models.add(ModelLoader.LoadModel("resources/models/Corvette/corvetteclass.json")); + for(int i = 0; i < 0; i++) { + CubeActors.add(new Actor("AdvancedModel" + i, models.get((int)Math.round(Math.min(Math.max(Math.random() *(Math.random() * models.size() - 1),0),models.size() - 1))).ID(), new Vector3f((float)(-200 + Math.random() * 400), (float)(-50 + Math.random() * 100), (float)(250 + Math.random() * -500)))); + angles.add((float)(Math.random() * 360)); + rotatingAngles.add(new Vector3f((float)(Math.random()*2), (float)(Math.random()*2), (float)(Math.random()*2))); + Velocities.add(new Vector3f((float)(-2 + Math.random()*4), -2 + (float)(Math.random()*4), -2 + (float)(Math.random()*4))); + } CubeActors.forEach(scene::AddActor); List materials = new ArrayList<>(); - //materials.addAll(ModelLoader.LoadMaterials("resources/models/Metro/OBJ/MetroLeadCar_mat.json")); - //materials.addAll(ModelLoader.LoadMaterials("resources/models/Corvette/corvetteclass_mat.json")); - //materials.addAll(ModelLoader.LoadMaterials("resources/models/melona/melona_mat.json")); - //materials.addAll(ModelLoader.LoadMaterials("resources/models/Alice/Welsh040Alice_mat.json")); - //materials.addAll(ModelLoader.LoadMaterials("resources/models/Sloop/SloopOBJ_mat.json")); + materials.addAll(ModelLoader.LoadMaterials("resources/models/Metro/OBJ/MetroLeadCar_mat.json")); + materials.addAll(ModelLoader.LoadMaterials("resources/models/Corvette/corvetteclass_mat.json")); + materials.addAll(ModelLoader.LoadMaterials("resources/models/melona/melona_mat.json")); + materials.addAll(ModelLoader.LoadMaterials("resources/models/Alice/Welsh040Alice_mat.json")); + materials.addAll(ModelLoader.LoadMaterials("resources/models/Sloop/SloopOBJ_mat.json")); materials.addAll(SponzaMaterial); - materials.addAll(SponzaMaterial1); + //materials.addAll(SponzaMaterial1); models.add(SponzaData); - models.add(SponzaData1); + //models.add(SponzaData1); Camera camera = scene.GetCamera(); camera.SetPosition(40.0f, 155.0f, -42.0f); camera.SetPosition(0,0,0); @@ -127,6 +133,18 @@ public class GameCore implements GameLogic { @Override public void RenderThreadInput(EngineInstance engineInstance, long FrameDiffNanoSeconds) { + if(ChangeGraphicsSettings){ + if(NextAAMode != -1){ + EngineConfig.getInstance().SetRenderAAType(NextAAMode); + NextAAMode = -1; + } + if((System.nanoTime() - LastFrameTime)/1000000.0 > CoolDown){ + ChangeGraphicsSettings = false; + LastFrameTime = System.nanoTime(); + } + } else{ + LastFrameTime = System.nanoTime(); + } HandleGui(engineInstance, FrameDiffNanoSeconds); } @@ -178,17 +196,16 @@ public class GameCore implements GameLogic { imGuiIO.addMousePosEvent(mousePosition.x,mousePosition.y); imGuiIO.addMouseButtonEvent(0,mouseListener.isLeftButtonPressed()); imGuiIO.addMouseButtonEvent(1,mouseListener.isRightButtonPressed()); - + int windowFlags = ImGuiWindowFlags.NoDecoration + | ImGuiWindowFlags.AlwaysAutoResize + | ImGuiWindowFlags.NoSavedSettings + | ImGuiWindowFlags.NoFocusOnAppearing + | ImGuiWindowFlags.NoNav + | ImGuiWindowFlags.NoMove; + ImGui.newFrame(); if(GUI_MODE == 0){ double FrameTimeMS = (frameTimeNS/1000000.0); double AverageGPUTimeMS = EngineConfig.LAST_AVERAGE_GPU_TIME/1000000.0; - int windowFlags = ImGuiWindowFlags.NoDecoration - | ImGuiWindowFlags.AlwaysAutoResize - | ImGuiWindowFlags.NoSavedSettings - | ImGuiWindowFlags.NoFocusOnAppearing - | ImGuiWindowFlags.NoNav - | ImGuiWindowFlags.NoMove; - ImGui.newFrame(); ImGui.setNextWindowPos(0,0, ImGuiCond.Always); //ImGui.setNextWindowSize(300,100); ImGui.begin("FPS overlay",windowFlags); @@ -198,6 +215,64 @@ public class GameCore implements GameLogic { ImGui.text(String.format("Primary Thread FPS: " + EngineConfig.FrameRate_PRIMARYTHREAD + "fps | GLFW Window FrameRate:" + EngineConfig.FrameRate_WINDOW + "fps | TPS: " + EngineConfig.TPS_PRIMARYTHREAD)); ImGui.text(String.format("Main Thread FPS: " + EngineConfig.FrameRate_MAINENGINETHREAD + "fps | TPS: " + EngineConfig.TPS_MAINENGINETHREAD)); ImGui.text(String.format("Fast Thread FPS: " + EngineConfig.FrameRate_FASTENGINETHREAD + "fps | TPS: " + EngineConfig.TPS_FASTENGINETHREAD)); + ImGui.separator(); + ImGui.text("GRAPHICS SETTINGS:"); + ImGui.text(" "); + ImGui.text("anti aliasing:"); + if(ImGui.button("No AA")){ + ChangeGraphicsSettings = true; + CoolDown = 2000; + NextAAMode = (0); + } + ImGui.sameLine(); + if(ImGui.button("FXAA")){ + ChangeGraphicsSettings = true; + CoolDown = 2000; + NextAAMode = (1); + } + ImGui.sameLine(); + if(ImGui.button("MSAAx2")){ + ChangeGraphicsSettings = true; + CoolDown = 2000; + NextAAMode = (2); + } + ImGui.sameLine(); + if(ImGui.button("MSAAx4")){ + ChangeGraphicsSettings = true; + CoolDown = 2000; + NextAAMode = (3); + } + ImGui.sameLine(); + if(ImGui.button("MSAAx8")){ + ChangeGraphicsSettings = true; + CoolDown = 2000; + NextAAMode = 4; + } + ImGui.text("pipeline:"); + if(ImGui.button("Single Pass")){ + ChangeGraphicsSettings = true; + CoolDown = 500; + SceneRender.SetDualPassRendering(false); + } + ImGui.sameLine(); + if(ImGui.button("dual Pass")){ + ChangeGraphicsSettings = true; + CoolDown = 500; + SceneRender.SetDualPassRendering(true); + } + if(ImGui.button("AlphaToCoverage False")){ + ChangeGraphicsSettings = true; + CoolDown = 500; + EngineConfig.getInstance().SetAlphaToCoverage(false); + PrimaryRuntime.GetRenderThread().GetRenderer().GetSceneRender().RebuildPipelines(PrimaryRuntime.GetRenderThread().GetRenderer().GetVulkanContext()); + } + ImGui.sameLine(); + if(ImGui.button("AlphaToCoverage True")){ + ChangeGraphicsSettings = true; + CoolDown = 500; + EngineConfig.getInstance().SetAlphaToCoverage(true); + PrimaryRuntime.GetRenderThread().GetRenderer().GetSceneRender().RebuildPipelines(PrimaryRuntime.GetRenderThread().GetRenderer().GetVulkanContext()); + } if(PerformanceMetrics.size() > 0) { ImGui.text(" "); ImGui.separator(); @@ -212,22 +287,26 @@ public class GameCore implements GameLogic { } } ImGui.end(); - ImGui.endFrame(); - ImGui.render(); } else if (GUI_MODE == 1){ - ImGui.newFrame(); ImGui.setNextWindowPos(0,0, ImGuiCond.Always); ImGui.setNextWindowSize(500,500); ImGui.begin("Test Window"); ImGui.image(guiTexture.ID(),new ImVec2(300,300)); ImGui.end(); - ImGui.endFrame(); - ImGui.render(); } else if (GUI_MODE == 2){ - ImGui.newFrame(); - ImGui.endFrame(); - ImGui.render(); } + if (ChangeGraphicsSettings){ + ImGuiViewport viewport = ImGui.getMainViewport(); + float CenterX = viewport.getWorkPosX() + viewport.getWorkSizeX() / 2.0f; + float CenterY = viewport.getWorkPosY() + viewport.getWorkSizeY() / 2.0f; + ImGui.setNextWindowPos(CenterX,CenterY, ImGuiCond.Always,0.5f,0.5f); + ImGui.begin("change notification",windowFlags); + ImGui.setWindowFontScale(4.0f); + ImGui.text("APPLYING GRAPHICS SETTINGS..."); + ImGui.end(); + } + ImGui.endFrame(); + ImGui.render(); FetchingMetrics = false; return imGuiIO.getWantCaptureKeyboard(); } @@ -236,10 +315,7 @@ public class GameCore implements GameLogic { public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) { float DeltaTime = (float)(FrameDiffNanoSeconds/16000000.0); for(int i = 0; i < angles.size()/2; i++) { - angles.set(i, (angles.get(i) + 0.1f* DeltaTime) % 360); - CubeActors.get(i).GetRotation().identity().rotateAxis((float) EngineConfig.DegToRad * angles.get(i), rotatingAngles.get(i)); - CubeActors.get(i).GetPosition().add((Velocities.get(i).x/100.0f) * DeltaTime,(Velocities.get(i).y/100.0f) * DeltaTime,(Velocities.get(i).z/100.0f) * DeltaTime); - CubeActors.get(i).UpdateModelMatrix(); + } Ticks++; if(Ticks == 1000){ @@ -250,7 +326,7 @@ public class GameCore implements GameLogic { @Override public void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds) { float DeltaTime = (float)(FrameDiffNanoSeconds/16000000.0); - for(int i = angles.size()/2; i < angles.size(); i++) { + for(int i = 0; i < angles.size(); i++) { angles.set(i, (angles.get(i) + 1.0f* DeltaTime) % 360); CubeActors.get(i).GetRotation().identity().rotateAxis((float) EngineConfig.DegToRad * angles.get(i), rotatingAngles.get(i)); CubeActors.get(i).GetPosition().add((Velocities.get(i).x/100.0f) * DeltaTime,(Velocities.get(i).y/100.0f) * DeltaTime,(Velocities.get(i).z/100.0f) * DeltaTime); 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 0ad957f..ce4e020 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java @@ -15,13 +15,15 @@ import java.util.Collections; import java.util.List; public class RenderThread extends EngineThread { - private final Render render; + private Render render; private Window window; + private final InitData initData; public RenderThread(Window window, EngineInstance engineInstance, InitData initData, GameLogic appLogic) { //this.window = window; render = new Render(engineInstance); super(engineInstance,appLogic,"Render"); + this.initData = initData; render.Initialise(initData); } @@ -48,6 +50,11 @@ public class RenderThread extends EngineThread { EngineConfig.getInstance().SetMemoryProfiling(Profiling); EngineConfig.FrameRate_RENDERTHREAD = Frames; EngineConfig.TPS_RENDERTHREAD = TickFrames; + if(render.GetCurrentAAMode() != EngineConfig.getInstance().RenderAAType()){ + render.cleanup(); + render = new Render(PrimaryRuntime.GetEngineInstance()); + render.Initialise(initData); + } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/DefaultPipeline.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/DefaultPipeline.java index bd6b1b5..94a5fb7 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/DefaultPipeline.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/DefaultPipeline.java @@ -81,7 +81,7 @@ public class DefaultPipeline implements Pipeline { .sampleShadingEnable(false) .minSampleShading(1.0f) .pSampleMask(null) - .alphaToCoverageEnable(false) + .alphaToCoverageEnable(BuildInfo.AlphaToCoverage()) .alphaToOneEnable(false); VkPipelineDepthStencilStateCreateInfo DepthStencil = null; @@ -89,7 +89,7 @@ public class DefaultPipeline implements Pipeline { DepthStencil = VkPipelineDepthStencilStateCreateInfo.calloc(MemStack) .sType(VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO) .depthTestEnable(true) - .depthWriteEnable(true) + .depthWriteEnable(BuildInfo.performDepthWrite()) .depthCompareOp(VK_COMPARE_OP_GREATER_OR_EQUAL) .depthBoundsTestEnable(false) .stencilTestEnable(false); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java index 298a520..78d8fd6 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Rendering/Pipeline/PipelineBuildInfo.java @@ -1,5 +1,6 @@ package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline; +import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSet; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSetLayout; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderModule; import org.lwjgl.vulkan.VkPipelineVertexInputStateCreateInfo; @@ -15,6 +16,9 @@ public class PipelineBuildInfo { private PushConstantsRange[] PushConstRanges; private DescriptorSetLayout[] DescriptorSetLayouts; private boolean useBlend; + private boolean DepthWrite = true; + private boolean DualPass = false; + private boolean alphaToCoverage = false; public PipelineBuildInfo(ShaderModule[] shaderModules, VkPipelineVertexInputStateCreateInfo VertexInput, int ColourFormat){ this.ColourFormat = ColourFormat; @@ -24,6 +28,23 @@ public class PipelineBuildInfo { useBlend = true; } + public PipelineBuildInfo SetAlphaToCoverage(boolean alphaToCoverage){ + this.alphaToCoverage = alphaToCoverage; + return this; + } + public PipelineBuildInfo SetDualPass(boolean DualPass){ + this.DualPass = DualPass; + return this; + } + public PipelineBuildInfo SetDepthWrite(boolean DepthWrite){ + this.DepthWrite = DepthWrite; + return this; + } + + public boolean performDepthWrite(){return DepthWrite;} + public boolean PassTwice(){return DualPass;} + public boolean AlphaToCoverage(){return alphaToCoverage;} + public DescriptorSetLayout[] GetDescriptorSetLayouts(){return DescriptorSetLayouts;} public PipelineBuildInfo SetDescriptorSetLayouts(DescriptorSetLayout[] descriptorSetLayouts){ diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/SceneRender.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/SceneRender.java index 46f06a5..2561867 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/SceneRender.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/SceneRender.java @@ -31,8 +31,7 @@ import org.tinylog.Logger; import java.nio.ByteBuffer; import java.nio.LongBuffer; -import java.util.Arrays; -import java.util.List; +import java.util.*; import static org.lwjgl.vulkan.KHRSynchronization2.VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR; import static org.lwjgl.vulkan.VK13.*; @@ -70,13 +69,20 @@ public class SceneRender implements SceneRenderer {//dynamic rendering private static String LastGPULog = ""; public static long GPUTIME = 0; public static long CYCLES = 0; + private static boolean DualPassRendering = false; private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_fragment.glsl"; + private static final String FRAGMENT_TRANSLUCENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_translucent_fragment.glsl"; + private static final String FRAGMENT_OPAQUE_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_opaque_fragment.glsl"; private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv"; + private static final String FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV = FRAGMENT_TRANSLUCENT_SHADER_FILE_GLSL + ".spv"; + private static final String FRAGMENT_OPAQUE_SHADER_FILE_SPV = FRAGMENT_OPAQUE_SHADER_FILE_GLSL + ".spv"; private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/scene_vertex.glsl"; private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv"; private final VulkanBuffer[] BufferViewMatrices; - private final Pipeline VkPipeline; + private Pipeline VkPipeline; + private Pipeline VkPipelineOpaque; + private Pipeline VkPipelineTranslucent; private Matrix4f ProjectionMatrix; public static long GetGPUTimeNS(){ @@ -99,7 +105,6 @@ public class SceneRender implements SceneRenderer {//dynamic rendering AttachmentInfoColour = CreateColourAttachmentInfo(AttachmentColour,ClearValueColour); RenderInfo = CreateRenderInfo(AttachmentColour, AttachmentInfoColour, AttachmentInfoDepth); - ShaderModule[] shaderModules = SceneRender.CreateShaderModules(vulkanContext); PushConstBuffer = (MemoryUtil.memAlloc(PUSH_CONSTANTS_SIZE)); descriptorLayoutVertexUniform = new DescriptorSetLayout(vulkanContext, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, @@ -116,6 +121,11 @@ public class SceneRender implements SceneRenderer {//dynamic rendering descriptorLayoutTexture = new DescriptorSetLayout(vulkanContext, new DescriptorSetLayout.LayoutInformation( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, TextureCache.MAX_TEXTURES, VK_SHADER_STAGE_FRAGMENT_BIT )); + BufferViewMatrices = VulkanUtils.CreateHostVisibleBuffers(vulkanContext, VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.MAX_IN_FLIGHT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESCRIPTOR_ID_VIEW, descriptorLayoutVertexUniform); + CreatePipelines(vulkanContext); + } + + public void CreatePipelines(VulkanContext vulkanContext){ DescriptorSetLayout[] layouts = new DescriptorSetLayout[]{ descriptorLayoutVertexUniform, descriptorLayoutVertexUniform, @@ -123,12 +133,23 @@ public class SceneRender implements SceneRenderer {//dynamic rendering descriptorLayoutTexture }; - BufferViewMatrices = VulkanUtils.CreateHostVisibleBuffers(vulkanContext, VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.MAX_IN_FLIGHT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESCRIPTOR_ID_VIEW, descriptorLayoutVertexUniform); - - VkPipeline = CreatePipeline(vulkanContext, shaderModules, layouts); + ShaderModule[] shaderModules = SceneRender.CreateShaderModules(vulkanContext,0); + VkPipeline = CreatePipeline(vulkanContext, shaderModules, layouts, true, false,EngineConfig.getInstance().AlphaToCoverage()); + shaderModules = SceneRender.CreateShaderModules(vulkanContext,1); + VkPipelineOpaque = CreatePipeline(vulkanContext, shaderModules, layouts, true, true,EngineConfig.getInstance().AlphaToCoverage()); + shaderModules = SceneRender.CreateShaderModules(vulkanContext,2); + VkPipelineTranslucent = CreatePipeline(vulkanContext, shaderModules, layouts, false, true,EngineConfig.getInstance().AlphaToCoverage()); Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext)); } + public void RebuildPipelines(VulkanContext vulkanContext){ + CreatePipelines(vulkanContext); + } + + public static void SetDualPassRendering(boolean dualPass){ + DualPassRendering = dualPass; + } + private static Attachment CreateColourAttachment(VulkanContext VkCtx){ SwapChain swapChain = VkCtx.GetSwapChain(); VkExtent2D SwapChainExtent = swapChain.GetSwapChainExtent(); @@ -192,28 +213,31 @@ public class SceneRender implements SceneRenderer {//dynamic rendering return Result; } - private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx){ + private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){ 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); + ShaderCompiler.CompileGLSLShaderOnChange( Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_GLSL : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_GLSL : FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_fragment_shader); } return new ShaderModule[]{ 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, Translucent == 2 ? FRAGMENT_TRANSLUCENT_SHADER_FILE_SPV : Translucent == 1 ? FRAGMENT_OPAQUE_SHADER_FILE_SPV : FRAGMENT_SHADER_FILE_SPV,null) }; } - private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts){ + private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts, boolean DepthWrite, boolean DualRender, boolean AlphaToCoverage){ var vertexBufferStructure = new VertexBufferStructure(); var BuildInfo = new PipelineBuildInfo(ShaderModules,vertexBufferStructure.getVertexInput(),COLOUR_FORMAT) .SetDepthFormat(DEPTH_FORMAT) + .SetDepthWrite(DepthWrite) .SetPushConstantRanges( new PushConstantsRange[]{ new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,0,VulkanUtils.MATRIX4X4_SIZE), new PushConstantsRange(VK_SHADER_STAGE_FRAGMENT_BIT,VulkanUtils.MATRIX4X4_SIZE,VulkanUtils.INT_SIZE) }) .SetDescriptorSetLayouts(DescriptorSetLayouts) - .BlendingIsUsed(true); + .BlendingIsUsed(DualRender ? !DepthWrite : true) + .SetDualPass(DualRender) + .SetAlphaToCoverage(AlphaToCoverage); var pipeline = new DefaultPipeline(VkCtx, BuildInfo); vertexBufferStructure.cleanup(); return pipeline; @@ -237,7 +261,7 @@ public class SceneRender implements SceneRenderer {//dynamic rendering long InitialTime = System.nanoTime(); vkCmdBeginRendering(CommandHandle, RenderInfo); - vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipeline.GetVulkanPipeline()); + vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipeline() : VkPipeline.GetVulkanPipeline()); Image ColourImage = AttachmentColour.GetVkImage(); int width = ColourImage.GetWidth(); @@ -262,9 +286,15 @@ public class SceneRender implements SceneRenderer {//dynamic rendering .put(1,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_VIEW, CurrentFrame).GetVkDescriptorSet()) .put(2,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_MAT).GetVkDescriptorSet()) .put(3,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet()); - vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null); + vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipelineLayout() : VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null); RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false); + if(DualPassRendering) { + vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineTranslucent.GetVulkanPipeline()); + vkCmdSetViewport(CommandHandle, 0, Viewport); + vkCmdSetScissor(CommandHandle, 0, Scissor); + vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineTranslucent.GetVulkanPipelineLayout(), 0, DescriptorSets, null); + } RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, true); vkCmdEndRendering(CommandHandle); @@ -280,7 +310,7 @@ public class SceneRender implements SceneRenderer {//dynamic rendering Scene scene = instance.scene(); List Actors = scene.GetActors(); int ActorCount = Actors.size(); - + List translucentObjects = new ArrayList<>(); for(int i = 0; i < ActorCount; i++){ var Actor = Actors.get(i); VulkanModel model = modelsCache.GetModel(Actor.GetModelID()); @@ -295,15 +325,49 @@ public class SceneRender implements SceneRenderer {//dynamic rendering Logger.warn("Mesh [{}] in model [{}] does not have material",j,model.GetID()); continue; } - if(vulkanMaterial.HasTransparency() == Transparent) { - SetPushConstants(CommandHandle, Actor.GetModelMatrix(), MaterialIndex); - vertexBuffer.put(0, VkMesh.VerticesBuffer().GetBuffer()); - vkCmdBindVertexBuffers(CommandHandle, 0, vertexBuffer, offsets); - vkCmdBindIndexBuffer(CommandHandle, VkMesh.IndicesBuffer().GetBuffer(), 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(CommandHandle, VkMesh.IndicesCount(), 1, 0, 0, 0); + if( DualPassRendering || vulkanMaterial.HasTransparency() == Transparent) { + //if(Transparent){ + // if(!translucentObjects.contains(Actor))translucentObjects.add(Actor); + //}else { + SetPushConstants(CommandHandle, Actor.GetModelMatrix(), MaterialIndex); + vertexBuffer.put(0, VkMesh.VerticesBuffer().GetBuffer()); + vkCmdBindVertexBuffers(CommandHandle, 0, vertexBuffer, offsets); + vkCmdBindIndexBuffer(CommandHandle, VkMesh.IndicesBuffer().GetBuffer(), 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(CommandHandle, VkMesh.IndicesCount(), 1, 0, 0, 0); + //} } } } + /*if(Transparent){ + translucentObjects.sort((actor1, actor2) -> { + float distSq1 = actor1.GetPosition().distanceSquared(scene.GetCamera().GetPosition()); + float distSq2 = actor2.GetPosition().distanceSquared(scene.GetCamera().GetPosition()); + return Float.compare(distSq2, distSq1); + }); + for(int i = 0; i < translucentObjects.size(); i++){ + var Actor = translucentObjects.get(i); + VulkanModel model = modelsCache.GetModel(Actor.GetModelID()); + List VkMeshList = model.GetVkMeshList(); + int MeshCount = VkMeshList.size(); + for(int j = 0; j < MeshCount; j++){ + var VkMesh = VkMeshList.get(j); + String MaterialID = VkMesh.MaterialID(); + int MaterialIndex = materialsCache.GetPosition(MaterialID); + VulkanMaterial vulkanMaterial = materialsCache.GetMaterial(MaterialID); + if(vulkanMaterial == null){ + Logger.warn("Mesh [{}] in model [{}] does not have material",j,model.GetID()); + continue; + } + if(vulkanMaterial.HasTransparency() == Transparent) { + SetPushConstants(CommandHandle, Actor.GetModelMatrix(), MaterialIndex); + vertexBuffer.put(0, VkMesh.VerticesBuffer().GetBuffer()); + vkCmdBindVertexBuffers(CommandHandle, 0, vertexBuffer, offsets); + vkCmdBindIndexBuffer(CommandHandle, VkMesh.IndicesBuffer().GetBuffer(), 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(CommandHandle, VkMesh.IndicesCount(), 1, 0, 0, 0); + } + } + } + }*/ } } diff --git a/terrain4j.properties b/terrain4j.properties index adb63c6..3bc1448 100644 --- a/terrain4j.properties +++ b/terrain4j.properties @@ -27,7 +27,7 @@ cap_fast_to_tickrate=true #2=MSAAx2 #3=MSAAx4 #4=MSAAx8 -anti_alias_mode=4 +anti_alias_mode=1 Debug_Shaders = false ShaderRecompiling = true #Vulkan Debugging toggle