Began major engineering on texturing

This commit is contained in:
mcrcortex
2024-01-24 22:49:55 +10:00
parent 48ec40c5c2
commit dd953fc774
21 changed files with 273 additions and 322 deletions

View File

@@ -46,7 +46,9 @@ dependencies {
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation "maven.modrinth:sodium:mc1.20.3-0.5.5"
//TODO: this is to eventually not need sodium installed as atm its just used for parsing shaders
modRuntimeOnly "maven.modrinth:sodium:mc1.20.3-0.5.5"
modCompileOnly "maven.modrinth:sodium:mc1.20.3-0.5.5"
modImplementation("maven.modrinth:cloth-config:13.0.121+fabric")
modImplementation("maven.modrinth:modmenu:9.0.0")

View File

@@ -1,23 +1,20 @@
package me.cortex.zenith.client.core;
import me.cortex.zenith.client.Zenith;
import me.cortex.zenith.client.config.ZenithConfig;
import me.cortex.zenith.client.core.model.ModelTextureBakery;
import me.cortex.zenith.client.core.model.TextureUtils;
import me.cortex.zenith.client.core.rendering.*;
import me.cortex.zenith.client.core.rendering.building.RenderGenerationService;
import me.cortex.zenith.client.core.util.DebugUtil;
import me.cortex.zenith.common.world.WorldEngine;
import me.cortex.zenith.client.core.other.BiomeColour;
import me.cortex.zenith.client.core.other.BlockStateColour;
import me.cortex.zenith.client.core.other.ColourResolver;
import me.cortex.zenith.common.world.other.Mapper;
import me.cortex.zenith.client.importers.WorldImporter;
import me.cortex.zenith.common.world.storage.FragmentedStorageBackendAdaptor;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.CropBlock;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Frustum;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import net.minecraft.world.chunk.WorldChunk;
@@ -83,39 +80,11 @@ public class VoxelCore {
this.postProcessing = null;//new PostProcessing();
this.world.getMapper().setCallbacks(this::stateUpdate, this::biomeUpdate);
for (var state : this.world.getMapper().getStateEntries()) {
this.stateUpdate(state);
}
for (var biome : this.world.getMapper().getBiomeEntries()) {
this.biomeUpdate(biome);
}
System.out.println("Entry updates applied");
this.world.getMapper().setCallbacks(a->{}, a->{});
System.out.println("Voxel core initialized");
}
private void stateUpdate(Mapper.StateEntry entry) {
var state = entry.state;
int tintMsk = 0;
if (biomeTintableAllFaces.contains(state.getBlock())) {
tintMsk |= (1<<6)-1;
}
if (biomeTintableUpFace.contains(state.getBlock())) {
tintMsk |= 1<<Direction.UP.getId();
}
if (waterTint.contains(state.getBlock())) {
tintMsk |= 1<<6;
}
this.renderer.enqueueUpdate(new BlockStateColour(entry.id, tintMsk, ColourResolver.resolveColour(state)));
}
private void biomeUpdate(Mapper.BiomeEntry entry) {
long dualColour = ColourResolver.resolveBiomeColour(entry.biome);
this.renderer.enqueueUpdate(new BiomeColour(entry.id, (int) dualColour, (int) (dualColour>>32)));
}
public void enqueueIngest(WorldChunk worldChunk) {
@@ -129,7 +98,7 @@ public class VoxelCore {
this.firstTime = false;
}
this.distanceTracker.setCenter(camera.getBlockPos().getX(), camera.getBlockPos().getY(), camera.getBlockPos().getZ());
this.renderer.setupRender(frustum, camera);
//this.renderer.setupRender(frustum, camera);
}
public void renderOpaque(MatrixStack matrices, double cameraX, double cameraY, double cameraZ) {
@@ -138,6 +107,8 @@ public class VoxelCore {
DebugUtil.setPositionMatrix(matrices);
matrices.pop();
renderer.getModelManager().updateEntry(0, Blocks.FERN.getDefaultState());
//int boundFB = GlStateManager.getBoundFramebuffer();
//this.postProcessing.setSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
//this.postProcessing.bindClearFramebuffer();
@@ -150,7 +121,8 @@ public class VoxelCore {
//TODO: have the renderer also render a bounding full face just like black boarders around lvl 0
// this is cause the terrain might not exist and so all the caves are visible causing hell for the
// occlusion culler
this.renderer.renderFarAwayOpaque(matrices, cameraX, cameraY, cameraZ);
if (false)
this.renderer.renderFarAwayOpaque(matrices, cameraX, cameraY, cameraZ);
//glBindFramebuffer(GL_FRAMEBUFFER, boundFB);

View File

@@ -10,6 +10,11 @@ import static org.lwjgl.opengl.GL45C.glNamedBufferStorage;
public class GlBuffer extends TrackedObject {
public final int id;
private final long size;
public GlBuffer(long size) {
this(size, 0);
}
public GlBuffer(long size, int flags) {
this.id = glCreateBuffers();
this.size = size;

View File

@@ -21,10 +21,11 @@ public class GlFramebuffer extends TrackedObject {
glDeleteFramebuffers(this.id);
}
public void verify() {
public GlFramebuffer verify() {
int code;
if ((code = glCheckNamedFramebufferStatus(this.id, GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
throw new IllegalStateException("Framebuffer incomplete with error code: " + code);
}
return this;
}
}

View File

@@ -0,0 +1,4 @@
package me.cortex.zenith.client.core.model;
public record ColourDepthTextureData(int[] colour, int[] depth) {
}

View File

@@ -0,0 +1,37 @@
package me.cortex.zenith.client.core.model;
import me.cortex.zenith.client.core.gl.GlBuffer;
import net.minecraft.block.BlockState;
//Manages the storage and updating of model states, textures and colours
//Also has a fast long[] based metadata lookup for when the terrain mesher needs to look up the face occlusion data
public class ModelManager {
public static final int MODEL_SIZE = 64;
private final ModelTextureBakery bakery = new ModelTextureBakery(16, 16);
private final GlBuffer modelBuffer;
private final long[] metadataCache;
public ModelManager() {
this.modelBuffer = new GlBuffer(MODEL_SIZE * (1<<16));
this.metadataCache = new long[1<<16];
}
public void updateEntry(int id, BlockState blockState) {
//This also checks if there is a block colour resolver for the given blockstate and marks that the block has a resolver
var textureData = this.bakery.renderFaces(blockState, 123456);
}
public long getModelMetadata(int id) {
return this.metadataCache[id];
}
public int getBufferId() {
return this.modelBuffer.id;
}
public void free() {
this.bakery.free();
this.modelBuffer.free();
}
}

View File

@@ -0,0 +1,142 @@
package me.cortex.zenith.client.core.model;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.systems.VertexSorter;
import me.cortex.zenith.client.core.gl.GlFramebuffer;
import me.cortex.zenith.client.core.gl.GlTexture;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.random.LocalRandom;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11C;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengl.ARBFramebufferObject.*;
import static org.lwjgl.opengl.ARBShaderImageLoadStore.GL_FRAMEBUFFER_BARRIER_BIT;
import static org.lwjgl.opengl.ARBShaderImageLoadStore.glMemoryBarrier;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL14C.glBlendFuncSeparate;
import static org.lwjgl.opengl.GL45C.glBlitNamedFramebuffer;
import static org.lwjgl.opengl.GL45C.glGetTextureImage;
//Builds a texture for each face of a model
public class ModelTextureBakery {
private final int width;
private final int height;
private final GlTexture colourTex;
private final GlTexture depthTex;
private final GlFramebuffer framebuffer;
private static final List<MatrixStack> FACE_VIEWS = new ArrayList<>();
static {
addView(-90,0);//Direction.DOWN
addView(90,0);//Direction.UP
addView(0,180);//Direction.NORTH
addView(0,0);//Direction.SOUTH
//TODO: check these arnt the wrong way round
addView(0,90);//Direction.EAST
addView(0,270);//Direction.WEST
}
public ModelTextureBakery(int width, int height) {
this.width = width;
this.height = height;
this.colourTex = new GlTexture().store(GL_RGBA8, 1, width, height);
this.depthTex = new GlTexture().store(GL_DEPTH24_STENCIL8, 1, width, height);
this.framebuffer = new GlFramebuffer().bind(GL_COLOR_ATTACHMENT0, this.colourTex).bind(GL_DEPTH_STENCIL_ATTACHMENT, this.depthTex).verify();
}
private static void addView(float pitch, float yaw) {
var stack = new MatrixStack();
stack.translate(0.5f,0.5f,0);
stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch));
stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
stack.translate(-0.5f,-0.5f,-0.5f);
FACE_VIEWS.add(stack);
}
public ColourDepthTextureData[] renderFaces(BlockState state, long randomValue) {
var model = MinecraftClient.getInstance()
.getBakedModelManager()
.getBlockModels()
.getModel(state);
int oldFB = GlStateManager.getBoundFramebuffer();
var oldProjection = new Matrix4f(RenderSystem.getProjectionMatrix());
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);
glClearColor(0,0,0,0);
glClearDepth(1);
glBindFramebuffer(GL_FRAMEBUFFER, this.framebuffer.id);
RenderSystem.depthMask(true);
RenderSystem.enableBlend();
RenderSystem.enableDepthTest();
RenderSystem.enableCull();
RenderSystem.depthFunc(GL_LESS);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
if (!state.getFluidState().isEmpty()) {
//TODO: render fluid
}
var renderLayer = RenderLayers.getBlockLayer(state);
if (renderLayer == RenderLayer.getTranslucent()) {
//TODO: TRANSLUCENT, must sort the quad first
}
var faces = new ColourDepthTextureData[FACE_VIEWS.size()];
for (int i = 0; i < faces.length; i++) {
faces[i] = captureView(state, model, FACE_VIEWS.get(i), randomValue);
}
RenderSystem.setProjectionMatrix(oldProjection, VertexSorter.BY_DISTANCE);
glBindFramebuffer(GL_FRAMEBUFFER, oldFB);
GL11C.glViewport(GlStateManager.Viewport.getX(), GlStateManager.Viewport.getY(), GlStateManager.Viewport.getWidth(), GlStateManager.Viewport.getHeight());
return faces;
}
private ColourDepthTextureData captureView(BlockState state, BakedModel model, MatrixStack stack, long randomValue) {
var vc = Tessellator.getInstance().getBuffer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
renderQuads(vc, state, model, stack, randomValue);
BufferRenderer.drawWithGlobalProgram(vc.end());
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
int[] colourData = 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.depthTex.id, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depthData);
return new ColourDepthTextureData(colourData, depthData);
}
private static void renderQuads(BufferBuilder builder, BlockState state, BakedModel model, MatrixStack stack, long randomValue) {
for (Direction direction : new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, null}) {
var quads = model.getQuads(state, direction, new LocalRandom(randomValue));
for (var quad : quads) {
builder.quad(stack.peek(), quad, 0, 0, 0, 0, 0);
}
}
}
public void free() {
this.framebuffer.free();
this.colourTex.free();
this.depthTex.free();
}
}

View File

@@ -0,0 +1,46 @@
package me.cortex.zenith.client.core.model;
//Texturing utils to manipulate data from the model bakery
public class TextureUtils {
//Returns if any pixels are not fully transparent or fully translucent
public static boolean hasAlpha(ColourDepthTextureData texture) {
for (int pixel : texture.colour()) {
int alpha = (pixel>>24)&0xFF;
if (alpha != 0 && alpha != 255) {
return true;
}
}
return false;
}
public static boolean isSolid(ColourDepthTextureData texture) {
for (int pixel : texture.colour()) {
if (((pixel>>24)&0xFF) != 255) {
return false;
}
}
return true;
}
public static boolean isFullyCovered(ColourDepthTextureData texture) {
for (int pixel : texture.colour()) {
if (((pixel>>24)&0xFF) == 0) {
return false;
}
}
return true;
}
public static int computeDepth(ColourDepthTextureData texture, int mode) {
final var colourData = texture.colour();
final var depthData = texture.depth();
for (int i = 0; i < colourData.length; i++) {
if ((colourData[0]&0xFF)==0) {
continue;
}
int depth = depthData[0]&0xffffff;
}
return 0;
}
}

View File

@@ -1,4 +0,0 @@
package me.cortex.zenith.client.core.other;
public record BiomeColour(int id, int foliageColour, int waterColour) {
}

View File

@@ -1,4 +0,0 @@
package me.cortex.zenith.client.core.other;
public record BlockStateColour(int id, int biomeTintMsk, int[] faceColours) {
}

View File

@@ -1,138 +0,0 @@
package me.cortex.zenith.client.core.other;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.texture.NativeImage;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.LocalRandom;
public class ColourResolver {
//TODO: sample from multiple random values and avg it
public static int[] resolveColour(BlockState state) {
return resolveColour(state, 1234567890L);
}
//The way this works is it takes the and computes its colour, it then computes the area of the quad and the normal direction
// it adds each area and colour to a per direcition colour
// for non specific axis dimensions it takes the normal of each quad computes the dot between it and each of the directions
// and averages that
// if the colour doesnt exist for a specific axis set it to the average of the other axis and or make it translucent
//TODO: fixme: finish
public static int[] resolveColour(BlockState state, long randomValue) {
if (state == Blocks.AIR.getDefaultState()) {
return new int[6];
}
int[][] builder = new int[6][5];
var random = new LocalRandom(randomValue);
if (state.getFluidState().isEmpty()) {
for (Direction direction : new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, null}) {
var quads = MinecraftClient.getInstance()
.getBakedModelManager()
.getBlockModels()
.getModel(state)
.getQuads(state, direction, random);
for (var quad : quads) {
long weightColour = resolveQuadColour(quad);
int colour = (int) weightColour;
int weight = (int) (weightColour>>32);
if (direction == null) {
//TODO: apply normal multiplication to weight
for (int i = 0; i < 6; i++) {
builder[i][0] += weight;
builder[i][4] += weight * ((colour>>>24)&0xFF);
builder[i][3] += weight * ((colour>>>16)&0xFF);
builder[i][2] += weight * ((colour>>>8)&0xFF);
builder[i][1] += weight * ((colour>>>0)&0xFF);
}
} else {
builder[direction.getId()][0] += weight;
builder[direction.getId()][4] += weight*((colour>>>24)&0xFF);
builder[direction.getId()][3] += weight*((colour>>>16)&0xFF);
builder[direction.getId()][2] += weight*((colour>>>8)&0xFF);
builder[direction.getId()][1] += weight*((colour>>>0)&0xFF);
}
}
}
} else {
//TODO FIXME: need to account for both the fluid and block state at the same time
//FIXME: make it not hacky and use the fluid handler thing from fabric
long weightColour = resolveNI(MinecraftClient.getInstance().getBakedModelManager().getBlockModels().getModelParticleSprite(state).getContents().image);
for (int i = 0; i < 6; i++) {
builder[i][0] = 1;
builder[i][1] += (weightColour>>0)&0xFF;
builder[i][2] += (weightColour>>8)&0xFF;
builder[i][3] += (weightColour>>16)&0xFF;
builder[i][4] += (weightColour>>24)&0xFF;
}
}
int[] out = new int[6];
for (int i = 0; i < 6; i++) {
int c = builder[i][0];
if (c == 0) {
continue;
}
int r = builder[i][4]/c;
int g = builder[i][3]/c;
int b = builder[i][2]/c;
int a = builder[i][1]/c;
out[i] = (r<<24)|(g<<16)|(b<<8)|a;
}
return out;
}
private static long resolveQuadColour(BakedQuad quad) {
return resolveNI(quad.getSprite().getContents().image);
}
private static long resolveNI(NativeImage image) {
int r = 0;
int g = 0;
int b = 0;
int a = 0;
int count = 0;
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int colour = image.getColor(x, y);
if (((colour >>> 24)&0xFF) == 0) {
continue;
}
r += (colour >>> 0) & 0xFF;
g += (colour >>> 8) & 0xFF;
b += (colour >>> 16) & 0xFF;
a += (colour >>> 24) & 0xFF;
count++;
}
}
if (count == 0) {
return 0;
}
r /= count;
g /= count;
b /= count;
a /= count;
int colour = (r<<24)|(g<<16)|(b<<8)|a;
return Integer.toUnsignedLong(colour)|(((long)count)<<32);
}
public static long resolveBiomeColour(String biomeId) {
var biome = MinecraftClient.getInstance().world.getRegistryManager().get(RegistryKeys.BIOME).get(new Identifier(biomeId));
if (biome == null) {
System.err.println("Biome: " + biomeId + " doesnt exist in registry!");
return 0;
}
int ARGBFoliage = biome.getFoliageColor();
int ARGBWater = biome.getWaterColor();
return Integer.toUnsignedLong(((ARGBFoliage&0xFFFFFF)<<8)|(ARGBFoliage>>>24)) | (Integer.toUnsignedLong(((ARGBWater&0xFFFFFF)<<8)|(ARGBWater>>>24))<<32);
}
}

