work on chunk outline renderer
This commit is contained in:
@@ -12,6 +12,9 @@ public class GlTexture extends TrackedObject {
|
|||||||
public final int id;
|
public final int id;
|
||||||
private final int type;
|
private final int type;
|
||||||
private int format;
|
private int format;
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private int layers;
|
||||||
public GlTexture() {
|
public GlTexture() {
|
||||||
this(GL_TEXTURE_2D);
|
this(GL_TEXTURE_2D);
|
||||||
}
|
}
|
||||||
@@ -34,6 +37,9 @@ public class GlTexture extends TrackedObject {
|
|||||||
this.format = format;
|
this.format = format;
|
||||||
if (this.type == GL_TEXTURE_2D) {
|
if (this.type == GL_TEXTURE_2D) {
|
||||||
glTextureStorage2D(this.id, levels, format, width, height);
|
glTextureStorage2D(this.id, levels, format, width, height);
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.layers = layers;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unknown texture type");
|
throw new IllegalStateException("Unknown texture type");
|
||||||
}
|
}
|
||||||
@@ -55,4 +61,16 @@ public class GlTexture extends TrackedObject {
|
|||||||
public GlTexture name(String name) {
|
public GlTexture name(String name) {
|
||||||
return GlDebug.name(name, this);
|
return GlDebug.name(name, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLayers() {
|
||||||
|
return this.layers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ public class ModelTextureBakery {
|
|||||||
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, this.capture.framebuffer.id);
|
glBindFramebuffer(GL_FRAMEBUFFER, this.capture.framebuffer.id);
|
||||||
|
//TODO: make use glClearNamedFramebuffer* to reduce/remove state change
|
||||||
glClearColor(0,0,0,0);
|
glClearColor(0,0,0,0);
|
||||||
glClearDepth(1);
|
glClearDepth(1);
|
||||||
glClearStencil(0);
|
glClearStencil(0);
|
||||||
|
|||||||
@@ -3,19 +3,30 @@ package me.cortex.voxy.client.core.rendering;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
|
import me.cortex.voxy.client.core.gl.GlFramebuffer;
|
||||||
|
import me.cortex.voxy.client.core.gl.GlTexture;
|
||||||
|
import me.cortex.voxy.client.core.gl.shader.Shader;
|
||||||
|
import me.cortex.voxy.client.core.gl.shader.ShaderType;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.joml.Vector3i;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import static me.cortex.voxy.client.core.rendering.PrintfDebugUtil.PRINTF_processor;
|
||||||
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
||||||
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
|
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
|
||||||
import static org.lwjgl.opengl.GL15.glBindBuffer;
|
import static org.lwjgl.opengl.GL15.glBindBuffer;
|
||||||
import static org.lwjgl.opengl.GL30.glBindBufferBase;
|
import static org.lwjgl.opengl.GL30.glBindBufferBase;
|
||||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||||
|
import static org.lwjgl.opengl.GL30C.*;
|
||||||
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
|
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
|
||||||
import static org.lwjgl.opengl.GL31.glDrawElementsInstanced;
|
import static org.lwjgl.opengl.GL31.glDrawElementsInstanced;
|
||||||
import static org.lwjgl.opengl.GL40C.GL_DRAW_INDIRECT_BUFFER;
|
import static org.lwjgl.opengl.GL40C.GL_DRAW_INDIRECT_BUFFER;
|
||||||
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER;
|
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER;
|
||||||
|
import static org.lwjgl.opengl.GL45.glClearNamedFramebufferfv;
|
||||||
|
|
||||||
//This is a render subsystem, its very simple in what it does
|
//This is a render subsystem, its very simple in what it does
|
||||||
// it renders an AABB around loaded chunks, thats it
|
// it renders an AABB around loaded chunks, thats it
|
||||||
@@ -25,12 +36,24 @@ public class ChunkBoundRenderer {
|
|||||||
private final GlBuffer uniformBuffer = new GlBuffer(128);
|
private final GlBuffer uniformBuffer = new GlBuffer(128);
|
||||||
private final Long2IntOpenHashMap chunk2idx = new Long2IntOpenHashMap(MAX_CHUNK_COUNT);
|
private final Long2IntOpenHashMap chunk2idx = new Long2IntOpenHashMap(MAX_CHUNK_COUNT);
|
||||||
private final long[] idx2chunk = new long[MAX_CHUNK_COUNT];
|
private final long[] idx2chunk = new long[MAX_CHUNK_COUNT];
|
||||||
|
private final Shader rasterShader = Shader.makeAuto()
|
||||||
|
.add(ShaderType.VERTEX, "voxy:chunkoutline/outline.vsh")
|
||||||
|
.add(ShaderType.FRAGMENT, "voxy:chunkoutline/outline.fsh")
|
||||||
|
.compile()
|
||||||
|
.ssbo(0, this.uniformBuffer)
|
||||||
|
.ssbo(1, this.chunkPosBuffer);
|
||||||
|
|
||||||
|
private GlTexture depthBuffer = new GlTexture().store(GL_DEPTH_COMPONENT24, 1, 128, 128);
|
||||||
|
private final GlFramebuffer frameBuffer = new GlFramebuffer().bind(GL_DEPTH_ATTACHMENT, this.depthBuffer).verify();
|
||||||
|
|
||||||
public ChunkBoundRenderer() {
|
public ChunkBoundRenderer() {
|
||||||
this.chunk2idx.defaultReturnValue(-1);
|
this.chunk2idx.defaultReturnValue(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addChunk(long pos) {
|
public void addChunk(long pos) {
|
||||||
|
if (this.chunk2idx.size() >= MAX_CHUNK_COUNT) {
|
||||||
|
throw new IllegalStateException("At capacity");
|
||||||
|
}
|
||||||
if (this.chunk2idx.containsKey(pos)) {
|
if (this.chunk2idx.containsKey(pos)) {
|
||||||
throw new IllegalArgumentException("Chunk already in map");
|
throw new IllegalArgumentException("Chunk already in map");
|
||||||
}
|
}
|
||||||
@@ -75,22 +98,62 @@ public class ChunkBoundRenderer {
|
|||||||
|
|
||||||
//Bind and render, changing as little gl state as possible so that the caller may configure how it wants to render
|
//Bind and render, changing as little gl state as possible so that the caller may configure how it wants to render
|
||||||
public void render(Viewport<?> viewport) {
|
public void render(Viewport<?> viewport) {
|
||||||
|
if (this.depthBuffer.getWidth() != viewport.width || this.depthBuffer.getHeight() != viewport.height) {
|
||||||
|
this.depthBuffer.free();
|
||||||
|
this.depthBuffer = new GlTexture().store(GL_DEPTH_COMPONENT24, 1, viewport.width, viewport.height);
|
||||||
|
this.frameBuffer.bind(GL_DEPTH_ATTACHMENT, this.depthBuffer).verify();
|
||||||
|
}
|
||||||
|
|
||||||
long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 128);
|
long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 128);
|
||||||
viewport.MVP.getToAddress(ptr); ptr += 4*4*4;
|
long matPtr = ptr; ptr += 4*4*4;
|
||||||
viewport.section.getToAddress(ptr); ptr += 4*4;
|
{//This is recomputed to be in chunk section space not worldsection
|
||||||
viewport.innerTranslation.getToAddress(ptr); ptr += 4*4;
|
int sx = MathHelper.floor(viewport.cameraX) >> 4;
|
||||||
|
int sy = MathHelper.floor(viewport.cameraY) >> 4;
|
||||||
|
int sz = MathHelper.floor(viewport.cameraZ) >> 4;
|
||||||
|
new Vector3i(sx, sy, sz).getToAddress(ptr); ptr += 4*4;
|
||||||
|
|
||||||
|
viewport.MVP.translate(
|
||||||
|
-(float) (viewport.cameraX - (sx << 4)),
|
||||||
|
-(float) (viewport.cameraY - (sy << 4)),
|
||||||
|
-(float) (viewport.cameraZ - (sz << 4)),
|
||||||
|
new Matrix4f()).getToAddress(matPtr);
|
||||||
|
}
|
||||||
UploadStream.INSTANCE.commit();
|
UploadStream.INSTANCE.commit();
|
||||||
|
|
||||||
|
|
||||||
//TODO: NOTE: need to reverse the winding order since we want the back faces of the AABB, not the front
|
//TODO: NOTE: need to reverse the winding order since we want the back faces of the AABB, not the front
|
||||||
//this.cullShader.bind();
|
{
|
||||||
|
glFrontFace(GL_CW);//Reverse winding order
|
||||||
|
|
||||||
|
//"reverse depth buffer" it goes from 0->1 where 1 is far away
|
||||||
|
glClearNamedFramebufferfv(this.frameBuffer.id, GL_DEPTH, 0, new float[]{0});
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_GREATER);
|
||||||
|
}
|
||||||
|
|
||||||
glBindVertexArray(RenderService.STATIC_VAO);
|
glBindVertexArray(RenderService.STATIC_VAO);
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
|
glBindFramebuffer(GL_FRAMEBUFFER, this.frameBuffer.id);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.chunkPosBuffer.id);
|
this.rasterShader.bind();
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE.id());
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE.id());
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, 6*2*3, GL_UNSIGNED_BYTE, SharedIndexBuffer.CUBE_INDEX_OFFSET, this.chunk2idx.size());
|
glDrawElementsInstanced(GL_TRIANGLES, 6*2*3, GL_UNSIGNED_BYTE, SharedIndexBuffer.CUBE_INDEX_OFFSET, this.chunk2idx.size());
|
||||||
|
|
||||||
|
{
|
||||||
|
glFrontFace(GL_CCW);//Restore winding order
|
||||||
|
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
|
||||||
|
//TODO: check this is correct
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void free() {
|
public void free() {
|
||||||
|
this.depthBuffer.free();
|
||||||
|
this.frameBuffer.free();
|
||||||
|
|
||||||
|
this.rasterShader.free();
|
||||||
this.uniformBuffer.free();
|
this.uniformBuffer.free();
|
||||||
this.chunkPosBuffer.free();
|
this.chunkPosBuffer.free();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package me.cortex.voxy.client.mixin.sodium;
|
|||||||
|
|
||||||
import me.cortex.voxy.client.VoxyClientInstance;
|
import me.cortex.voxy.client.VoxyClientInstance;
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
|
import me.cortex.voxy.client.core.IGetVoxyRenderSystem;
|
||||||
import me.cortex.voxy.commonImpl.VoxyCommon;
|
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||||
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
|
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
@@ -18,13 +19,23 @@ public class MixinRenderSectionManager {
|
|||||||
|
|
||||||
@Inject(method = "onChunkAdded", at = @At("HEAD"))
|
@Inject(method = "onChunkAdded", at = @At("HEAD"))
|
||||||
private void voxy$trackChunkAdd(int x, int z, CallbackInfo ci) {
|
private void voxy$trackChunkAdd(int x, int z, CallbackInfo ci) {
|
||||||
|
if (this.level.worldRenderer != null) {
|
||||||
|
var system = ((IGetVoxyRenderSystem)(this.level.worldRenderer)).getVoxyRenderSystem();
|
||||||
|
if (system != null) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(method = "onChunkRemoved", at = @At("HEAD"))
|
@Inject(method = "onChunkRemoved", at = @At("HEAD"))
|
||||||
private void voxy$trackChunkRemove(int x, int z, CallbackInfo ci) {
|
private void voxy$trackChunkRemove(int x, int z, CallbackInfo ci) {
|
||||||
|
if (this.level.worldRenderer != null) {
|
||||||
|
var system = ((IGetVoxyRenderSystem)(this.level.worldRenderer)).getVoxyRenderSystem();
|
||||||
|
if (system != null) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(method = "onChunkRemoved", at = @At("HEAD"))
|
@Inject(method = "onChunkRemoved", at = @At("HEAD"))
|
||||||
private void injectIngest(int x, int z, CallbackInfo ci) {
|
private void injectIngest(int x, int z, CallbackInfo ci) {
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#version 460 core
|
||||||
|
layout(early_fragment_tests) in;
|
||||||
|
|
||||||
|
void main() {}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 uv;
|
||||||
|
layout(binding = 0, std140) uniform SceneUniform {
|
||||||
|
mat4 MVP;
|
||||||
|
ivec4 section;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(binding = 1, std430) restrict readonly buffer ChunkPosBuffer {
|
||||||
|
ivec2[] chunkPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec3 cubeCornerI = ivec3(gl_VertexID&1, (gl_VertexID>>2)&1, (gl_VertexID>>1)&1);
|
||||||
|
cubeCornerI.xz += chunkPos[gl_InstanceID];
|
||||||
|
//Expand the y height to be big (will be +- 8192)
|
||||||
|
//TODO: make it W.R.T world height and offsets
|
||||||
|
cubeCornerI.y = cubeCornerI.y*1024-512;
|
||||||
|
cubeCornerI -= section.xyz;
|
||||||
|
gl_Position = MVP * vec4(vec3(cubeCornerI*16), 1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user