diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McSsaoApplyRenderer.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McSsaoApplyRenderer.java new file mode 100644 index 000000000..e6a0f66dd --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McSsaoApplyRenderer.java @@ -0,0 +1,252 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.common.renderTest; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import com.mojang.blaze3d.platform.DestFactor; +import com.mojang.blaze3d.platform.PolygonMode; +import com.mojang.blaze3d.platform.SourceFactor; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderPass; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.AddressMode; +import com.mojang.blaze3d.textures.FilterMode; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.Identifier; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.function.Supplier; + +/** + * TODO ??? + */ +public class McSsaoApplyRenderer +{ + public static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + + public static final McSsaoApplyRenderer INSTANCE = new McSsaoApplyRenderer(); + + private VertexFormat vertexFormat; + private RenderPipeline pipeline; + private boolean init = false; + + private GpuBuffer vboGpuBuffer; + + + //=============// + // constructor // + //=============// + //region + + private McSsaoApplyRenderer() + { + + } + + private void tryInit() + { + if (this.init) + { + return; + } + this.init = true; + + + + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + + this.vertexFormat = VertexFormat.builder() + .add("vPosition", DhVertexFormat.SCREEN_POS) + .build(); + + + RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder(); + { + pipelineBuilder.withCull(false); + pipelineBuilder.withDepthWrite(false); + pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST); + pipelineBuilder.withColorWrite(true); + pipelineBuilder.withBlend(new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE)); + pipelineBuilder.withPolygonMode(PolygonMode.FILL); + pipelineBuilder.withLocation(Identifier.parse("distanthorizons:ssao_apply_render")); + + pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/quad_apply")); + pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/apply")); + + pipelineBuilder.withSampler("uSsaoColorTexture"); + pipelineBuilder.withSampler("uDhDepthTexture"); + + pipelineBuilder.withVertexFormat(this.vertexFormat, VertexFormat.Mode.TRIANGLE_FAN); + } + this.pipeline = pipelineBuilder.build(); + + + // upload vertex data + { + // vertices for a full-screen quad + float[] vertices = new float[] + { + // PosX,Y, + -1f, -1f, + 1f, -1f, + 1f, 1f, + -1f, 1f, + }; + + + Supplier labelSupplier = () -> "distantHorizons:McApplyRenderer"; + int usage = 8 | 32; // is this just using OpenGL VBO flags?, if so I can't find it, supposedly GlDevice on Mojang's side + int size = vertices.length * Float.BYTES; + this.vboGpuBuffer = gpuDevice.createBuffer(labelSupplier, usage, size); + + { + int offset = 0; + int length = vertices.length * Float.BYTES; + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, offset, length); + + ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES); + // Fill buffer with vertices. + byteBuffer.order(ByteOrder.nativeOrder()); + byteBuffer.asFloatBuffer().put(vertices); + byteBuffer.rewind(); + + commandEncoder.writeToBuffer(bufferSlice, byteBuffer); + } + } + + } + + //endregion + + + + //========// + // render // + //========// + //region + + public void render() + { + this.tryInit(); + + + if (McLodRenderer.INSTANCE.dhColorTexture == null) + { + return; + } + + if (McLodRenderer.INSTANCE.dhDepthTexture == null) + { + return; + } + + + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + + + // create a render pass + { + Supplier debugLabelSupplier = () -> "distantHorizons:McApplySsaoRenderer"; + GpuTextureView colorTexture = gpuDevice.createTextureView(McLodRenderer.INSTANCE.dhColorTexture); + OptionalInt optionalClearColorAsInt = OptionalInt.empty(); + GpuTextureView depthTexture = null; + OptionalDouble optionalDepthValueAsDouble = OptionalDouble.empty(); + + try (RenderPass renderPass = commandEncoder.createRenderPass( + debugLabelSupplier, + colorTexture, + optionalClearColorAsInt, + depthTexture, optionalDepthValueAsDouble)) + { + //renderPass.pushDebugGroup(); + //renderPass.popDebugGroup(); + + + // render pass setup + { + // bind SSAO color texture + { + GpuTextureView textureView = gpuDevice.createTextureView(McSsaoRenderer.INSTANCE.ssaoColorTexture); + GpuSampler gpuSampler = gpuDevice.createSampler( + AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V + FilterMode.NEAREST, FilterMode.NEAREST, // minFilter, magFilter + 1, // maxAnisotropy + OptionalDouble.empty() // maxLod + ); + renderPass.bindTexture("uSsaoColorTexture", textureView, gpuSampler); + } + + // bind DH LOD depth texture + { + GpuTextureView textureView = gpuDevice.createTextureView(McLodRenderer.INSTANCE.dhDepthTexture); + GpuSampler gpuSampler = gpuDevice.createSampler( + AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V + FilterMode.NEAREST, FilterMode.NEAREST, // minFilter, magFilter + 1, // maxAnisotropy + OptionalDouble.empty() // maxLod + ); + renderPass.bindTexture("uDhDepthTexture", textureView, gpuSampler); + } + + // bind VBO + renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol + + // set pipeline + renderPass.setPipeline(this.pipeline); + } + + // draw render pass + { + int indexStart = 0; + int indexCount = 4; + renderPass.draw(indexStart, indexCount); + } + } + } + } + + //endregion + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McSsaoRenderer.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McSsaoRenderer.java new file mode 100644 index 000000000..6938d0986 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McSsaoRenderer.java @@ -0,0 +1,329 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.common.renderTest; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.buffers.Std140Builder; +import com.mojang.blaze3d.buffers.Std140SizeCalculator; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import com.mojang.blaze3d.platform.PolygonMode; +import com.mojang.blaze3d.shaders.UniformType; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderPass; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.*; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.seibel.distanthorizons.api.objects.math.DhApiMat4f; +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.util.RenderUtil; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcFadeRenderer; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcSsaoRenderer; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.Identifier; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.function.Supplier; + +/** + * Renders a TODO + */ +public class McSsaoRenderer implements IMcSsaoRenderer +{ + public static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + + public static final McSsaoRenderer INSTANCE = new McSsaoRenderer(); + + private VertexFormat vertexFormat; + private RenderPipeline pipeline; + private boolean init = false; + + private GpuBuffer fragUniformBuffer; + + private GpuBuffer vboGpuBuffer; + + public GpuTexture ssaoColorTexture; + + + + //=============// + // constructor // + //=============// + //region + + private McSsaoRenderer() + { + this.vertexFormat = VertexFormat.builder() + .add("vPosition", DhVertexFormat.SCREEN_POS) + .build(); + } + + private void tryInit() + { + if (this.init) + { + return; + } + this.init = true; + + + + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + + + RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder(); + { + pipelineBuilder.withCull(false); + pipelineBuilder.withDepthWrite(false); + pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST); + pipelineBuilder.withColorWrite(true); + pipelineBuilder.withoutBlend(); + pipelineBuilder.withPolygonMode(PolygonMode.FILL); + pipelineBuilder.withLocation(Identifier.parse("distanthorizons:test_render")); + + pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/quad_apply")); + pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/ao")); + + pipelineBuilder.withSampler("uMcDepthTexture"); + pipelineBuilder.withSampler("uCombinedMcDhColorTexture"); + + pipelineBuilder.withSampler("uDhDepthTexture"); + + pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER); + + pipelineBuilder.withVertexFormat(this.vertexFormat, VertexFormat.Mode.TRIANGLE_FAN); + } + this.pipeline = pipelineBuilder.build(); + + + // upload vertex data + { + // vertices for a full-screen quad + float[] vertices = new float[] + { + // PosX,Y, + -1f, -1f, + 1f, -1f, + 1f, 1f, + -1f, 1f, + }; + + + Supplier labelSupplier = () -> "distantHorizons:McFadeRenderer"; + int usage = 8 | 32; // is this just using OpenGL VBO flags?, if so I can't find it, supposedly GlDevice on Mojang's side + int size = vertices.length * Float.BYTES; + this.vboGpuBuffer = gpuDevice.createBuffer(labelSupplier, usage, size); + + { + int offset = 0; + int length = vertices.length * Float.BYTES; + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, offset, length); + + ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES); + // Fill buffer with vertices. + byteBuffer.order(ByteOrder.nativeOrder()); + byteBuffer.asFloatBuffer().put(vertices); + byteBuffer.rewind(); + + commandEncoder.writeToBuffer(bufferSlice, byteBuffer); + } + } + + } + + //endregion + + + + //========// + // render // + //========// + //region + + @Override + public void render(DhApiMat4f dhProjectionMatrix) + { + this.tryInit(); + + + if (McLodRenderer.INSTANCE.dhDepthTexture == null + || McLodRenderer.INSTANCE.dhColorTexture == null) + { + return; + } + + + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + + + // textures + if (this.ssaoColorTexture == null + || this.ssaoColorTexture.getWidth(0) != MC_RENDER.getTargetFramebufferViewportWidth() + || this.ssaoColorTexture.getHeight(0) != MC_RENDER.getTargetFramebufferViewportHeight()) + { + if (this.ssaoColorTexture != null) + { + this.ssaoColorTexture.close(); + } + + // TODO USAGE_TEXTURE_BINDING = 4 + int usage = 4 | 8 | 32 | 128; + this.ssaoColorTexture = gpuDevice.createTexture("SsaoColorTexture", + usage, + TextureFormat.RGBA8, + MC_RENDER.getTargetFramebufferViewportWidth(), MC_RENDER.getTargetFramebufferViewportHeight(), + 1, 1 + ); + } + + + { + int uniformBufferSize = new Std140SizeCalculator() + .putInt() // uSampleCount\ + + .putFloat() // uRadius + .putFloat() // uStrength + .putFloat() // uMinLight + .putFloat() // uBias + .putFloat() // uFadeDistanceInBlocks + + .putMat4f() // uInvProj + .putMat4f() // uProj + .get(); + + + // create data // + + Mat4f projMatrix = new Mat4f(dhProjectionMatrix); + Mat4f invertedProjMatrix = new Mat4f(dhProjectionMatrix); + invertedProjMatrix.invert(); + + + // upload data // + + ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize); + buffer.order(ByteOrder.LITTLE_ENDIAN); + buffer = Std140Builder.intoBuffer(buffer) + .putInt(6) // uSampleCount + + .putFloat(4.0f) // uRadius + .putFloat(0.2f) // uStrength + .putFloat(0.25f) // uMinLight + .putFloat(0.02f) // uBias + .putFloat(1_600.0f) // uFadeDistanceInBlocks + + .putMat4f(invertedProjMatrix.createJomlMatrix()) + .putMat4f(projMatrix.createJomlMatrix()) + .get() + ; + + this.fragUniformBuffer = UniformHandler.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer); + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize); + + commandEncoder.writeToBuffer(bufferSlice, buffer); + } + + + this.renderSsaoToTexture(); + // TODO + McSsaoApplyRenderer.INSTANCE.render(); + + } + + private void renderSsaoToTexture() + { + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + // create a render pass + Supplier debugLabelSupplier = () -> "distantHorizons:McSsaoRenderer"; + GpuTextureView colorTexture = gpuDevice.createTextureView(this.ssaoColorTexture); + OptionalInt optionalClearColorAsInt = OptionalInt.empty(); + GpuTextureView depthTexture = null; + OptionalDouble optionalDepthValueAsDouble = OptionalDouble.empty(); + + try (RenderPass renderPass = commandEncoder.createRenderPass( + debugLabelSupplier, + colorTexture, + optionalClearColorAsInt, + depthTexture, optionalDepthValueAsDouble)) + { + //renderPass.pushDebugGroup(); + //renderPass.popDebugGroup(); + + + // render pass setup + { + // bind DH depth texture + { + GpuTextureView textureView = gpuDevice.createTextureView(McLodRenderer.INSTANCE.dhDepthTexture); + GpuSampler gpuSampler = gpuDevice.createSampler( + AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V + FilterMode.NEAREST, FilterMode.NEAREST, // minFilter, magFilter + 1, // maxAnisotropy + OptionalDouble.empty() // maxLod + ); + renderPass.bindTexture("uDhDepthTexture", textureView, gpuSampler); + } + + + renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer); + + // bind VBO + renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol + + // set pipeline + renderPass.setPipeline(this.pipeline); + } + + // draw render pass + { + int indexStart = 0; + int indexCount = 4; + renderPass.draw(indexStart, indexCount); + } + } + } + + + //endregion + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java index 5f38f083f..170874605 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java @@ -21,6 +21,7 @@ package com.seibel.distanthorizons.common.wrappers; import com.seibel.distanthorizons.common.renderTest.McFadeRenderer; import com.seibel.distanthorizons.common.renderTest.McLodRenderer; +import com.seibel.distanthorizons.common.renderTest.McSsaoRenderer; import com.seibel.distanthorizons.common.renderTest.McTestRenderer; import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI; import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper; @@ -41,6 +42,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRen import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcFadeRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcLodRenderer; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcSsaoRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcTestRenderer; /** @@ -81,6 +83,7 @@ public class DependencySetup SingletonInjector.INSTANCE.bind(IMcTestRenderer.class, McTestRenderer.INSTANCE); SingletonInjector.INSTANCE.bind(IMcFadeRenderer.class, McFadeRenderer.INSTANCE); SingletonInjector.INSTANCE.bind(IMcLodRenderer.class, McLodRenderer.INSTANCE); + SingletonInjector.INSTANCE.bind(IMcSsaoRenderer.class, McSsaoRenderer.INSTANCE); } } diff --git a/coreSubProjects b/coreSubProjects index 3d9ae5f08..84c212a78 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 3d9ae5f088d24387152bf336e752d041d5a5fb8d +Subproject commit 84c212a78040457ca2fb88c998dc95c4758cb1f1