View File

@@ -4,10 +4,9 @@ package me.cortex.zenith.client.core.rendering;
// could maybe tosomething else
import me.cortex.zenith.client.core.gl.GlBuffer;
import me.cortex.zenith.client.core.model.ModelManager;
import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry;
import me.cortex.zenith.client.core.rendering.util.UploadStream;
import me.cortex.zenith.client.core.other.BiomeColour;
import me.cortex.zenith.client.core.other.BlockStateColour;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Frustum;
@@ -16,7 +15,6 @@ import org.joml.FrustumIntersection;
import org.lwjgl.system.MemoryUtil;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque;
import static org.lwjgl.opengl.ARBMultiDrawIndirect.glMultiDrawElementsIndirect;
import static org.lwjgl.opengl.GL30.*;
@@ -35,14 +33,9 @@ public abstract class AbstractFarWorldRenderer {
protected final GlBuffer uniformBuffer;
protected final GeometryManager geometry;
private final ConcurrentLinkedDeque<BlockStateColour> stateUpdateQueue = new ConcurrentLinkedDeque<>();
private final ConcurrentLinkedDeque<BiomeColour> biomeUpdateQueue = new ConcurrentLinkedDeque<>();
protected final GlBuffer stateDataBuffer;
protected final GlBuffer biomeDataBuffer;
protected final ModelManager models;
protected final GlBuffer lightDataBuffer;
//Current camera base level section position
protected int sx;
protected int sy;
@@ -51,12 +44,10 @@ public abstract class AbstractFarWorldRenderer {
protected FrustumIntersection frustum;
public AbstractFarWorldRenderer(int geometrySize, int maxSections) {
this.uniformBuffer = new GlBuffer(1024, 0);
//TODO: make these both dynamically sized
this.stateDataBuffer = new GlBuffer((1<<16)*28, 0);//Capacity for 1<<16 entries
this.biomeDataBuffer = new GlBuffer(512*4*2, 0);//capacity for 1<<9 entries
this.lightDataBuffer = new GlBuffer(256*4, 0);//256 of uint
this.uniformBuffer = new GlBuffer(1024);
this.lightDataBuffer = new GlBuffer(256*4);//256 of uint
this.geometry = new GeometryManager(geometrySize*8L, maxSections);
this.models = new ModelManager();
}
protected abstract void setupVao();
@@ -89,36 +80,10 @@ public abstract class AbstractFarWorldRenderer {
//Upload any new geometry
this.geometry.uploadResults();
//Upload any block state changes
while (!this.stateUpdateQueue.isEmpty()) {
var stateUpdate = this.stateUpdateQueue.pop();
long ptr = UploadStream.INSTANCE.upload(this.stateDataBuffer, stateUpdate.id()*28L, 28);
MemoryUtil.memPutInt(ptr, stateUpdate.biomeTintMsk()); ptr+=4;
for (int faceColour : stateUpdate.faceColours()) {
MemoryUtil.memPutInt(ptr, faceColour); ptr+=4;
}
}
//Upload any biome changes
while (!this.biomeUpdateQueue.isEmpty()) {
var biomeUpdate = this.biomeUpdateQueue.pop();
long ptr = UploadStream.INSTANCE.upload(this.biomeDataBuffer, biomeUpdate.id()*8L, 8);
MemoryUtil.memPutInt(ptr, biomeUpdate.foliageColour()); ptr+=4;
MemoryUtil.memPutInt(ptr, biomeUpdate.waterColour()); ptr+=4;
}
}
public abstract void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz);
public void enqueueUpdate(BlockStateColour stateColour) {
this.stateUpdateQueue.add(stateColour);
}
public void enqueueUpdate(BiomeColour biomeColour) {
this.biomeUpdateQueue.add(biomeColour);
}
public void enqueueResult(BuiltSectionGeometry result) {
this.geometry.enqueueResult(result);
}
@@ -129,10 +94,13 @@ public abstract class AbstractFarWorldRenderer {
public void shutdown() {
glDeleteVertexArrays(this.vao);
this.models.free();
this.geometry.free();
this.uniformBuffer.free();
this.stateDataBuffer.free();
this.biomeDataBuffer.free();
this.lightDataBuffer.free();
}
public ModelManager getModelManager() {
return this.models;
}
}

View File

@@ -43,7 +43,7 @@ public class GeometryManager {
public GeometryManager(long geometryBufferSize, int maxSections) {
this.sectionMetaBuffer = new GlBuffer(((long) maxSections) * SECTION_METADATA_SIZE, 0);
this.sectionMetaBuffer = new GlBuffer(((long) maxSections) * SECTION_METADATA_SIZE);
this.geometryBuffer = new BufferArena(geometryBufferSize, 8);
this.pos2id.defaultReturnValue(-1);
}

View File

@@ -50,10 +50,10 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer {
public Gl46FarWorldRenderer(int geometryBuffer, int maxSections) {
super(geometryBuffer, maxSections);
glCommandBuffer = new GlBuffer(maxSections*5L*4, 0);
glVisibilityBuffer = new GlBuffer(maxSections*4L, 0);
glClearNamedBufferData(glCommandBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
glClearNamedBufferData(glVisibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
this.glCommandBuffer = new GlBuffer(maxSections*5L*4);
this.glVisibilityBuffer = new GlBuffer(maxSections*4L);
glClearNamedBufferData(this.glCommandBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
glClearNamedBufferData(this.glVisibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
setupVao();
}
@@ -67,9 +67,8 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.glCommandBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.geometry.metaId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, this.glVisibilityBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, this.stateDataBuffer.id);//State LUT
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.biomeDataBuffer.id);//Biome LUT
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, this.lightDataBuffer.id);//Lighting LUT
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, this.models.getBufferId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.lightDataBuffer.id);//Lighting LUT
glBindVertexArray(0);
}

View File

@@ -1,5 +0,0 @@
package me.cortex.zenith.client.core.rendering;
//Manages the storage and updating of model states, textures and colours
public class ModelManager {
}

View File

@@ -1,55 +0,0 @@
package me.cortex.zenith.client.core.rendering;
import me.cortex.zenith.client.core.gl.shader.Shader;
import me.cortex.zenith.client.core.gl.shader.ShaderType;
import me.cortex.zenith.client.core.rendering.util.UploadStream;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.util.math.MatrixStack;
import static org.lwjgl.opengl.ARBMultiDrawIndirect.glMultiDrawElementsIndirect;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.NVMeshShader.glDrawMeshTasksNV;
//TODO: make this a 2 phase culling system
// first phase renders the terrain, in the terrain task shader it also checks if the section was not visible in the frustum but now is
// and then renders it and marks it as being in the frustum
public class NvFarWorldRenderer extends AbstractFarWorldRenderer {
private final Shader primaryTerrainRaster = Shader.make()
.add(ShaderType.TASK, "voxelmon:lod/nvmesh/primary.task")
.add(ShaderType.MESH, "voxelmon:lod/nvmesh/primary.mesh")
.add(ShaderType.FRAGMENT, "voxelmon:lod/nvmesh/primary.frag")
.compile();
public NvFarWorldRenderer(int geometrySize, int maxSections) {
super(geometrySize, maxSections);
}
@Override
protected void setupVao() {
}
@Override
public void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz) {
if (this.geometry.getSectionCount() == 0) {
return;
}
RenderLayer.getCutoutMipped().startDrawing();
UploadStream.INSTANCE.commit();
glBindVertexArray(this.vao);
this.primaryTerrainRaster.bind();
glDrawMeshTasksNV(0, this.geometry.getSectionCount());
glBindVertexArray(0);
RenderLayer.getCutoutMipped().endDrawing();
}
@Override
public void shutdown() {
super.shutdown();
}
}

View File

@@ -14,7 +14,7 @@ public class SharedIndexBuffer {
private final GlBuffer indexBuffer;
public SharedIndexBuffer() {
this.indexBuffer = new GlBuffer((1<<16)*6*2 + 6*2*3, 0);
this.indexBuffer = new GlBuffer((1<<16)*6*2 + 6*2*3);
var quadIndexBuff = IndexUtil.generateQuadIndicesShort(16380);
var cubeBuff = generateCubeIndexBuffer();

View File

@@ -18,7 +18,7 @@ public class BufferArena {
}
this.size = capacity;
this.elementSize = elementSize;
this.buffer = new GlBuffer(capacity, 0);
this.buffer = new GlBuffer(capacity);
this.allocationMap.setLimit(capacity/elementSize);
}

View File

@@ -7,7 +7,7 @@ import net.minecraft.util.math.Box;
import org.joml.Matrix4f;
public class DebugUtil {
private static Matrix4f positionMatrix = new Matrix4f().identity();
public static Matrix4f positionMatrix = new Matrix4f().identity();
public static void setPositionMatrix(MatrixStack stack) {
positionMatrix = new Matrix4f(stack.peek().getPositionMatrix());
}

View File

@@ -11,16 +11,10 @@ layout(binding = 0, std140) uniform SceneUniform {
uint frameId;
};
struct State {
uint biomeTintMsk;
struct BlockModel {
uint faceColours[6];
};
struct Biome {
uint foliage;
uint water;
};
struct SectionMeta {
uvec4 header;
uvec4 drawdata;
@@ -57,15 +51,11 @@ layout(binding = 4, std430) VISIBILITY_ACCESS restrict buffer VisibilityBuffer {
uint visibilityData[];
};
layout(binding = 5, std430) readonly restrict buffer StateBuffer {
State stateData[];
layout(binding = 5, std430) readonly restrict buffer ModelBuffer {
BlockModel modelData[];
};
layout(binding = 6, std430) readonly restrict buffer BiomeBuffer {
Biome biomeData[];
};
layout(binding = 7, std430) readonly restrict buffer LightingBuffer {
layout(binding = 6, std430) readonly restrict buffer LightingBuffer {
uint lightData[];
};

View File

@@ -63,20 +63,11 @@ void main() {
uint stateId = extractStateId(quad);
uint biomeId = extractBiomeId(quad);
State stateInfo = stateData[stateId];
BlockModel stateInfo = modelData[stateId];
colour = uint2vec4RGBA(stateInfo.faceColours[face]);
colour *= getLighting(extractLightId(quad));
if (((stateInfo.biomeTintMsk>>face)&1) == 1) {
vec4 biomeColour = uint2vec4RGBA(biomeData[biomeId].foliage);
colour *= biomeColour;
}
//Apply water tint
if (((stateInfo.biomeTintMsk>>6)&1) == 1) {
colour *= vec4(0.247, 0.463, 0.894, 1);
}
//Apply face tint
if (face == 0) {
colour.xyz *= vec3(0.75, 0.75, 0.75);