mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-22 18:05:33 +01:00
Wbout it
- Implement WBOIT
This commit is contained in:
parent
c438fb57ca
commit
5d16ebda60
10 changed files with 310 additions and 16 deletions
|
@ -31,7 +31,9 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
private static final ResourceLocation SCATTER_SHADER_MAIN = Flywheel.rl("internal/indirect/scatter.glsl");
|
private static final ResourceLocation SCATTER_SHADER_MAIN = Flywheel.rl("internal/indirect/scatter.glsl");
|
||||||
private static final ResourceLocation DOWNSAMPLE_FIRST = Flywheel.rl("internal/indirect/downsample_first.glsl");
|
private static final ResourceLocation DOWNSAMPLE_FIRST = Flywheel.rl("internal/indirect/downsample_first.glsl");
|
||||||
private static final ResourceLocation DOWNSAMPLE_SECOND = Flywheel.rl("internal/indirect/downsample_second.glsl");
|
private static final ResourceLocation DOWNSAMPLE_SECOND = Flywheel.rl("internal/indirect/downsample_second.glsl");
|
||||||
public static final List<ResourceLocation> UTIL_SHADERS = List.of(APPLY_SHADER_MAIN, SCATTER_SHADER_MAIN, DOWNSAMPLE_FIRST, DOWNSAMPLE_SECOND);
|
|
||||||
|
private static final ResourceLocation FULLSCREEN = Flywheel.rl("internal/indirect/fullscreen.vert");
|
||||||
|
private static final ResourceLocation OIT_COMPOSITE = Flywheel.rl("internal/indirect/oit_composite.frag");
|
||||||
|
|
||||||
private static final Compile<InstanceType<?>> CULL = new Compile<>();
|
private static final Compile<InstanceType<?>> CULL = new Compile<>();
|
||||||
private static final Compile<ResourceLocation> UTIL = new Compile<>();
|
private static final Compile<ResourceLocation> UTIL = new Compile<>();
|
||||||
|
@ -45,11 +47,13 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
private final PipelineCompiler pipeline;
|
private final PipelineCompiler pipeline;
|
||||||
private final CompilationHarness<InstanceType<?>> culling;
|
private final CompilationHarness<InstanceType<?>> culling;
|
||||||
private final CompilationHarness<ResourceLocation> utils;
|
private final CompilationHarness<ResourceLocation> utils;
|
||||||
|
private final CompilationHarness<ResourceLocation> fullscreen;
|
||||||
|
|
||||||
private IndirectPrograms(PipelineCompiler pipeline, CompilationHarness<InstanceType<?>> culling, CompilationHarness<ResourceLocation> utils) {
|
private IndirectPrograms(PipelineCompiler pipeline, CompilationHarness<InstanceType<?>> culling, CompilationHarness<ResourceLocation> utils, CompilationHarness<ResourceLocation> fullscreen) {
|
||||||
this.pipeline = pipeline;
|
this.pipeline = pipeline;
|
||||||
this.culling = culling;
|
this.culling = culling;
|
||||||
this.utils = utils;
|
this.utils = utils;
|
||||||
|
this.fullscreen = fullscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> getExtensions(GlslVersion glslVersion) {
|
private static List<String> getExtensions(GlslVersion glslVersion) {
|
||||||
|
@ -88,8 +92,9 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, vertexComponents, fragmentComponents, EXTENSIONS);
|
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, vertexComponents, fragmentComponents, EXTENSIONS);
|
||||||
var cullingCompiler = createCullingCompiler(sources);
|
var cullingCompiler = createCullingCompiler(sources);
|
||||||
var utilCompiler = createUtilCompiler(sources);
|
var utilCompiler = createUtilCompiler(sources);
|
||||||
|
var fullscreenCompiler = createFullscreenCompiler(sources);
|
||||||
|
|
||||||
IndirectPrograms newInstance = new IndirectPrograms(pipelineCompiler, cullingCompiler, utilCompiler);
|
IndirectPrograms newInstance = new IndirectPrograms(pipelineCompiler, cullingCompiler, utilCompiler, fullscreenCompiler);
|
||||||
|
|
||||||
setInstance(newInstance);
|
setInstance(newInstance);
|
||||||
}
|
}
|
||||||
|
@ -125,6 +130,17 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
.harness("utilities", sources);
|
.harness("utilities", sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CompilationHarness<ResourceLocation> createFullscreenCompiler(ShaderSources sources) {
|
||||||
|
return UTIL.program()
|
||||||
|
.link(UTIL.shader(GlCompat.MAX_GLSL_VERSION, ShaderType.VERTEX)
|
||||||
|
.nameMapper($ -> "fullscreen/fullscreen")
|
||||||
|
.withResource(FULLSCREEN))
|
||||||
|
.link(UTIL.shader(GlCompat.MAX_GLSL_VERSION, ShaderType.FRAGMENT)
|
||||||
|
.nameMapper(rl -> "fullscreen/" + ResourceUtil.toDebugFileNameNoExtension(rl))
|
||||||
|
.withResource(s -> s))
|
||||||
|
.harness("fullscreen", sources);
|
||||||
|
}
|
||||||
|
|
||||||
static void setInstance(@Nullable IndirectPrograms newInstance) {
|
static void setInstance(@Nullable IndirectPrograms newInstance) {
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
instance.release();
|
instance.release();
|
||||||
|
@ -148,8 +164,8 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
setInstance(null);
|
setInstance(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram getIndirectProgram(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
|
public GlProgram getIndirectProgram(InstanceType<?> instanceType, ContextShader contextShader, Material material, boolean oit) {
|
||||||
return pipeline.get(instanceType, contextShader, material);
|
return pipeline.get(instanceType, contextShader, material, oit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram getCullingProgram(InstanceType<?> instanceType) {
|
public GlProgram getCullingProgram(InstanceType<?> instanceType) {
|
||||||
|
@ -172,10 +188,15 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
return utils.get(DOWNSAMPLE_SECOND);
|
return utils.get(DOWNSAMPLE_SECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GlProgram getOitCompositeProgram() {
|
||||||
|
return fullscreen.get(OIT_COMPOSITE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void _delete() {
|
protected void _delete() {
|
||||||
pipeline.delete();
|
pipeline.delete();
|
||||||
culling.delete();
|
culling.delete();
|
||||||
utils.delete();
|
utils.delete();
|
||||||
|
fullscreen.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class InstancingPrograms extends AtomicReferenceCounted {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
|
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
|
||||||
return pipeline.get(instanceType, contextShader, material);
|
return pipeline.get(instanceType, contextShader, material, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -50,7 +50,7 @@ public final class PipelineCompiler {
|
||||||
ALL.add(this);
|
ALL.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
|
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, Material material, boolean oit) {
|
||||||
var light = material.light();
|
var light = material.light();
|
||||||
var cutout = material.cutout();
|
var cutout = material.cutout();
|
||||||
var shaders = material.shaders();
|
var shaders = material.shaders();
|
||||||
|
@ -66,7 +66,7 @@ public final class PipelineCompiler {
|
||||||
MaterialShaderIndices.cutoutSources()
|
MaterialShaderIndices.cutoutSources()
|
||||||
.index(cutout.source());
|
.index(cutout.source());
|
||||||
|
|
||||||
return harness.get(new PipelineProgramKey(instanceType, contextShader, light, shaders, cutout != CutoutShaders.OFF, FrameUniforms.debugOn()));
|
return harness.get(new PipelineProgramKey(instanceType, contextShader, light, shaders, cutout != CutoutShaders.OFF, FrameUniforms.debugOn(), oit));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
|
@ -128,7 +128,8 @@ public final class PipelineCompiler {
|
||||||
.source());
|
.source());
|
||||||
var debug = key.debugEnabled() ? "_debug" : "";
|
var debug = key.debugEnabled() ? "_debug" : "";
|
||||||
var cutout = key.useCutout() ? "_cutout" : "";
|
var cutout = key.useCutout() ? "_cutout" : "";
|
||||||
return "pipeline/" + pipeline.compilerMarker() + "/frag/" + material + "/" + light + "_" + context + cutout + debug;
|
var oit = key.oit() ? "_oit" : "";
|
||||||
|
return "pipeline/" + pipeline.compilerMarker() + "/frag/" + material + "/" + light + "_" + context + cutout + debug + oit;
|
||||||
})
|
})
|
||||||
.requireExtensions(extensions)
|
.requireExtensions(extensions)
|
||||||
.enableExtension("GL_ARB_conservative_depth")
|
.enableExtension("GL_ARB_conservative_depth")
|
||||||
|
@ -146,6 +147,11 @@ public final class PipelineCompiler {
|
||||||
comp.define("_FLW_USE_DISCARD");
|
comp.define("_FLW_USE_DISCARD");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.onCompile((key, comp) -> {
|
||||||
|
if (key.oit()) {
|
||||||
|
comp.define("_FLW_OIT");
|
||||||
|
}
|
||||||
|
})
|
||||||
.withResource(API_IMPL_FRAG)
|
.withResource(API_IMPL_FRAG)
|
||||||
.withResource(key -> key.materialShaders()
|
.withResource(key -> key.materialShaders()
|
||||||
.fragmentSource())
|
.fragmentSource())
|
||||||
|
@ -217,6 +223,7 @@ public final class PipelineCompiler {
|
||||||
* @param light The light shader to use.
|
* @param light The light shader to use.
|
||||||
*/
|
*/
|
||||||
public record PipelineProgramKey(InstanceType<?> instanceType, ContextShader contextShader, LightShader light,
|
public record PipelineProgramKey(InstanceType<?> instanceType, ContextShader contextShader, LightShader light,
|
||||||
MaterialShaders materialShaders, boolean useCutout, boolean debugEnabled) {
|
MaterialShaders materialShaders, boolean useCutout, boolean debugEnabled,
|
||||||
|
boolean oit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,17 @@ public final class MaterialRenderState {
|
||||||
setupWriteMask(material.writeMask());
|
setupWriteMask(material.writeMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setupOit(Material material) {
|
||||||
|
setupTexture(material);
|
||||||
|
setupBackfaceCulling(material.backfaceCulling());
|
||||||
|
setupPolygonOffset(material.polygonOffset());
|
||||||
|
setupDepthTest(material.depthTest());
|
||||||
|
|
||||||
|
WriteMask mask = material.writeMask();
|
||||||
|
boolean writeColor = mask.color();
|
||||||
|
RenderSystem.colorMask(writeColor, writeColor, writeColor, writeColor);
|
||||||
|
}
|
||||||
|
|
||||||
private static void setupTexture(Material material) {
|
private static void setupTexture(Material material) {
|
||||||
Samplers.DIFFUSE.makeActive();
|
Samplers.DIFFUSE.makeActive();
|
||||||
AbstractTexture texture = Minecraft.getInstance()
|
AbstractTexture texture = Minecraft.getInstance()
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.util.List;
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.material.Material;
|
import dev.engine_room.flywheel.api.material.Material;
|
||||||
|
import dev.engine_room.flywheel.api.material.Transparency;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||||
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||||
|
@ -36,6 +37,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
private final List<IndirectInstancer<I>> instancers = new ArrayList<>();
|
private final List<IndirectInstancer<I>> instancers = new ArrayList<>();
|
||||||
private final List<IndirectDraw> indirectDraws = new ArrayList<>();
|
private final List<IndirectDraw> indirectDraws = new ArrayList<>();
|
||||||
private final List<MultiDraw> multiDraws = new ArrayList<>();
|
private final List<MultiDraw> multiDraws = new ArrayList<>();
|
||||||
|
private final List<MultiDraw> transparentDraws = new ArrayList<>();
|
||||||
|
|
||||||
private final IndirectPrograms programs;
|
private final IndirectPrograms programs;
|
||||||
private final GlProgram cullProgram;
|
private final GlProgram cullProgram;
|
||||||
|
@ -130,6 +132,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
|
|
||||||
private void sortDraws() {
|
private void sortDraws() {
|
||||||
multiDraws.clear();
|
multiDraws.clear();
|
||||||
|
transparentDraws.clear();
|
||||||
// sort by visual type, then material
|
// sort by visual type, then material
|
||||||
indirectDraws.sort(DRAW_COMPARATOR);
|
indirectDraws.sort(DRAW_COMPARATOR);
|
||||||
|
|
||||||
|
@ -138,7 +141,9 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
|
|
||||||
// if the next draw call has a different VisualType or Material, start a new MultiDraw
|
// if the next draw call has a different VisualType or Material, start a new MultiDraw
|
||||||
if (i == indirectDraws.size() - 1 || incompatibleDraws(draw1, indirectDraws.get(i + 1))) {
|
if (i == indirectDraws.size() - 1 || incompatibleDraws(draw1, indirectDraws.get(i + 1))) {
|
||||||
multiDraws.add(new MultiDraw(draw1.material(), draw1.isEmbedded(), start, i + 1));
|
var dst = draw1.material()
|
||||||
|
.transparency() == Transparency.TRANSLUCENT ? transparentDraws : multiDraws;
|
||||||
|
dst.add(new MultiDraw(draw1.material(), draw1.isEmbedded(), start, i + 1));
|
||||||
start = i + 1;
|
start = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +176,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
needsDrawSort = true;
|
needsDrawSort = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void submit() {
|
public void submitSolid() {
|
||||||
if (nothingToDo()) {
|
if (nothingToDo()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +188,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
GlProgram lastProgram = null;
|
GlProgram lastProgram = null;
|
||||||
|
|
||||||
for (var multiDraw : multiDraws) {
|
for (var multiDraw : multiDraws) {
|
||||||
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material);
|
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material, false);
|
||||||
if (drawProgram != lastProgram) {
|
if (drawProgram != lastProgram) {
|
||||||
lastProgram = drawProgram;
|
lastProgram = drawProgram;
|
||||||
|
|
||||||
|
@ -197,8 +202,34 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void submitTransparent() {
|
||||||
|
if (nothingToDo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers.bindForDraw();
|
||||||
|
|
||||||
|
drawBarrier();
|
||||||
|
|
||||||
|
GlProgram lastProgram = null;
|
||||||
|
|
||||||
|
for (var multiDraw : transparentDraws) {
|
||||||
|
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material, true);
|
||||||
|
if (drawProgram != lastProgram) {
|
||||||
|
lastProgram = drawProgram;
|
||||||
|
|
||||||
|
// Don't need to do this unless the program changes.
|
||||||
|
drawProgram.bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialRenderState.setupOit(multiDraw.material);
|
||||||
|
|
||||||
|
multiDraw.submit(drawProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void bindForCrumbling(Material material) {
|
public void bindForCrumbling(Material material) {
|
||||||
var program = programs.getIndirectProgram(instanceType, ContextShader.CRUMBLING, material);
|
var program = programs.getIndirectProgram(instanceType, ContextShader.CRUMBLING, material, false);
|
||||||
|
|
||||||
program.bind();
|
program.bind();
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||||
|
|
||||||
private final DepthPyramid depthPyramid;
|
private final DepthPyramid depthPyramid;
|
||||||
|
|
||||||
|
private final WboitFrameBuffer wboitFrameBuffer;
|
||||||
|
|
||||||
public IndirectDrawManager(IndirectPrograms programs) {
|
public IndirectDrawManager(IndirectPrograms programs) {
|
||||||
this.programs = programs;
|
this.programs = programs;
|
||||||
programs.acquire();
|
programs.acquire();
|
||||||
|
@ -62,6 +64,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||||
matrixBuffer = new MatrixBuffer();
|
matrixBuffer = new MatrixBuffer();
|
||||||
|
|
||||||
depthPyramid = new DepthPyramid(programs);
|
depthPyramid = new DepthPyramid(programs);
|
||||||
|
|
||||||
|
wboitFrameBuffer = new WboitFrameBuffer(programs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -138,9 +142,17 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||||
Uniforms.bindAll();
|
Uniforms.bindAll();
|
||||||
|
|
||||||
for (var group : cullingGroups.values()) {
|
for (var group : cullingGroups.values()) {
|
||||||
group.submit();
|
group.submitSolid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wboitFrameBuffer.setup();
|
||||||
|
|
||||||
|
for (var group : cullingGroups.values()) {
|
||||||
|
group.submitTransparent();
|
||||||
|
}
|
||||||
|
|
||||||
|
wboitFrameBuffer.composite();
|
||||||
|
|
||||||
MaterialRenderState.reset();
|
MaterialRenderState.reset();
|
||||||
TextureBinder.resetLightAndOverlay();
|
TextureBinder.resetLightAndOverlay();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
package dev.engine_room.flywheel.backend.engine.indirect;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.ARBDrawBuffersBlend;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GL46;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||||
|
import dev.engine_room.flywheel.backend.gl.GlTextureUnit;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
|
public class WboitFrameBuffer {
|
||||||
|
|
||||||
|
public final int fbo;
|
||||||
|
private final IndirectPrograms programs;
|
||||||
|
private final int vao;
|
||||||
|
|
||||||
|
public int accum;
|
||||||
|
public int reveal;
|
||||||
|
|
||||||
|
private int lastWidth = -1;
|
||||||
|
private int lastHeight = -1;
|
||||||
|
|
||||||
|
public WboitFrameBuffer(IndirectPrograms programs) {
|
||||||
|
this.programs = programs;
|
||||||
|
fbo = GL46.glCreateFramebuffers();
|
||||||
|
vao = GL46.glCreateVertexArrays();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setup() {
|
||||||
|
var mainRenderTarget = Minecraft.getInstance()
|
||||||
|
.getMainRenderTarget();
|
||||||
|
|
||||||
|
createTextures(mainRenderTarget.width, mainRenderTarget.height);
|
||||||
|
|
||||||
|
// No depth writes, but we'll still use the depth test
|
||||||
|
GlStateManager._depthMask(false);
|
||||||
|
GlStateManager._enableBlend();
|
||||||
|
ARBDrawBuffersBlend.glBlendFunciARB(0, GL46.GL_ONE, GL46.GL_ONE); // accumulation blend target
|
||||||
|
ARBDrawBuffersBlend.glBlendFunciARB(1, GL46.GL_ZERO, GL46.GL_ONE_MINUS_SRC_COLOR); // revealage blend target
|
||||||
|
GlStateManager._blendEquation(GL46.GL_FUNC_ADD);
|
||||||
|
|
||||||
|
GL46.glNamedFramebufferTexture(fbo, GL46.GL_DEPTH_ATTACHMENT, mainRenderTarget.getDepthTextureId(), 0);
|
||||||
|
|
||||||
|
GlStateManager._glBindFramebuffer(GL46.GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
|
GL46.glClearBufferfv(GL46.GL_COLOR, 0, new float[]{0, 0, 0, 0});
|
||||||
|
GL46.glClearBufferfv(GL46.GL_COLOR, 1, new float[]{1, 1, 1, 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void composite() {
|
||||||
|
var mainRenderTarget = Minecraft.getInstance()
|
||||||
|
.getMainRenderTarget();
|
||||||
|
|
||||||
|
mainRenderTarget.bindWrite(false);
|
||||||
|
|
||||||
|
var oitCompositeProgram = programs.getOitCompositeProgram();
|
||||||
|
|
||||||
|
GlStateManager._depthMask(false);
|
||||||
|
GlStateManager._depthFunc(GL46.GL_ALWAYS);
|
||||||
|
GlStateManager._enableBlend();
|
||||||
|
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
oitCompositeProgram.bind();
|
||||||
|
|
||||||
|
GlTextureUnit.T0.makeActive();
|
||||||
|
GlStateManager._bindTexture(accum);
|
||||||
|
|
||||||
|
GlTextureUnit.T1.makeActive();
|
||||||
|
GlStateManager._bindTexture(reveal);
|
||||||
|
|
||||||
|
// Empty VAO, the actual full screen triangle is generated in the vertex shader
|
||||||
|
GlStateManager._glBindVertexArray(vao);
|
||||||
|
|
||||||
|
GL46.glDrawArrays(GL46.GL_TRIANGLES, 0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
GL46.glDeleteTextures(accum);
|
||||||
|
GL46.glDeleteTextures(reveal);
|
||||||
|
GL46.glDeleteFramebuffers(fbo);
|
||||||
|
GL46.glDeleteVertexArrays(vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTextures(int width, int height) {
|
||||||
|
if (lastWidth == width && lastHeight == height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastWidth = width;
|
||||||
|
lastHeight = height;
|
||||||
|
|
||||||
|
GL46.glDeleteTextures(accum);
|
||||||
|
GL46.glDeleteTextures(reveal);
|
||||||
|
|
||||||
|
accum = GL46.glCreateTextures(GL46.GL_TEXTURE_2D);
|
||||||
|
reveal = GL46.glCreateTextures(GL46.GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
GL46.glNamedFramebufferDrawBuffers(fbo, new int[]{GL46.GL_COLOR_ATTACHMENT0, GL46.GL_COLOR_ATTACHMENT1});
|
||||||
|
|
||||||
|
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT0, accum, 0);
|
||||||
|
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT1, reveal, 0);
|
||||||
|
|
||||||
|
GL46.glTextureStorage2D(accum, 1, GL32.GL_RGBA32F, width, height);
|
||||||
|
GL46.glTextureStorage2D(reveal, 1, GL32.GL_R8, width, height);
|
||||||
|
|
||||||
|
for (int tex : new int[]{accum, reveal}) {
|
||||||
|
GL46.glTextureParameteri(tex, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_NEAREST);
|
||||||
|
GL46.glTextureParameteri(tex, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_NEAREST);
|
||||||
|
GL46.glTextureParameteri(tex, GL32.GL_TEXTURE_COMPARE_MODE, GL32.GL_NONE);
|
||||||
|
GL46.glTextureParameteri(tex, GL32.GL_TEXTURE_WRAP_S, GL32.GL_CLAMP_TO_EDGE);
|
||||||
|
GL46.glTextureParameteri(tex, GL32.GL_TEXTURE_WRAP_T, GL32.GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,20 @@ in vec2 _flw_crumblingTexCoord;
|
||||||
flat in uvec2 _flw_ids;
|
flat in uvec2 _flw_ids;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _FLW_OIT
|
||||||
|
|
||||||
|
// your first render target which is used to accumulate pre-multiplied color values
|
||||||
|
layout (location = 0) out vec4 accum;
|
||||||
|
|
||||||
|
// your second render target which is used to store pixel revealage
|
||||||
|
layout (location = 1) out float reveal;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
out vec4 _flw_outputColor;
|
out vec4 _flw_outputColor;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
float _flw_diffuseFactor() {
|
float _flw_diffuseFactor() {
|
||||||
if (flw_material.cardinalLightingMode == 2u) {
|
if (flw_material.cardinalLightingMode == 2u) {
|
||||||
return diffuseFromLightDirections(flw_vertexNormal);
|
return diffuseFromLightDirections(flw_vertexNormal);
|
||||||
|
@ -33,6 +45,11 @@ float _flw_diffuseFactor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float linearize_depth(float d, float zNear, float zFar) {
|
||||||
|
float z_n = 2.0 * d - 1.0;
|
||||||
|
return 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));
|
||||||
|
}
|
||||||
|
|
||||||
void _flw_main() {
|
void _flw_main() {
|
||||||
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
|
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
|
||||||
flw_fragColor = flw_vertexColor * flw_sampleColor;
|
flw_fragColor = flw_vertexColor * flw_sampleColor;
|
||||||
|
@ -99,5 +116,31 @@ void _flw_main() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_flw_outputColor = flw_fogFilter(color);
|
color = flw_fogFilter(color);
|
||||||
|
|
||||||
|
color.a = 0.9;
|
||||||
|
|
||||||
|
#ifdef _FLW_OIT
|
||||||
|
|
||||||
|
float depth = linearize_depth(gl_FragCoord.z, _flw_cullData.znear, _flw_cullData.zfar);
|
||||||
|
|
||||||
|
// insert your favorite weighting function here. the color-based factor
|
||||||
|
// avoids color pollution from the edges of wispy clouds. the z-based
|
||||||
|
// factor gives precedence to nearer surfaces
|
||||||
|
//float weight = clamp(pow(min(1.0, color.a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - gl_FragCoord.z * 0.9, 3.0), 1e-2, 3e3);
|
||||||
|
float weight = max(min(1.0, max(max(color.r, color.g), color.b) * color.a), color.a) *
|
||||||
|
clamp(0.03 / (1e-5 + pow(depth / 200, 4.0)), 1e-2, 3e3);
|
||||||
|
|
||||||
|
// blend func: GL_ONE, GL_ONE
|
||||||
|
// switch to pre-multiplied alpha and weight
|
||||||
|
accum = vec4(color.rgb * color.a, color.a) * weight;
|
||||||
|
|
||||||
|
// blend func: GL_ZERO, GL_ONE_MINUS_SRC_ALPHA
|
||||||
|
reveal = color.a;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
_flw_outputColor = color;
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
void main() {
|
||||||
|
vec2 vertices[3] = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3));
|
||||||
|
gl_Position = vec4(vertices[gl_VertexID], 0, 1);
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// shader outputs
|
||||||
|
layout (location = 0) out vec4 frag;
|
||||||
|
|
||||||
|
// color accumulation buffer
|
||||||
|
layout (binding = 0) uniform sampler2D accum;
|
||||||
|
|
||||||
|
// revealage threshold buffer
|
||||||
|
layout (binding = 1) uniform sampler2D reveal;
|
||||||
|
|
||||||
|
// epsilon number
|
||||||
|
const float EPSILON = 0.00001f;
|
||||||
|
|
||||||
|
// calculate floating point numbers equality accurately
|
||||||
|
bool isApproximatelyEqual(float a, float b) {
|
||||||
|
return abs(a - b) <= (abs(a) < abs(b) ? abs(b) : abs(a)) * EPSILON;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the max value between three values
|
||||||
|
float max3(vec3 v) {
|
||||||
|
return max(max(v.x, v.y), v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// fragment coordination
|
||||||
|
ivec2 coords = ivec2(gl_FragCoord.xy);
|
||||||
|
|
||||||
|
// fragment revealage
|
||||||
|
float revealage = texelFetch(reveal, coords, 0).r;
|
||||||
|
|
||||||
|
// save the blending and color texture fetch cost if there is not a transparent fragment
|
||||||
|
if (isApproximatelyEqual(revealage, 1.0f)) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fragment color
|
||||||
|
vec4 accumulation = texelFetch(accum, coords, 0);
|
||||||
|
|
||||||
|
// suppress overflow
|
||||||
|
if (isinf(max3(abs(accumulation.rgb)))) {
|
||||||
|
accumulation.rgb = vec3(accumulation.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent floating point precision bug
|
||||||
|
vec3 average_color = accumulation.rgb / max(accumulation.a, EPSILON);
|
||||||
|
|
||||||
|
// blend pixels
|
||||||
|
frag = vec4(average_color, 1.0f - revealage);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue