Skip to content

Commit

Permalink
Bring over flat pipeline shading improvements from Indigo
Browse files Browse the repository at this point in the history
  • Loading branch information
Technici4n committed Aug 26, 2023
1 parent 6f4d0b9 commit 2eb8f01
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ public boolean hasVertexNormals() {
return normalFlags() != 0;
}

/** True if all vertex normals have been set. */
public boolean hasAllVertexNormals() {
return (normalFlags() & 0b1111) == 0b1111;
}

protected final int normalIndex(int vertexIndex) {
return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.jellysquid.mods.sodium.client.model.light.flat;

import me.jellysquid.mods.sodium.client.frapi.mesh.QuadViewImpl;
import me.jellysquid.mods.sodium.client.model.light.LightPipeline;
import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess;
import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData;
Expand All @@ -11,6 +12,7 @@
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import org.joml.Vector3f;

import java.util.Arrays;

Expand All @@ -31,14 +33,14 @@ public FlatLightPipeline(LightDataAccess lightCache) {
}

@Override
public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade) {
public void calculate(ModelQuadView modelQuadView, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade) {
int lightmap;

// To match vanilla behavior, use the cull face if it exists/is available
if (cullFace != null) {
lightmap = getOffsetLightmap(pos, cullFace);
} else {
int flags = quad.getFlags();
int flags = modelQuadView.getFlags();
// If the face is aligned, use the light data above it
// To match vanilla behavior, also treat the face as aligned if it is parallel and the block state is a full cube
if ((flags & ModelQuadFlags.IS_ALIGNED) != 0 || ((flags & ModelQuadFlags.IS_PARALLEL) != 0 && unpackFC(this.lightCache.get(pos)))) {
Expand All @@ -49,7 +51,44 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direc
}

Arrays.fill(out.lm, lightmap);
Arrays.fill(out.br, this.lightCache.getWorld().getBrightness(lightFace, shade));

/*
* Compute brightness depending on quad normal. For irregular quads this is essential to achieve decent results.
* This code comes from Indigo, which is licensed under the Apache 2.0 license to FabricMC.
*/
// TODO: this cast is quite ugly, what should we do? Move this to AbstractBlockRenderContext?
if (modelQuadView instanceof QuadViewImpl quad) {
BlockRenderView blockView = this.lightCache.getWorld();

if (quad.hasAllVertexNormals()) {
for (int i = 0; i < 4; i++) {
out.br[i] = normalShade(blockView, quad.normalX(i), quad.normalY(i), quad.normalZ(i), shade);
}
} else {
final float faceShade;

if ((quad.geometryFlags() & ModelQuadFlags.IS_ALIGNED) != 0) {
faceShade = blockView.getBrightness(lightFace, shade);
} else {
Vector3f faceNormal = quad.faceNormal();
faceShade = normalShade(blockView, faceNormal.x, faceNormal.y, faceNormal.z, shade);
}

if (quad.hasVertexNormals()) {
for (int i = 0; i < 4; i++) {
if (quad.hasNormal(i)) {
out.br[i] = normalShade(blockView, quad.normalX(i), quad.normalY(i), quad.normalZ(i), shade);
} else {
out.br[i] = faceShade;
}
}
} else {
Arrays.fill(out.br, faceShade);
}
}
} else {
Arrays.fill(out.br, this.lightCache.getWorld().getBrightness(lightFace, shade));
}
}

/**
Expand All @@ -71,4 +110,43 @@ private int getOffsetLightmap(BlockPos pos, Direction face) {
int adjWord = this.lightCache.get(pos, face);
return LightmapTextureManager.pack(Math.max(unpackBL(adjWord), unpackLU(word)), unpackSL(adjWord));
}


/**
* Finds mean of per-face shading factors weighted by normal components.
* Not how light actually works but the vanilla diffuse shading model is a hack to start with
* and this gives reasonable results for non-cubic surfaces in a vanilla-style renderer.
* <p>
* This code comes from Indigo, which is licensed under the Apache 2.0 license to FabricMC.
*/
private float normalShade(BlockRenderView blockView, float normalX, float normalY, float normalZ, boolean hasShade) {
float sum = 0;
float div = 0;

if (normalX > 0) {
sum += normalX * blockView.getBrightness(Direction.EAST, hasShade);
div += normalX;
} else if (normalX < 0) {
sum += -normalX * blockView.getBrightness(Direction.WEST, hasShade);
div -= normalX;
}

if (normalY > 0) {
sum += normalY * blockView.getBrightness(Direction.UP, hasShade);
div += normalY;
} else if (normalY < 0) {
sum += -normalY * blockView.getBrightness(Direction.DOWN, hasShade);
div -= normalY;
}

if (normalZ > 0) {
sum += normalZ * blockView.getBrightness(Direction.SOUTH, hasShade);
div += normalZ;
} else if (normalZ < 0) {
sum += -normalZ * blockView.getBrightness(Direction.NORTH, hasShade);
div -= normalZ;
}

return sum / div;
}
}

0 comments on commit 2eb8f01

Please sign in to comment.