God i hate opengl

This commit is contained in:
mcrcortex
2024-01-28 02:59:03 +10:00
parent 3f6647af70
commit 66be05369c
5 changed files with 152 additions and 29 deletions

View File

@@ -2,7 +2,7 @@ package me.cortex.zenith.client.core.model;
import java.util.Arrays; import java.util.Arrays;
public record ColourDepthTextureData(int[] colour, int[] depth) { public record ColourDepthTextureData(int[] colour, int[] depth, int width, int height) {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null) return false; if (obj == null) return false;
@@ -12,6 +12,6 @@ public record ColourDepthTextureData(int[] colour, int[] depth) {
@Override @Override
public int hashCode() { public int hashCode() {
return Arrays.hashCode(this.colour) ^ Arrays.hashCode(this.depth); return (this.width * 312337173 * (Arrays.hashCode(this.colour) ^ Arrays.hashCode(this.depth))) ^ this.height;
} }
} }

View File

@@ -7,6 +7,7 @@ import me.cortex.zenith.client.core.gl.GlBuffer;
import me.cortex.zenith.client.core.gl.GlTexture; import me.cortex.zenith.client.core.gl.GlTexture;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderLayers; import net.minecraft.client.render.RenderLayers;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@@ -97,9 +98,9 @@ public class ModelManager {
//TODO: so need a few things, per face sizes and offsets, the sizes should be computed from the pixels and find the minimum bounding pixel //TODO: so need a few things, per face sizes and offsets, the sizes should be computed from the pixels and find the minimum bounding pixel
// while the depth is computed from the depth buffer data // while the depth is computed from the depth buffer data
public int addEntry(int blockId, BlockState blockState) { public int addEntry(int blockId, BlockState blockState) {
if (this.idMappings[blockId] != -1) { //if (this.idMappings[blockId] != -1) {
throw new IllegalArgumentException("Trying to add entry for duplicate id"); // throw new IllegalArgumentException("Trying to add entry for duplicate id");
} //}
int modelId = -1; int modelId = -1;
var textureData = this.bakery.renderFaces(blockState, 123456); var textureData = this.bakery.renderFaces(blockState, 123456);
@@ -107,7 +108,8 @@ public class ModelManager {
int possibleDuplicate = this.modelTexture2id.getInt(List.of(textureData)); int possibleDuplicate = this.modelTexture2id.getInt(List.of(textureData));
if (possibleDuplicate != -1) {//Duplicate found if (possibleDuplicate != -1) {//Duplicate found
this.idMappings[blockId] = possibleDuplicate; this.idMappings[blockId] = possibleDuplicate;
return possibleDuplicate; modelId = possibleDuplicate;
//return possibleDuplicate;
} else {//Not a duplicate so create a new entry } else {//Not a duplicate so create a new entry
modelId = this.modelTexture2id.size(); modelId = this.modelTexture2id.size();
this.idMappings[blockId] = modelId; this.idMappings[blockId] = modelId;
@@ -119,22 +121,15 @@ public class ModelManager {
var colourProvider = MinecraftClient.getInstance().getBlockColors().providers.get(Registries.BLOCK.getRawId(blockState.getBlock())); var colourProvider = MinecraftClient.getInstance().getBlockColors().providers.get(Registries.BLOCK.getRawId(blockState.getBlock()));
var blockRenderLayer = RenderLayers.getBlockLayer(blockState); var blockRenderLayer = RenderLayers.getBlockLayer(blockState);
int checkMode = blockRenderLayer==RenderLayer.getSolid()?TextureUtils.WRITE_CHECK_STENCIL:TextureUtils.WRITE_CHECK_ALPHA;
//If it is the solid layer, it is _always_ going to occlude fully for all written pixels, even if they are 100% translucent, this should save alot of resources //If it is the solid layer, it is _always_ going to occlude fully for all written pixels, even if they are 100% translucent, this should save alot of resources
// if it is cutout it might occlude might not, need to test // if it is cutout it might occlude might not, need to test
// if it is translucent it will _never_ occlude // if it is translucent it will _never_ occlude
//NOTE: this is excluding fluid states //NOTE: this is excluding fluid states
//This also checks if there is a block colour resolver for the given blockstate and marks that the block has a resolver
var sizes = this.computeModelDepth(textureData);
for (int face = 0; face < 6; face++) {
if (sizes[face] == -1) {//Face is empty, so ignore
continue;
}
//TODO: combine all the methods into a single
//boolean fullyOccluding = TextureUtils.hasAlpha()
}
//Model data contains, the quad size and offset of each face and whether the face needs to be resolved with a colour modifier //Model data contains, the quad size and offset of each face and whether the face needs to be resolved with a colour modifier
@@ -162,7 +157,20 @@ public class ModelManager {
//This also checks if there is a block colour resolver for the given blockstate and marks that the block has a resolver
var sizes = this.computeModelDepth(textureData, checkMode);
for (int face = 0; face < 6; face++) {
if (sizes[face] < -0.1) {//Face is empty, so ignore
continue;
}
//TODO: replace this with a more intelligent method that
// if using solid use TextureUtils.computeBounds() with depth testing
// if using translucent or transparent compare if alpha is 0
var faceSize = TextureUtils.computeBounds(textureData[face], checkMode);
int eee = 0;
}
@@ -170,17 +178,30 @@ public class ModelManager {
return modelId; return modelId;
} }
private int[] computeModelDepth(ColourDepthTextureData[] textures) {
int[] res = new int[6];
private float[] computeModelDepth(ColourDepthTextureData[] textures, int checkMode) {
float[] res = new float[6];
for (var dir : Direction.values()) { for (var dir : Direction.values()) {
var data = textures[dir.getId()]; var data = textures[dir.getId()];
float fd = TextureUtils.computeDepth(data, TextureUtils.DEPTH_MODE_MIN);//Compute the min float depth, smaller means closer to the camera, range 0-1 float fd = TextureUtils.computeDepth(data, TextureUtils.DEPTH_MODE_MIN, checkMode);//Compute the min float depth, smaller means closer to the camera, range 0-1
int depth = Math.round(fd * this.modelTextureSize); int depth = Math.round(fd * this.modelTextureSize);
//If fd is -1, it means that there was nothing rendered on that face and it should be discarded //If fd is -1, it means that there was nothing rendered on that face and it should be discarded
if (fd < -0.1) { if (fd < -0.1) {
res[dir.ordinal()] = -1; res[dir.ordinal()] = -1;
} else { } else {
res[dir.ordinal()] = depth; res[dir.ordinal()] = ((float) depth)/this.modelTextureSize;
} }
} }
return res; return res;

View File

@@ -90,7 +90,12 @@ public class ModelTextureBakery {
var oldProjection = new Matrix4f(RenderSystem.getProjectionMatrix()); var oldProjection = new Matrix4f(RenderSystem.getProjectionMatrix());
GL11C.glViewport(0, 0, this.width, this.height); GL11C.glViewport(0, 0, this.width, this.height);
RenderSystem.setProjectionMatrix(new Matrix4f().identity().scale(2,2,-1f).translate(-0.5f, -0.5f, 0.0f), VertexSorter.BY_Z); RenderSystem.setProjectionMatrix(new Matrix4f().identity().set(new float[]{
2,0,0,0,
0, 2,0,0,
0,0, -1f,0,
-1,-1,0,1,
}), VertexSorter.BY_Z);
glClearColor(0,0,0,0); glClearColor(0,0,0,0);
glClearDepth(1); glClearDepth(1);
@@ -100,6 +105,8 @@ public class ModelTextureBakery {
var renderLayer = RenderLayers.getBlockLayer(state); var renderLayer = RenderLayers.getBlockLayer(state);
renderLayer.startDrawing(); renderLayer.startDrawing();
glEnable(GL_STENCIL_TEST);
glDepthRange(0, 1);
RenderSystem.depthMask(true); RenderSystem.depthMask(true);
RenderSystem.enableBlend(); RenderSystem.enableBlend();
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
@@ -107,7 +114,10 @@ public class ModelTextureBakery {
RenderSystem.depthFunc(GL_LESS); RenderSystem.depthFunc(GL_LESS);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
//TODO: bind the required uniforms and glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
this.rasterShader.bind(); this.rasterShader.bind();
RenderSystem.bindTexture(RenderSystem.getShaderTexture(0)); RenderSystem.bindTexture(RenderSystem.getShaderTexture(0));
GlUniform.uniform1(0, 0); GlUniform.uniform1(0, 0);
@@ -124,14 +134,18 @@ public class ModelTextureBakery {
var faces = new ColourDepthTextureData[FACE_VIEWS.size()]; var faces = new ColourDepthTextureData[FACE_VIEWS.size()];
for (int i = 0; i < faces.length; i++) { for (int i = 0; i < faces.length; i++) {
faces[i] = captureView(state, model, FACE_VIEWS.get(i), randomValue); faces[i] = captureView(state, model, FACE_VIEWS.get(i), randomValue);
//glBlitNamedFramebuffer(this.framebuffer.id, oldFB, 0,0,16,16,300*(i%3),300*(i/3),300*(i%3)+256,300*(i/3)+256, GL_COLOR_BUFFER_BIT, GL_NEAREST);
} }
renderLayer.endDrawing(); renderLayer.endDrawing();
glDisable(GL_STENCIL_TEST);
RenderSystem.setProjectionMatrix(oldProjection, VertexSorter.BY_DISTANCE); RenderSystem.setProjectionMatrix(oldProjection, VertexSorter.BY_DISTANCE);
glBindFramebuffer(GL_FRAMEBUFFER, oldFB); glBindFramebuffer(GL_FRAMEBUFFER, oldFB);
GL11C.glViewport(GlStateManager.Viewport.getX(), GlStateManager.Viewport.getY(), GlStateManager.Viewport.getWidth(), GlStateManager.Viewport.getHeight()); GL11C.glViewport(GlStateManager.Viewport.getX(), GlStateManager.Viewport.getY(), GlStateManager.Viewport.getWidth(), GlStateManager.Viewport.getHeight());
glBlitNamedFramebuffer(this.framebuffer.id, oldFB, 0,0,16,16,0,0,256,256, GL_COLOR_BUFFER_BIT, GL_NEAREST);
//TODO: FIXME: fully revert the state of opengl
return faces; return faces;
} }
@@ -142,7 +156,7 @@ public class ModelTextureBakery {
renderQuads(vc, state, model, stack, randomValue); renderQuads(vc, state, model, stack, randomValue);
float[] mat = new float[4*4]; float[] mat = new float[4*4];
new Matrix4f(RenderSystem.getModelViewMatrix()).mul(RenderSystem.getProjectionMatrix()).get(mat); RenderSystem.getProjectionMatrix().get(mat);
glUniformMatrix4fv(1, false, mat); glUniformMatrix4fv(1, false, mat);
BufferRenderer.draw(vc.end()); BufferRenderer.draw(vc.end());
@@ -151,7 +165,7 @@ public class ModelTextureBakery {
int[] depthData = new int[this.width*this.height]; int[] depthData = new int[this.width*this.height];
glGetTextureImage(this.colourTex.id, 0, GL_RGBA, GL_UNSIGNED_BYTE, colourData); glGetTextureImage(this.colourTex.id, 0, GL_RGBA, GL_UNSIGNED_BYTE, colourData);
glGetTextureImage(this.depthTex.id, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depthData); glGetTextureImage(this.depthTex.id, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depthData);
return new ColourDepthTextureData(colourData, depthData); return new ColourDepthTextureData(colourData, depthData, this.width, this.height);
} }
private static void renderQuads(BufferBuilder builder, BlockState state, BakedModel model, MatrixStack stack, long randomValue) { private static void renderQuads(BufferBuilder builder, BlockState state, BakedModel model, MatrixStack stack, long randomValue) {

View File

@@ -22,7 +22,7 @@ public class TextureUtils {
public static int getNonWrittenPixels(ColourDepthTextureData texture) { public static int getNonWrittenPixels(ColourDepthTextureData texture) {
int count = 0; int count = 0;
for (int pixel : texture.depth()) { for (int pixel : texture.depth()) {
count += (((pixel>>8)&0xFFFFFF) == 0xFFFFFF)?1:0; count += ((pixel&0xFF) == 0)?1:0;
} }
return count; return count;
} }
@@ -36,12 +36,27 @@ public class TextureUtils {
return true; return true;
} }
public static final int WRITE_CHECK_STENCIL = 1;
public static final int WRITE_CHECK_DEPTH = 2;
public static final int WRITE_CHECK_ALPHA = 3;
private static boolean wasPixelWritten(ColourDepthTextureData data, int mode, int index) {
if (mode == WRITE_CHECK_STENCIL) {
return (data.depth()[index]&0xFF)!=0;
} else if (mode == WRITE_CHECK_DEPTH) {
return (data.depth()[index]>>>8)!=((1<<24)-1);
} else if (mode == WRITE_CHECK_ALPHA) {
return ((data.colour()[index]>>>24)&0xff)!=0;
}
throw new IllegalArgumentException();
}
public static final int DEPTH_MODE_AVG = 1; public static final int DEPTH_MODE_AVG = 1;
public static final int DEPTH_MODE_MAX = 2; public static final int DEPTH_MODE_MAX = 2;
public static final int DEPTH_MODE_MIN = 3; public static final int DEPTH_MODE_MIN = 3;
//Computes depth info based on written pixel data //Computes depth info based on written pixel data
public static float computeDepth(ColourDepthTextureData texture, int mode) { public static float computeDepth(ColourDepthTextureData texture, int mode, int checkMode) {
final var colourData = texture.colour(); final var colourData = texture.colour();
final var depthData = texture.depth(); final var depthData = texture.depth();
long a = 0; long a = 0;
@@ -53,7 +68,7 @@ public class TextureUtils {
a = Long.MIN_VALUE; a = Long.MIN_VALUE;
} }
for (int i = 0; i < colourData.length; i++) { for (int i = 0; i < colourData.length; i++) {
if ((colourData[i]&0xFF)==0) { if (!wasPixelWritten(texture, checkMode, i)) {
continue; continue;
} }
int depth = depthData[i]>>>8; int depth = depthData[i]>>>8;
@@ -87,6 +102,74 @@ public class TextureUtils {
} }
private static float u2fdepth(int depth) { private static float u2fdepth(int depth) {
return (((float)depth)/(float)(1<<24)); float depthF = (float) ((double)depth/((1<<24)-1));
//https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDepthRange.xhtml
// due to this and the unsigned bullshit, i believe the depth value needs to get multiplied by 2
depthF *= 2;
if (depthF > 1.00001f) {
throw new IllegalArgumentException("Depth greater than 1");
}
return depthF;
}
//NOTE: data goes from bottom left to top right (x first then y)
public static int[] computeBounds(ColourDepthTextureData data, int checkMode) {
final var depth = data.depth();
//Compute x bounds first
int minX = 0;
minXCheck:
do {
for (int y = 0; y < data.height(); y++) {
int idx = minX + (y * data.width());
if (wasPixelWritten(data, checkMode, idx)) {
break minXCheck;//pixel was written too so break from loop
}
}
minX++;
} while (minX != data.width());
int maxX = data.width()-1;
maxXCheck:
do {
for (int y = data.height()-1; y!=-1; y--) {
int idx = maxX + (y * data.width());
if (wasPixelWritten(data, checkMode, idx)) {
break maxXCheck;//pixel was written too so break from loop
}
}
maxX--;
} while (maxX != -1);
maxX++;
//Compute y bounds
int minY = 0;
minYCheck:
do {
for (int x = 0; x < data.width(); x++) {
int idx = (minY * data.height()) + x;
if (wasPixelWritten(data, checkMode, idx)) {
break minYCheck;//pixel was written too
}
}
minY++;
} while (minY != data.height());
int maxY = data.height()-1;
maxYCheck:
do {
for (int x = data.width()-1; x!=-1; x--) {
int idx = (maxY * data.height()) + x;
if (wasPixelWritten(data, checkMode, idx)) {
break maxYCheck;//pixel was written too so break from loop
}
}
maxY--;
} while (maxY != -1);
maxY++;
return new int[]{minX, maxX, minY, maxY};
} }
} }

View File

@@ -7,8 +7,11 @@ import me.cortex.zenith.client.core.gl.shader.ShaderType;
import me.cortex.zenith.client.core.rendering.util.UploadStream; import me.cortex.zenith.client.core.rendering.util.UploadStream;
import me.cortex.zenith.client.mixin.joml.AccessFrustumIntersection; import me.cortex.zenith.client.mixin.joml.AccessFrustumIntersection;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.WallMountedBlock;
import net.minecraft.block.enums.BlockFace;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Direction;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.opengl.GL11C; import org.lwjgl.opengl.GL11C;
@@ -75,11 +78,13 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer {
} }
public void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz) { public void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz) {
this.getModelManager().addEntry(this.frameId%(1<<15), Blocks.OAK_BUTTON.getDefaultState().with(WallMountedBlock.FACE, BlockFace.FLOOR).with(WallMountedBlock.FACING, Direction.SOUTH));
//this.getModelManager().addEntry(this.frameId%(1<<15), Blocks.HEAVY_WEIGHTED_PRESSURE_PLATE.getDefaultState());
//this.getModelManager().addEntry(this.frameId%(1<<15), Blocks.COMPARATOR.getDefaultState());
if (this.geometry.getSectionCount() == 0) { if (this.geometry.getSectionCount() == 0) {
return; return;
} }
//this.getModelManager().addEntry(this.frameId%(1<<15), Blocks.OAK_BUTTON.getDefaultState());
RenderLayer.getCutoutMipped().startDrawing(); RenderLayer.getCutoutMipped().startDrawing();
int oldActiveTexture = glGetInteger(GL_ACTIVE_TEXTURE); int oldActiveTexture = glGetInteger(GL_ACTIVE_TEXTURE);