Skip to content

Commit

Permalink
change: Use JOML matrix and frustum types in chunk rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
jellysquid3 committed Sep 2, 2021
1 parent e0c5399 commit f7d3a99
Show file tree
Hide file tree
Showing 17 changed files with 109 additions and 201 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ dependencies {
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"

implementation 'org.joml:joml:1.10.2'
include 'org.joml:joml:1.10.2'

// Fabric API
modIncludeImplementation(fabricApi.module("fabric-api-base", project.fabric_version))
modIncludeImplementation(fabricApi.module("fabric-rendering-fluids-v1", project.fabric_version))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package me.jellysquid.mods.sodium.client.gl.shader.uniform;

import net.minecraft.util.math.Matrix4f;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL30C;
import org.lwjgl.system.MemoryStack;

Expand All @@ -15,7 +15,7 @@ public GlUniformMatrix4f(int index) {
public void set(Matrix4f value) {
try (MemoryStack stack = MemoryStack.stackPush()) {
FloatBuffer buf = stack.callocFloat(16);
value.writeColumnMajor(buf);
value.get(buf);

GL30C.glUniformMatrix4fv(this.index, false, buf);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import me.jellysquid.mods.sodium.client.SodiumClientMod;
import me.jellysquid.mods.sodium.client.gl.device.CommandList;
import me.jellysquid.mods.sodium.client.gl.device.RenderDevice;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices;
import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager;
import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData;
import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass;
import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager;
import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared;
import me.jellysquid.mods.sodium.client.util.NativeBuffer;
import me.jellysquid.mods.sodium.client.util.math.FrustumExtended;
import me.jellysquid.mods.sodium.client.world.ChunkStatusListener;
import me.jellysquid.mods.sodium.client.world.ClientChunkManagerExtended;
import me.jellysquid.mods.sodium.client.world.WorldRendererExtended;
Expand All @@ -30,6 +30,7 @@
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.profiler.Profiler;
import org.joml.FrustumIntersection;

import java.util.*;

Expand All @@ -49,9 +50,8 @@ public class SodiumWorldRenderer implements ChunkStatusListener {

private final Set<BlockEntity> globalBlockEntities = new ObjectOpenHashSet<>();

private Frustum frustum;
private FrustumIntersection cullingFrustum;
private RenderSectionManager renderSectionManager;
private BlockRenderPassManager renderPassManager;

/**
* @return The SodiumWorldRenderer based on the current dimension
Expand Down Expand Up @@ -152,11 +152,9 @@ public boolean isTerrainRenderComplete() {
/**
* Called prior to any chunk rendering in order to update necessary state.
*/
public void updateChunks(Camera camera, Frustum frustum, boolean hasForcedFrustum, int frame, boolean spectator) {
public void updateChunks(Camera camera, int frame, boolean spectator) {
NativeBuffer.reclaim(false);

this.frustum = frustum;

this.useEntityCulling = SodiumClientMod.options().advanced.useEntityCulling;

if (this.client.options.viewDistance != this.renderDistance) {
Expand Down Expand Up @@ -193,10 +191,10 @@ public void updateChunks(Camera camera, Frustum frustum, boolean hasForcedFrustu

this.renderSectionManager.updateChunks();

if (!hasForcedFrustum && this.renderSectionManager.isGraphDirty()) {
if (this.renderSectionManager.isGraphDirty()) {
profiler.swap("chunk_graph_rebuild");

this.renderSectionManager.update(camera, (FrustumExtended) frustum, frame, spectator);
this.renderSectionManager.update(camera, this.cullingFrustum, frame, spectator);
}

profiler.swap("visible_chunk_tick");
Expand All @@ -223,7 +221,7 @@ public void drawChunkLayer(RenderLayer renderLayer, MatrixStack matrixStack, dou
public void drawChunkLayer(BlockRenderPass pass, MatrixStack matrixStack, double x, double y, double z) {
pass.startDrawing();

this.renderSectionManager.renderLayer(matrixStack, pass, x, y, z);
this.renderSectionManager.renderLayer(ChunkRenderMatrices.from(matrixStack), pass, x, y, z);

pass.endDrawing();
}
Expand All @@ -246,9 +244,9 @@ private void initRenderer(CommandList commandList) {

this.renderDistance = this.client.options.viewDistance;

this.renderPassManager = BlockRenderPassManager.createDefaultMappings();
BlockRenderPassManager renderPassManager = BlockRenderPassManager.createDefaultMappings();

this.renderSectionManager = new RenderSectionManager(this, this.renderPassManager, this.world, this.renderDistance, commandList);
this.renderSectionManager = new RenderSectionManager(this, renderPassManager, this.world, this.renderDistance, commandList);
this.renderSectionManager.loadChunks();
}

Expand Down Expand Up @@ -363,13 +361,6 @@ public boolean isBoxVisible(double x1, double y1, double z1, double x2, double y
return false;
}

/**
* @return The frustum of the current player's camera used to cull chunks
*/
public Frustum getFrustum() {
return this.frustum;
}

public String getChunksDebugString() {
// C: visible/total
// TODO: add dirty and queued counts
Expand Down Expand Up @@ -406,4 +397,8 @@ public void scheduleRebuildForChunk(int x, int y, int z, boolean important) {
public Collection<String> getMemoryDebugStrings() {
return this.renderSectionManager.getDebugStrings();
}

public void setCullingFrustum(FrustumIntersection frustum) {
this.cullingFrustum = frustum;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package me.jellysquid.mods.sodium.client.render.chunk;

import com.mojang.blaze3d.systems.RenderSystem;
import me.jellysquid.mods.sodium.client.util.math.JomlHelper;
import net.minecraft.client.util.math.MatrixStack;
import org.joml.Matrix4f;

public record ChunkRenderMatrices(Matrix4f projection, Matrix4f modelView) {
public static ChunkRenderMatrices from(MatrixStack stack) {
MatrixStack.Entry entry = stack.peek();
return new ChunkRenderMatrices(JomlHelper.copy(RenderSystem.getProjectionMatrix()), JomlHelper.copy(entry.getModel()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import me.jellysquid.mods.sodium.client.gl.device.CommandList;
import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType;
import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass;
import net.minecraft.client.util.math.MatrixStack;

/**
* The chunk render backend takes care of managing the graphics resource state of chunk render containers. This includes
Expand All @@ -12,13 +11,13 @@
public interface ChunkRenderer {
/**
* Renders the given chunk render list to the active framebuffer.
* @param matrixStack The current matrix stack to be used for rendering
* @param matrices The camera matrices to use for rendering
* @param commandList The command list which OpenGL commands should be serialized to
* @param renders An iterator over the list of chunks to be rendered
* @param pass The block render pass to execute
* @param camera The camera context containing chunk offsets for the current render
*/
void render(MatrixStack matrixStack, CommandList commandList, ChunkRenderList renders, BlockRenderPass pass, ChunkCameraContext camera);
void render(ChunkRenderMatrices matrices, CommandList commandList, ChunkRenderList renders, BlockRenderPass pass, ChunkCameraContext camera);

/**
* Deletes this render backend and any resources attached to it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType;
import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation;
import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding;
import me.jellysquid.mods.sodium.client.gl.texture.GlTexture;
import me.jellysquid.mods.sodium.client.gl.texture.TextureData;
import me.jellysquid.mods.sodium.client.gl.util.ElementRange;
import me.jellysquid.mods.sodium.client.gl.util.MultiDrawBatch;
import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing;
Expand All @@ -25,9 +23,8 @@
import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion;
import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints;
import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderInterface;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11C;
import me.jellysquid.mods.sodium.client.util.math.JomlHelper;
import org.joml.Matrix4f;
import org.lwjgl.system.MemoryStack;

import java.nio.ByteBuffer;
Expand Down Expand Up @@ -92,13 +89,13 @@ private static ByteBuffer createChunkInfoBuffer(MemoryStack stack) {
}

@Override
public void render(MatrixStack matrixStack, CommandList commandList,
public void render(ChunkRenderMatrices matrices, CommandList commandList,
ChunkRenderList list, BlockRenderPass pass,
ChunkCameraContext camera) {
super.begin(pass);

ChunkShaderInterface shader = this.activeProgram.getInterface();
shader.setProjectionMatrix(RenderSystem.getProjectionMatrix());
shader.setProjectionMatrix(matrices.projection());
shader.setDrawUniforms(this.chunkInfoBuffer);

for (Map.Entry<RenderRegion, List<RenderSection>> entry : sortedRegions(list, pass.isTranslucent())) {
Expand All @@ -109,7 +106,7 @@ public void render(MatrixStack matrixStack, CommandList commandList,
continue;
}

this.setModelMatrixUniforms(shader, matrixStack, region, camera);
this.setModelMatrixUniforms(shader, matrices, region, camera);

GlTessellation tessellation = this.createTessellationForRegion(commandList, region.getArenas(), pass);
executeDrawBatches(commandList, tessellation);
Expand Down Expand Up @@ -202,15 +199,16 @@ private void executeDrawBatches(CommandList commandList, GlTessellation tessella
}
}

private void setModelMatrixUniforms(ChunkShaderInterface shader, MatrixStack matrixStack, RenderRegion region, ChunkCameraContext camera) {
private final Matrix4f cachedModelViewMatrix = new Matrix4f();

private void setModelMatrixUniforms(ChunkShaderInterface shader, ChunkRenderMatrices matrices, RenderRegion region, ChunkCameraContext camera) {
float x = getCameraTranslation(region.getOriginX(), camera.blockX, camera.deltaX);
float y = getCameraTranslation(region.getOriginY(), camera.blockY, camera.deltaY);
float z = getCameraTranslation(region.getOriginZ(), camera.blockZ, camera.deltaZ);

Matrix4f matrix = matrixStack.peek()
.getModel()
.copy();
matrix.multiplyByTranslation(x, y, z);
Matrix4f matrix = this.cachedModelViewMatrix;
matrix.set(matrices.modelView());
matrix.translate(x, y, z);

shader.setModelViewMatrix(matrix);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderEmptyBuildTask;
import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderRebuildTask;
import me.jellysquid.mods.sodium.client.util.MathUtil;
import me.jellysquid.mods.sodium.client.util.math.FrustumExtended;
import me.jellysquid.mods.sodium.client.world.ChunkStatusListener;
import me.jellysquid.mods.sodium.client.world.ClientChunkManagerExtended;
import me.jellysquid.mods.sodium.client.world.WorldSlice;
Expand All @@ -38,11 +37,11 @@
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.*;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import org.joml.FrustumIntersection;

import java.util.*;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -101,7 +100,7 @@ public class RenderSectionManager implements ChunkStatusListener {

private double fogRenderCutoff;

private FrustumExtended frustum;
private FrustumIntersection frustum;

private int currentFrame = 0;
private final double detailFarPlane;
Expand Down Expand Up @@ -145,7 +144,7 @@ public void loadChunks() {
}
}

public void update(Camera camera, FrustumExtended frustum, int frame, boolean spectator) {
public void update(Camera camera, FrustumIntersection frustum, int frame, boolean spectator) {
this.resetLists();

this.regions.updateVisibility(frustum);
Expand Down Expand Up @@ -175,7 +174,7 @@ private void setup(Camera camera) {
}
}

private void iterateChunks(Camera camera, FrustumExtended frustum, int frame, boolean spectator) {
private void iterateChunks(Camera camera, FrustumIntersection frustum, int frame, boolean spectator) {
this.initSearch(camera, frustum, frame, spectator);

ChunkGraphIterationQueue queue = this.iterationQueue;
Expand Down Expand Up @@ -309,11 +308,11 @@ private boolean unloadSection(int x, int y, int z) {
return true;
}

public void renderLayer(MatrixStack matrixStack, BlockRenderPass pass, double x, double y, double z) {
public void renderLayer(ChunkRenderMatrices matrices, BlockRenderPass pass, double x, double y, double z) {
RenderDevice device = RenderDevice.INSTANCE;
CommandList commandList = device.createCommandList();

this.chunkRenderer.render(matrixStack, commandList, this.chunkRenderList, pass, new ChunkCameraContext(x, y, z));
this.chunkRenderer.render(matrices, commandList, this.chunkRenderList, pass, new ChunkCameraContext(x, y, z));

commandList.flush();
}
Expand Down Expand Up @@ -497,7 +496,7 @@ private boolean isCulled(ChunkGraphInfo node, Direction from, Direction to) {
return this.useOcclusionCulling && from != null && !node.isVisibleThrough(from, to);
}

private void initSearch(Camera camera, FrustumExtended frustum, int frame, boolean spectator) {
private void initSearch(Camera camera, FrustumIntersection frustum, int frame, boolean spectator) {
this.currentFrame = frame;
this.frustum = frustum;
this.useOcclusionCulling = MinecraftClient.getInstance().chunkCullingEnabled;
Expand Down Expand Up @@ -569,9 +568,9 @@ private void bfsEnqueue(RenderSection parent, RenderSection render, Direction fl

RenderRegionVisibility parentVisibility = parent.getRegion().getVisibility();

if (parentVisibility == RenderRegionVisibility.CULLED) {
if (parentVisibility == RenderRegionVisibility.OUTSIDE) {
return;
} else if (parentVisibility == RenderRegionVisibility.VISIBLE && info.isCulledByFrustum(this.frustum)) {
} else if (parentVisibility == RenderRegionVisibility.INTERSECT && info.isCulledByFrustum(this.frustum)) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import me.jellysquid.mods.sodium.client.render.chunk.RenderSection;
import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData;
import me.jellysquid.mods.sodium.client.util.math.FrustumExtended;
import me.jellysquid.mods.sodium.common.util.DirectionUtil;
import net.minecraft.client.render.chunk.ChunkOcclusionData;
import net.minecraft.util.math.Direction;
import org.joml.FrustumIntersection;

public class ChunkGraphInfo {
private static final long DEFAULT_VISIBILITY_DATA = calculateVisibilityData(ChunkRenderData.EMPTY.getOcclusionData());
Expand Down Expand Up @@ -68,12 +68,12 @@ public void resetCullingState() {
this.cullingState = 0;
}

public boolean isCulledByFrustum(FrustumExtended frustum) {
public boolean isCulledByFrustum(FrustumIntersection frustum) {
float x = this.getOriginX();
float y = this.getOriginY();
float z = this.getOriginZ();

return !frustum.fastAabbTest(x, y, z, x + 16.0f, y + 16.0f, z + 16.0f);
return !frustum.testAab(x, y, z, x + 16.0f, y + 16.0f, z + 16.0f);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
import me.jellysquid.mods.sodium.client.gl.arena.staging.StagingBuffer;
import me.jellysquid.mods.sodium.client.gl.device.CommandList;
import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderer;
import me.jellysquid.mods.sodium.client.render.chunk.RenderSection;
import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkModelVertexFormats;
import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass;
import me.jellysquid.mods.sodium.client.util.MathUtil;
import me.jellysquid.mods.sodium.client.util.math.FrustumExtended;
import net.minecraft.util.math.ChunkSectionPos;
import org.apache.commons.lang3.Validate;
import org.joml.FrustumIntersection;

import java.util.EnumMap;
import java.util.Map;
Expand Down Expand Up @@ -122,16 +121,22 @@ public int getChunkCount() {
return this.chunks.size();
}

public void updateVisibility(FrustumExtended frustum) {
public void updateVisibility(FrustumIntersection frustum) {
int x = this.getOriginX();
int y = this.getOriginY();
int z = this.getOriginZ();

// HACK: Regions need to be slightly larger than their real volume
// Otherwise, the first node in the iteration graph might be incorrectly culled when the camera
// is at the extreme end of a region
this.visibility = frustum.aabbTest(x - REGION_EXCESS, y - REGION_EXCESS, z - REGION_EXCESS,
int visflag = frustum.intersectAab(x - REGION_EXCESS, y - REGION_EXCESS, z - REGION_EXCESS,
x + (REGION_WIDTH << 4) + REGION_EXCESS, y + (REGION_HEIGHT << 4) + REGION_EXCESS, z + (REGION_LENGTH << 4) + REGION_EXCESS);

this.visibility = switch (visflag) {
case FrustumIntersection.INSIDE -> RenderRegionVisibility.INSIDE;
case FrustumIntersection.INTERSECT -> RenderRegionVisibility.INTERSECT;
default -> RenderRegionVisibility.OUTSIDE;
};
}

public RenderRegionVisibility getVisibility() {
Expand Down
Loading

0 comments on commit f7d3a99

Please sign in to comment.