SSAO, performance sucks and it flickers so tweaking is needed, also more material support

This commit is contained in:
Halbear 2026-09-01 03:33:26 +01:00
parent 5b231d6920
commit 577836a03f
39 changed files with 889 additions and 74 deletions

View file

@ -12,6 +12,7 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRe
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.TextureCache;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.PostProcessing.PostProcess;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.ScreenSpace.AmbientOcclusionRenderer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shadows.ShadowRenderer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.*;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.SpriteRendering.SpriteRenderer;
@ -51,6 +52,7 @@ public class VulkanRenderer implements Renderer {
private final Queue.PresentQueue PresentQueue;
private final Semaphore[] RenderCompleteSemaphores;
private final SceneRenderer sceneRender;
private final AmbientOcclusionRenderer ssaoRenderer;
private final SpriteRenderer spriteRenderer;
private final LightRenderer lightRenderer;
private final PostProcess PostProcessor;
@ -110,13 +112,16 @@ public class VulkanRenderer implements Renderer {
if(Deferred) {
sceneRender = new DeferredSceneRender(RendererContext, engineInstance);
shadowRender = new ShadowRenderer(RendererContext);
ssaoRenderer = new AmbientOcclusionRenderer(RendererContext,sceneRender.GetMRTAttachments().GetColourAttachments(), GraphicsQueue);
List<Attachment> attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments());
attachments.add(ssaoRenderer.getSSAOBlurAttachment());
attachments.add(shadowRender.getShadowAttachment());
lightRenderer = new LightRenderer(RendererContext, attachments);
PostProcessor = new PostProcess(RendererContext, lightRenderer.getAttachment());
} else{
sceneRender = new ForwardSceneRender(RendererContext);
ssaoRenderer = null;
PostProcessor = new PostProcess(RendererContext, sceneRender.GetAttachmentColour());
lightRenderer = null;
shadowRender = null;
@ -189,6 +194,7 @@ public class VulkanRenderer implements Renderer {
RendererContext.GetDevice().waitIdle();
Logger.debug("Waiting Vulkan Context");
sceneRender.cleanup(RendererContext);
if(ssaoRenderer != null)ssaoRenderer.cleanup(RendererContext);
if(shadowRender != null)shadowRender.cleanup(RendererContext);
if(lightRenderer != null)lightRenderer.cleanup(RendererContext);
PostProcessor.CleanUp(RendererContext);
@ -231,16 +237,15 @@ public class VulkanRenderer implements Renderer {
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
boolean RenderShadows = ShadowRenderer.AllowShadowRendering() && EngineConfig.getInstance().RenderShadows();
//lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), shadowRender.getShadowAttachment(), CurrentFrame, shadowRender.getCascadeShadows(CurrentFrame));
if(RenderShadows) {shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); }
ssaoRenderer.Render(RendererContext,engineInstance, CommandBuffer, sceneRender.GetMRTAttachments(), CurrentFrame);
if(RenderShadows) {
shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame);
lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), shadowRender.getShadowAttachment(), CurrentFrame, shadowRender.getCascadeShadows(CurrentFrame));
} else lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(),CurrentFrame);
lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(),
shadowRender.getShadowAttachment(), ssaoRenderer.getSSAOBlurAttachment(), CurrentFrame, shadowRender.getCascadeShadows(CurrentFrame));
} else lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(),ssaoRenderer.getSSAOBlurAttachment(),CurrentFrame);
PostProcessor.Render(RendererContext,CommandBuffer,lightRenderer.getAttachment());
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);
GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment());
swapChainRender.Render(RendererContext,CommandBuffer,PostProcessor.GetAttachment(),ImageIndex);
RecordingStop(CommandBuffer);
@ -302,6 +307,7 @@ public class VulkanRenderer implements Renderer {
shadowRender.RebuildPipelineAndRenderingAttachments(RendererContext);
List<Attachment> attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments());
attachments.add(ssaoRenderer.getSSAOBlurAttachment());
attachments.add(shadowRender.getShadowAttachment());
lightRenderer.updateAttachmentDescriptors(RendererContext, attachments);
@ -332,6 +338,11 @@ public class VulkanRenderer implements Renderer {
sceneRender.Resize(engineInstance,RendererContext);
if(Deferred) {
List<Attachment> attachments = new ArrayList<>(sceneRender.GetMRTAttachments().GetColourAttachments());
List<Attachment> ssaoAttachments = new ArrayList<>();
ssaoAttachments.add(attachments.get(0));
ssaoAttachments.add(attachments.get(2));
ssaoRenderer.resize(RendererContext, ssaoAttachments);
attachments.add(ssaoRenderer.getSSAOBlurAttachment());
attachments.add(shadowRender.getShadowAttachment());
lightRenderer.resize(RendererContext, attachments);
PostProcessor.Resize(RendererContext, lightRenderer.getAttachment());

View file

@ -122,6 +122,7 @@ public class ModelCompiler {
String NormalTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_NORMALS);
String EmissiveTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_EMISSIVE);
String TranslucencyTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_TRANSMISSION);
String SpecularTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_SPECULAR);
String MetallicRoughTexture = ProcessTexture(aiScene, aiMaterial, BaseDirectory, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
String OpacityTexture = ProcessTexture(aiScene,aiMaterial,BaseDirectory,aiTextureType_OPACITY);
@ -132,6 +133,18 @@ public class ModelCompiler {
MetallicArray = new float[]{0.0f};
}
float[] SpecularArray = new float[]{0.0f};
Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_SPECULAR_FACTOR,aiTextureType_NONE,0,SpecularArray,MaxPointer);
if(Result != aiReturn_SUCCESS){
SpecularArray = new float[]{0.0f};
}
if(MetallicArray[0] == 0.0f && SpecularArray[0] != 0.0f)
MetallicArray[0] = SpecularArray[0];
if(MetallicRoughTexture.isEmpty()){
MetallicRoughTexture = SpecularTexture;
}
float[] RoughnessArray = new float[]{0.0f};
Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_ROUGHNESS_FACTOR,aiTextureType_NONE,0,RoughnessArray,MaxPointer);
if(Result != aiReturn_SUCCESS){
@ -151,13 +164,32 @@ public class ModelCompiler {
}
float[] OpacityArray = new float[]{0.0f};
Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_OPACITY,aiTextureType_NONE,0,OpacityArray,MaxPointer);
if(Result != aiReturn_SUCCESS){
OpacityArray = new float[]{0.0f};
}
return new MaterialData(ModelName + "-mat-" + Position,DiffuseTexture,NormalTexture, MetallicRoughTexture,diffuse,RoughnessArray[0],MetallicArray[0], EmissiveTexture,emissiveColour, TranslucencyTexture, TranslucencyArray[0], OpacityTexture, OpacityArray[0]);
float[] RefractionArray = new float[]{0.0f};
Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_REFRACTI,aiTextureType_NONE,0,RefractionArray,MaxPointer);
if(Result != aiReturn_SUCCESS){
RefractionArray = new float[]{0.0f};
}
float[] ReflectionArray = new float[]{0.0f};
Result = aiGetMaterialFloatArray(aiMaterial,AI_MATKEY_REFLECTIVITY,aiTextureType_NONE,0,ReflectionArray,MaxPointer);
if(Result != aiReturn_SUCCESS){
ReflectionArray = new float[]{0.0f};
}
AIColor4D colour_transparency = AIColor4D.create();
Vector4f ColorTransparency = new Vector4f();
Result = aiGetMaterialColor(aiMaterial,AI_MATKEY_COLOR_TRANSPARENT,aiTextureType_NONE,0,colour_transparency);
if(Result != aiReturn_SUCCESS){
ColorTransparency.set(colour_transparency.r(),colour_transparency.g(),colour_transparency.b(),colour_transparency.a());
}
return new MaterialData(ModelName + "-mat-" + Position,DiffuseTexture,NormalTexture, MetallicRoughTexture,diffuse,RoughnessArray[0],MetallicArray[0], EmissiveTexture,emissiveColour, TranslucencyTexture, TranslucencyArray[0], OpacityTexture, OpacityArray[0],ColorTransparency,RefractionArray[0], ReflectionArray[0]);
}
public static MeshData ProcessMesh(AIMesh aiMesh, List<MaterialData> MaterialList, int MeshPosition, ModelBinaryData BinaryData) throws IOException {

View file

@ -0,0 +1,52 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Universal.SSAO;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import org.joml.Vector4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Random;
public class SSAO_Utils {
public static FloatBuffer GenerateSampleKernel(int size, long MappedMemory) {
FloatBuffer kernel = MemoryUtil.memFloatBuffer(MappedMemory,size * 4); // vec4 alignment
Random rnd = new Random();
for (int i = 0; i < size; i++) {
Vector4f sample = new Vector4f(rnd.nextFloat() * 2.0f - 1.0f,rnd.nextFloat() * 2.0f - 1.0f,rnd.nextFloat(),0);
sample = sample.normalize();
float scale = (float) i / (float) size;
scale = Lerp(0.1f, 1.0f, scale * scale);
sample.mul(scale);
kernel.put(sample.x);
kernel.put(sample.y);
kernel.put(sample.z);
kernel.put(0.0f);
}
return kernel;
}
public static ByteBuffer GenerateNoiseTexture() {
ByteBuffer buffer = BufferUtils.createByteBuffer(16 * 4 * Float.BYTES);
Random rnd = new Random();
for (int i = 0; i < 16; i++) {
float x = rnd.nextFloat() * 2.0f - 1.0f;
float y = rnd.nextFloat() * 2.0f - 1.0f;
buffer.putFloat(x);
buffer.putFloat(y);
buffer.putFloat(0.0f);
buffer.putFloat(0.0f);
}
buffer.flip();
return buffer;
}
private static float Lerp(float a, float b, float f) {
return a + f * (b - a);
}
}

View file

@ -50,7 +50,7 @@ public class LightRenderer {
private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv";
private static final String NO_SHADOWS_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/lighting_frag.glsl";
private static final String NO_SHADOWS_FRAGMENT_SHADER_FILE_SPV = NO_SHADOWS_FRAGMENT_SHADER_FILE_GLSL + ".spv";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/lighting_vertex.glsl";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl";
private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv";
private final DescriptorSetLayout AttachmentDescriptorSetLayout;
@ -69,6 +69,8 @@ public class LightRenderer {
private final DescriptorSetLayout StorageDescriptorSetLayout;
private final VulkanBuffer[] shadowMatrices;
private int MinimumAttachments = 9; // shadow + ssaoBlur
public LightRenderer(VulkanContext VkCtx, List<Attachment> attachments){
ClearValueColour = VkClearValue.calloc().color(
c -> c.float32(0, 0.0f).float32(1, 0.0f).float32(2, 0.0f).float32(3, 0.0f));
@ -84,8 +86,9 @@ public class LightRenderer {
VK_BORDER_COLOR_INT_OPAQUE_BLACK, 1, true);
textureSampler = new TextureSampler(VkCtx, textureSamplerInfo);
int numAttachments = attachments.size();
DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments + 1];
for (int i = 0; i < numAttachments + 1; i++) {
if(numAttachments < MinimumAttachments) numAttachments = MinimumAttachments;
DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments];
for (int i = 0; i < numAttachments; i++) {
descSetLayouts[i] = new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, i, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
}
AttachmentDescriptorSetLayout = new DescriptorSetLayout(VkCtx, descSetLayouts);
@ -209,7 +212,7 @@ public class LightRenderer {
}
public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments,Attachment shadowAttachment, int CurrentFrame, CascadeShadows cascadeShadows) {
public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments,Attachment shadowAttachment, Attachment ssaoBlurAttachment, int CurrentFrame, CascadeShadows cascadeShadows) {
try (var stack = MemoryStack.stackPush()) {
VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer();
@ -219,16 +222,6 @@ public class LightRenderer {
VK_ACCESS_2_NONE, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
List<Attachment> attachments = mrtAttachments.GetColourAttachments();
int numAttachments = attachments.size();
for (int i = 0; i < numAttachments; i++) {
Attachment attachment = attachments.get(i);
VulkanUtils.ImageBarrier(stack, cmdHandle, attachment.GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
}
VulkanUtils.ImageBarrier(stack, cmdHandle, mrtAttachments.GetDepthAttachment().GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT,
@ -285,7 +278,7 @@ public class LightRenderer {
}
}
public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments, int CurrentFrame) {
public void render(EngineInstance engineInstance, VulkanContext VkCtx, CommandBuffer cmdBuffer, MultiRenderTargetAttachments mrtAttachments, Attachment SSAOattachment, int CurrentFrame) {
try (var stack = MemoryStack.stackPush()) {
VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer();
@ -295,16 +288,6 @@ public class LightRenderer {
VK_ACCESS_2_NONE, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
List<Attachment> attachments = mrtAttachments.GetColourAttachments();
int numAttachments = attachments.size();
for (int i = 0; i < numAttachments; i++) {
Attachment attachment = attachments.get(i);
VulkanUtils.ImageBarrier(stack, cmdHandle, attachment.GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
}
VulkanUtils.ImageBarrier(stack, cmdHandle, mrtAttachments.GetDepthAttachment().GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT,
@ -422,7 +405,7 @@ public class LightRenderer {
DescriptorSet noShadowDescSet = VkCtx.GetDescriptorAllocator().GetDescriptorSet(DESC_ID_NOSHADOW_ATT);
var noShadowImageViews = new ArrayList<ImageView>();
for (int i = 0; i < attachments.size() - 1; i++) {
for (int i = 0; i < attachments.size(); i++) {
noShadowImageViews.add(attachments.get(i).GetVkImageView());
}
noShadowDescSet.SetImages(VkCtx.GetDevice(), noShadowImageViews, textureSampler, 0);
@ -444,7 +427,7 @@ public class LightRenderer {
DescriptorSet noShadowDescSet = VkCtx.GetDescriptorAllocator().GetDescriptorSet(DESC_ID_NOSHADOW_ATT);
var noShadowImageViews = new ArrayList<ImageView>();
for (int i = 0; i < attachments.size() - 1; i++) {
for (int i = 0; i < attachments.size(); i++) {
noShadowImageViews.add(attachments.get(i).GetVkImageView());
}
noShadowDescSet.SetImages(VkCtx.GetDevice(), noShadowImageViews, textureSampler, 0);

View file

@ -18,7 +18,9 @@ public class MultiRenderTargetAttachments {
public static final int EMISSIVE_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT;
public static final int TRANSLUCECNY_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT;
public static final int OPACITY_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT;
public static final int POSITION_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT;
public static final int POSITION_FORMAT = VK_FORMAT_R32G32B32A32_SFLOAT;
public static final int SSAO_RAW_ATTACHMENT = VK_FORMAT_R8_UNORM;
public static final int SSAO_BLUR_ATTACHMENT = VK_FORMAT_R8_UNORM;
private final List<Attachment> ColourAttachments;
private final Attachment DepthAttachment;
private final int Height;

View file

@ -3,12 +3,20 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
import org.w3c.dom.Text;
import static org.lwjgl.vulkan.VK13.*;
public class Attachment {
private final Image VkImage;
private final ImageView VkImageView;
private boolean DepthAttachment;
public Attachment(VulkanContext VkCtx, Texture ExistingImage){
VkImageView = ExistingImage.GetImageView();
VkImage = ExistingImage.GetImage();
DepthAttachment = VkImageView.IsDepthImage();
}
public Attachment(VulkanContext VkCtx, int Width, int Height, int Format, int Usage, boolean MultiSamples){
var ImageData = new Image.ImageData().Width(Width).Height(Height).Format(Format).SampleCount(EngineConfig.getInstance().GetRenderSampleCount());

View file

@ -44,6 +44,7 @@ public class Texture implements ITexture {
.AspectMask(VK_IMAGE_ASPECT_COLOR_BIT).MipLevels(MipMapLevels);
imageView = new ImageView(VkCtx.GetDevice(), image.getVulkanImage(), ImageViewData, false);
}
public Image GetImage(){return image;}
public boolean HasTransparency(){return Transparent;}
public void SetTransparency(ByteBuffer data){
int PixelCount = data.capacity()/4;

View file

@ -18,7 +18,7 @@ import java.util.UUID;
import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8G8B8A8_SRGB;
public class TextureCache implements ITextureCache {
public static final int MAX_TEXTURES = 256;
public static final int MAX_TEXTURES = 512;
private final IndexedLinkedHashMap<String, ITexture> TextureMap;
private final IndexedLinkedHashMap<String, ITexture> CubemapTextures;
private final List<String> ActualTextures;

View file

@ -35,7 +35,7 @@ public class PostProcess {
private static final String MULTI_PASS_FRAGMENT_SHADER_FILE_SPV = MULTI_PASS_FRAGMENT_SHADER_FILE_GLSL + ".spv";
private static final String SINGLE_PASS_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/post_process_frag.glsl";
private static final String SINGLE_PASS_FRAGMENT_SHADER_FILE_SPV = SINGLE_PASS_FRAGMENT_SHADER_FILE_GLSL + ".spv";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/post_process_vtx.glsl";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl";
private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv";
private final DescriptorSetLayout AttachmentDescriptorSetLayout;

View file

@ -0,0 +1,442 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.ScreenSpace;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Universal.SSAO.SSAO_Utils;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.EmptyVertexBufferStruct;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Image;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.ImageSrc;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Texture;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PipelineBuildInfo;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandPool;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Queues.Queue;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.SwapChain;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.util.shaderc.Shaderc;
import org.lwjgl.vulkan.*;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.LongBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments.SSAO_BLUR_ATTACHMENT;
import static net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments.SSAO_RAW_ATTACHMENT;
import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_FRAGMENT_BIT;
import static org.lwjgl.vulkan.VK13.*;
public class AmbientOcclusionRenderer {
private static final long SSAO_INFO_BUFFER_SIZE =
VulkanUtils.MATRIX4X4_SIZE + // projection
VulkanUtils.MATRIX4X4_SIZE + // view
VulkanUtils.VEC4_SIZE + // screenSize.xy, radius, bias
VulkanUtils.VEC4_SIZE; // kernelSize + padding
private static final int SSAO_KERNEL_SIZE = 32;
private static final float SSAO_RADIUS = 5.0f;
private static final float SSAO_BIAS = 0.15f;
private static final long SSAO_KERNEL_BUFFER_SIZE = SSAO_KERNEL_SIZE * 4L * VulkanUtils.FLOAT_SIZE;
private static final String DESC_ID_SSAO_ATTACHMENTS = "SSAO_DESC_ID_ATTACHMENTS";
private static final String DESC_ID_SSAO_KERNEL = "SSAO_DESC_ID_KERNEL";
private static final String DESC_ID_SSAO_INFO = "SSAO_DESC_ID_INFO";
private static final String DESC_ID_SSAO_BLUR_INPUT = "SSAO_DESC_ID_BLUR_INPUT";
private static final String BLUR_FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/ssao_blur_frag.glsl";
private static final String BLUR_FRAGMENT_SHADER_FILE_SPV = BLUR_FRAGMENT_SHADER_FILE_GLSL + ".spv";
private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/ssao_frag.glsl";
private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl";
private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv";
private Attachment ssaoAttachment;
private VkRenderingAttachmentInfo.Buffer ssaoAttachmentInfo;
private Attachment ssaoBlurAttachment;
private VkRenderingAttachmentInfo.Buffer ssaoBlurAttachmentInfo;
private final Attachment[] SSAO_ATTACHMENTS = new Attachment[2];
private final Pipeline ssaoPipeline;
private final Pipeline blurPipeline;
private final TextureSampler textureSampler;
private DescriptorSetLayout ssaoAttachmentDescriptorLayout;
private DescriptorSetLayout ssaoKernelDescriptorLayout;
private DescriptorSetLayout ssaoInfoDescriptorLayout;
private DescriptorSetLayout blurDescriptorLayout;
private final VkClearValue clearColour;
private VulkanBuffer sampleKernelBuffer;
private VkRenderingInfo ssaoRenderInfo;
private VkRenderingInfo ssaoBlurRenderInfo;
private VulkanBuffer[] ssaoInfoBuffers;
private Texture NoiseTexture;
private Attachment NoiseImageAttachment;
public AmbientOcclusionRenderer(VulkanContext VkCtx, List<Attachment> MRTAttachments, Queue queue) {
List<Attachment> attachments = new ArrayList<>();
attachments.add(MRTAttachments.get(0)); // position
attachments.add(MRTAttachments.get(2)); // normal
CreateAttachments(VkCtx);
clearColour = VkClearValue.calloc().color(
c -> c.float32(0, 0.0f).float32(1, 0.0f).float32(2, 0.0f).float32(3, 0.0f));
ssaoAttachmentInfo = CreateColourAttachmentInfo(ssaoAttachment, clearColour);
ssaoBlurAttachmentInfo = CreateColourAttachmentInfo(ssaoBlurAttachment, clearColour);
var textureSamplerInfo = new TextureSamplerInfo(VK_SAMPLER_ADDRESS_MODE_REPEAT,
VK_BORDER_COLOR_INT_OPAQUE_BLACK, 1, true);
textureSampler = new TextureSampler(VkCtx, textureSamplerInfo);
ByteBuffer NoiseTexturedata = SSAO_Utils.GenerateNoiseTexture();
ImageSrc imageSrc = new ImageSrc(NoiseTexturedata, 4, 4,4);
NoiseTexture = new Texture(VkCtx,"SSAO_NOISE_SAMPLE", imageSrc,VK_FORMAT_R32G32B32A32_SFLOAT);
var commandPool = new CommandPool(VkCtx, queue.GetQueueFamilyIndex(), false);
var commandBuffer = new CommandBuffer(VkCtx, commandPool, true, true);
commandBuffer.BeginRecording();
NoiseTexture.RecordTextureTransition(commandBuffer);
commandBuffer.EndRecording();
commandBuffer.SubmitAndWait(VkCtx, queue);
commandBuffer.cleanup(VkCtx,commandPool);
commandPool.cleanup(VkCtx);
NoiseImageAttachment = new Attachment(VkCtx, NoiseTexture);
attachments.add(NoiseImageAttachment);
ssaoKernelDescriptorLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
0, 1, VK_SHADER_STAGE_FRAGMENT_BIT));
sampleKernelBuffer = VulkanUtils.CreateHostVisibleBuffer(VkCtx, SSAO_KERNEL_BUFFER_SIZE, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
DESC_ID_SSAO_KERNEL, ssaoKernelDescriptorLayout);
long MappedMemory = sampleKernelBuffer.MapMemory(VkCtx);
FloatBuffer KernelBuffer = SSAO_Utils.GenerateSampleKernel(SSAO_KERNEL_SIZE, MappedMemory);
sampleKernelBuffer.UnMapMemory(VkCtx);
int numAttachments = attachments.size();
DescriptorSetLayout.LayoutInformation[] descSetLayouts = new DescriptorSetLayout.LayoutInformation[numAttachments];
for (int i = 0; i < numAttachments; i++) {
descSetLayouts[i] = new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, i, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
}
ssaoAttachmentDescriptorLayout = new DescriptorSetLayout(VkCtx, descSetLayouts);
CreateSSAOAttachmentDescriptorSet(VkCtx, attachments);
ssaoInfoDescriptorLayout = new DescriptorSetLayout(VkCtx,new DescriptorSetLayout.LayoutInformation( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,1,VK_SHADER_STAGE_FRAGMENT_BIT ));
blurDescriptorLayout = new DescriptorSetLayout(VkCtx,new DescriptorSetLayout.LayoutInformation( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
0,1,VK_SHADER_STAGE_FRAGMENT_BIT ));
CreateBlurDescriptorSet(VkCtx);
ssaoInfoBuffers = VulkanUtils.CreateHostVisibleBuffers(VkCtx,SSAO_INFO_BUFFER_SIZE, VulkanUtils.MAX_IN_FLIGHT,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESC_ID_SSAO_INFO,ssaoInfoDescriptorLayout);
ssaoRenderInfo = CreateRenderInfo(ssaoAttachment, ssaoAttachmentInfo);
ssaoBlurRenderInfo = CreateRenderInfo(ssaoBlurAttachment, ssaoBlurAttachmentInfo);
ShaderModule[] shaderModules = CreateRawShaderModules(VkCtx);
ssaoPipeline = CreatePipeline(VkCtx, shaderModules,
new DescriptorSetLayout[]{
ssaoAttachmentDescriptorLayout,
ssaoKernelDescriptorLayout,
ssaoInfoDescriptorLayout
},false);
Arrays.stream(shaderModules).toList().forEach(shaderModule -> shaderModule.CleanUp(VkCtx));
shaderModules = CreateBlurShaderModules(VkCtx);
blurPipeline = CreatePipeline( VkCtx, shaderModules,
new DescriptorSetLayout[]{ blurDescriptorLayout },
true );
Arrays.stream(shaderModules).toList().forEach(shaderModule -> shaderModule.CleanUp(VkCtx));
}
private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] shaderModules, DescriptorSetLayout[] descSetLayouts, boolean blur) {
var vtxBuffStruct = new EmptyVertexBufferStruct();
var buildInfo = new PipelineBuildInfo(shaderModules, vtxBuffStruct.GetVertexInput(),new int[]{blur ? SSAO_BLUR_ATTACHMENT : SSAO_RAW_ATTACHMENT})
.SetDescriptorSetLayouts(descSetLayouts)
.BlendingIsUsed(false)
.SetDepthWrite(false)
.SetDepthTest(false);
var pipeline = new DefaultPipeline(VkCtx, buildInfo);
vtxBuffStruct.CleanUp();
return pipeline;
}
private static ShaderModule[] CreateRawShaderModules(VulkanContext VkCtx) {
if (EngineConfig.getInstance().RecompileShaders()) {
ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader);
ShaderCompiler.CompileGLSLShaderOnChange( FRAGMENT_SHADER_FILE_GLSL , Shaderc.shaderc_glsl_fragment_shader);
}
return new ShaderModule[]{
new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV, null),
new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, FRAGMENT_SHADER_FILE_SPV, null),
};
}
private static ShaderModule[] CreateBlurShaderModules(VulkanContext VkCtx) {
if (EngineConfig.getInstance().RecompileShaders()) {
ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader);
ShaderCompiler.CompileGLSLShaderOnChange( BLUR_FRAGMENT_SHADER_FILE_GLSL , Shaderc.shaderc_glsl_fragment_shader);
}
return new ShaderModule[]{
new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV, null),
new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, BLUR_FRAGMENT_SHADER_FILE_SPV, null),
};
}
private static VkRenderingAttachmentInfo.Buffer CreateColourAttachmentInfo(Attachment attachment, VkClearValue clearValue) {
return VkRenderingAttachmentInfo.calloc(1)
.sType$Default()
.imageView(attachment.GetVkImageView().GetVulkanImageView())
.imageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
.loadOp(VK_ATTACHMENT_LOAD_OP_CLEAR)
.storeOp(VK_ATTACHMENT_STORE_OP_STORE)
.clearValue(clearValue);
}
private static VkRenderingInfo CreateRenderInfo(Attachment attachment, VkRenderingAttachmentInfo.Buffer attachmentInfo) {
return VkRenderingInfo.calloc()
.sType$Default()
.renderArea(area -> area
.offset(offset -> offset.x(0).y(0))
.extent(extent -> extent
.width(attachment.GetVkImage().GetWidth())
.height(attachment.GetVkImage().GetHeight())))
.layerCount(1)
.pColorAttachments(attachmentInfo);
}
private void CreateSSAOAttachmentDescriptorSet(VulkanContext vkCtx, List<Attachment> Attachments ) {
DescriptorSet descSet = vkCtx.GetDescriptorAllocator().AddDescriptorSet(
vkCtx.GetDevice(), DESC_ID_SSAO_ATTACHMENTS,ssaoAttachmentDescriptorLayout );
List<ImageView> imageViews = new ArrayList<>();
Attachments.forEach(a -> imageViews.add(a.GetVkImageView()));
descSet.SetImages(vkCtx.GetDevice(), imageViews, textureSampler, 0);
}
private void CreateBlurDescriptorSet(VulkanContext vkCtx) {
DescriptorSet descSet = vkCtx.GetDescriptorAllocator().AddDescriptorSet(
vkCtx.GetDevice(),DESC_ID_SSAO_BLUR_INPUT, blurDescriptorLayout);
descSet.SetImage(vkCtx.GetDevice(), ssaoAttachment.GetVkImageView(),
textureSampler,0);
}
private void CreateAttachments(VulkanContext VkCtx){
SwapChain swapChain = VkCtx.GetSwapChain();
VkExtent2D swapChainExtent = swapChain.GetSwapChainExtent();
//SSAO Raw
ssaoAttachment = new Attachment(VkCtx, swapChainExtent.width(), swapChainExtent.height(), SSAO_RAW_ATTACHMENT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1);
SSAO_ATTACHMENTS[0] = ssaoAttachment;
//SSAO Blur
ssaoBlurAttachment = new Attachment(VkCtx, swapChainExtent.width(), swapChainExtent.height(), SSAO_BLUR_ATTACHMENT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1);
SSAO_ATTACHMENTS[1] = ssaoBlurAttachment;
}
public void Render(VulkanContext VkCtx,EngineInstance engineInstance, CommandBuffer cmdBuffer, MultiRenderTargetAttachments MRT,int CurrentFrame) {
try (var stack = MemoryStack.stackPush()) {
VkCommandBuffer cmdHandle = cmdBuffer.GetVulkanCommandBuffer();
UpdateSSAOInfo(VkCtx, engineInstance, CurrentFrame);
VulkanUtils.ImageBarrier(stack, cmdHandle, ssaoAttachment.GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_2_SHADER_READ_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
TransitionMRTtoReadOnly(stack, cmdHandle, MRT);
vkCmdBeginRendering(cmdHandle, ssaoRenderInfo);
vkCmdBindPipeline(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, ssaoPipeline.GetVulkanPipeline());
SetViewportAndScissor(stack, cmdHandle, ssaoAttachment);
DescriptorAllocator descAllocator = VkCtx.GetDescriptorAllocator();
LongBuffer descriptorSets = stack.mallocLong(3)
.put(0, descAllocator.GetDescriptorSet(DESC_ID_SSAO_ATTACHMENTS).GetVkDescriptorSet())
.put(1, descAllocator.GetDescriptorSet(DESC_ID_SSAO_KERNEL).GetVkDescriptorSet())
.put(2, descAllocator.GetDescriptorSet(DESC_ID_SSAO_INFO, CurrentFrame).GetVkDescriptorSet());
vkCmdBindDescriptorSets(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS,
ssaoPipeline.GetVulkanPipelineLayout(), 0, descriptorSets, null);
vkCmdDraw(cmdHandle, 3, 1, 0, 0);
vkCmdEndRendering(cmdHandle);
//blur pass
VulkanUtils.ImageBarrier(stack, cmdHandle, ssaoAttachment.GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
VulkanUtils.ImageBarrier(stack, cmdHandle, ssaoBlurAttachment.GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_2_SHADER_READ_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
vkCmdBeginRendering(cmdHandle, ssaoBlurRenderInfo);
vkCmdBindPipeline(cmdHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, blurPipeline.GetVulkanPipeline());
SetViewportAndScissor(stack, cmdHandle, ssaoBlurAttachment);
LongBuffer blurDescriptorSets = stack.mallocLong(1)
.put(0, descAllocator.GetDescriptorSet(DESC_ID_SSAO_BLUR_INPUT).GetVkDescriptorSet());
vkCmdBindDescriptorSets(cmdHandle,VK_PIPELINE_BIND_POINT_GRAPHICS,
blurPipeline.GetVulkanPipelineLayout(),0, blurDescriptorSets,null );
vkCmdDraw(cmdHandle, 3, 1, 0, 0);
vkCmdEndRendering(cmdHandle);
VulkanUtils.ImageBarrier( stack, cmdHandle, ssaoBlurAttachment.GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
}
}
private static void TransitionMRTtoReadOnly(MemoryStack stack,VkCommandBuffer cmdHandle, MultiRenderTargetAttachments MRT) {
List<Attachment> attachments = MRT.GetColourAttachments();
for (Attachment attachment : attachments) {
VulkanUtils.ImageBarrier( stack,cmdHandle, attachment.GetVkImage().getVulkanImage(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT,
VK_IMAGE_ASPECT_COLOR_BIT
);
}
}
private void SetViewportAndScissor(MemoryStack stack, VkCommandBuffer cmdHandle, Attachment attachment){
Image ColourImage = attachment.GetVkImage();
int width = ColourImage.GetWidth();
int height = ColourImage.GetHeight();
var viewport = VkViewport.calloc(1, stack)
.x(0)
.y(height)
.height(-height)
.width(width)
.minDepth(0.0f)
.maxDepth(1.0f);
vkCmdSetViewport(cmdHandle, 0, viewport);
var scissor = VkRect2D.calloc(1, stack)
.extent(it -> it.width(width).height(height))
.offset(it -> it.x(0).y(0));
vkCmdSetScissor(cmdHandle, 0, scissor);
}
private void UpdateSSAOInfo(VulkanContext vkCtx, EngineInstance engineInstance, int currentFrame) {
VulkanBuffer buffer = ssaoInfoBuffers[currentFrame];
long mappedMemory = buffer.MapMemory(vkCtx);
ByteBuffer data = MemoryUtil.memByteBuffer(mappedMemory, (int) buffer.GetRequestedSize());
int offset = 0;
engineInstance.scene().GetProjection().GetProjectionMatrix().get(offset, data);
offset += VulkanUtils.MATRIX4X4_SIZE;
engineInstance.scene().GetCamera().GetViewMatrix().get(offset, data);
offset += VulkanUtils.MATRIX4X4_SIZE;
data.putFloat(offset, ssaoAttachment.GetVkImage().GetWidth());
data.putFloat(offset + VulkanUtils.FLOAT_SIZE, ssaoAttachment.GetVkImage().GetHeight());
data.putFloat(offset + VulkanUtils.FLOAT_SIZE * 2, SSAO_RADIUS);
data.putFloat(offset + VulkanUtils.FLOAT_SIZE * 3, SSAO_BIAS);
offset += VulkanUtils.VEC4_SIZE;
data.putInt(offset, SSAO_KERNEL_SIZE);
buffer.UnMapMemory(vkCtx);
}
public Attachment getSSAOBlurAttachment() {
return ssaoBlurAttachment;
}
public void resize(VulkanContext VkCtx, List<Attachment> attachments) {
ssaoRenderInfo.free();
ssaoBlurRenderInfo.free();
ssaoAttachmentInfo.free();
ssaoAttachment.CleanUp(VkCtx);
ssaoBlurAttachmentInfo.free();
ssaoBlurAttachment.CleanUp(VkCtx);
CreateAttachments(VkCtx);
ssaoAttachmentInfo = CreateColourAttachmentInfo(ssaoAttachment, clearColour);
ssaoBlurAttachmentInfo = CreateColourAttachmentInfo(ssaoBlurAttachment, clearColour);
ssaoRenderInfo = CreateRenderInfo(ssaoAttachment, ssaoAttachmentInfo);
ssaoBlurRenderInfo = CreateRenderInfo(ssaoBlurAttachment, ssaoBlurAttachmentInfo);
attachments.add(NoiseImageAttachment);
CreateSSAOAttachmentDescriptorSet(VkCtx,attachments);
CreateBlurDescriptorSet(VkCtx);
}
public void cleanup(VulkanContext VkCtx) {
ssaoRenderInfo.free();
ssaoBlurRenderInfo.free();
ssaoAttachmentInfo.free();
ssaoAttachment.CleanUp(VkCtx);
ssaoBlurAttachmentInfo.free();
ssaoBlurAttachment.CleanUp(VkCtx);
ssaoPipeline.CleanUp(VkCtx);
blurPipeline.CleanUp(VkCtx);
clearColour.free();
Arrays.stream(ssaoInfoBuffers).toList().forEach(b -> b.cleanup(VkCtx));
sampleKernelBuffer.cleanup(VkCtx);
ssaoAttachmentDescriptorLayout.CleanUp(VkCtx);
blurDescriptorLayout.CleanUp(VkCtx);
ssaoInfoDescriptorLayout.CleanUp(VkCtx);
ssaoKernelDescriptorLayout.CleanUp(VkCtx);
NoiseTexture.CleanUp(VkCtx);
textureSampler.CleanUp(VkCtx);
}
}

View file

@ -1,5 +1,6 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.TextureCache;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
@ -100,9 +101,19 @@ public class DescriptorSet {
public void SetImageArray(Device device, List<ImageView> imageViews, TextureSampler textureSampler, int BaseBinding){
try(var MemStack = MemoryStack.stackPush()){
int ImageCount = imageViews.size();
if (textureSampler == null || textureSampler.GetVkSampler() == 0) {
throw new NullPointerException("The provided TextureSampler is uninitialized or null!");
}
VkDescriptorImageInfo.Buffer imageInfos = VkDescriptorImageInfo.calloc(ImageCount,MemStack);
for(int i = 0; i < ImageCount; i++){
ImageView imageView = imageViews.get(i);
if (imageView == null || imageView.GetVulkanImageView() == 0) {
Logger.error("Texture or ImageView at index " + i + " is NULL! Check your material cache loading.");
imageView = imageViews.getFirst();
if(imageView == null || imageView.GetVulkanImageView() == 0) throw new NullPointerException("The provided TextureSampler is uninitialized or null!");
}
VkDescriptorImageInfo imageInfo = imageInfos.get(i);
imageInfo.imageView(imageView.GetVulkanImageView()).sampler(textureSampler.GetVkSampler());

View file

@ -2,5 +2,5 @@ package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel;
import org.joml.Vector4f;
public record MaterialData(String ID, String TexturePath,String NormalTexturePath,String MetalRoughnessMap, Vector4f DiffuseColour,float Roughness, float Metallic, String EmissiveTexture,Vector4f EmissiveColour, String TranslucencyTexture, float Translucency, String OpacityTexture, float Opacity) {
public record MaterialData(String ID, String TexturePath,String NormalTexturePath,String MetalRoughnessMap, Vector4f DiffuseColour,float Roughness, float Metallic, String EmissiveTexture,Vector4f EmissiveColour, String TranslucencyTexture, float Translucency, String OpacityTexture, float Opacity, Vector4f ColorTransparency, float Refractiveness, float Reflectiveness) {
}

View file

@ -205,9 +205,11 @@ public class SpriteRenderer {
public void LoadMaterials(VulkanContext VkCtx, MaterialsCache materialsCache, TextureCache textureCache){
DescriptorAllocator descriptorAllocator = VkCtx.GetDescriptorAllocator();
Device device = VkCtx.GetDevice();
List<ImageView> imageViews = new ArrayList<>(textureCache.GetAll2DTextures().stream().map(ITexture::GetImageView).toList());
ImageView fallback = textureCache.GetTexture("resources/EngineResources/Texture/NoTexture.png").GetImageView();
List<ImageView> imageViews = new ArrayList<>();
imageViews.add(fallback);
imageViews.addAll(textureCache.GetAll2DTextures().stream().map(ITexture::GetImageView).toList());
while (imageViews.size() < TextureCache.MAX_TEXTURES) {
imageViews.add(fallback);
}

View file

@ -29,7 +29,7 @@ public class SwapChainRender {
private static final String DESCRIPTOR_ID_ATTACHMENT = "FWD_DESC_ID_ATT";
private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/EngineResources/shaders/swap_frag.glsl";
private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/swap_vtx.glsl";
private static final String VERTEX_SHADER_FILE_GLSL = "resources/EngineResources/shaders/basic_screen_vertex.glsl";
private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv";
private final DescriptorSetLayout AttachmentDescriptorSetLayout;
private final VkClearValue ClearValueColour;

View file

@ -160,7 +160,7 @@ public class VulkanUtils {
descriptorAllocator.AddDescriptorSets(device, ID, BufferCount, layout);
DescriptorSetLayout.LayoutInformation LayoutInfo = layout.GetLayoutInfo();
for(int i = 0; i < BufferCount; i++){
Result[i] = new VulkanBuffer(VkCtx, BufferSize, Usage,VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
Result[i] = new VulkanBuffer(VkCtx, BufferSize, Usage,VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
DescriptorSet descriptorSet = descriptorAllocator.GetDescriptorSet(ID, i);
descriptorSet.SetBuffer(device, Result[i], Result[i].GetRequestedSize(), layout.GetLayoutInfo().Binding(),layout.GetLayoutInfo().DescriptorType());