mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-11 22:45:38 -04:00
Fix Indigo AO calculation (#2344)
* Fix AO calculation - Ensure calcFastVanilla and computeFace have parity with vanilla - Ensure BlockStates are not queried more than once for the same position - Replace deprecated FabricLoader#getConfigDirectory call with FabricLoader#getConfigDir * Revert opaque sides fix * More AO fixes and optimizations
This commit is contained in:
parent
2d1b3c535f
commit
41a02c8a4e
7 changed files with 121 additions and 82 deletions
fabric-renderer-indigo/src/main/java/net/fabricmc/fabric/impl/client/indigo
|
@ -23,8 +23,8 @@ import java.io.IOException;
|
|||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
||||
|
@ -89,7 +89,7 @@ public class Indigo implements ClientModInitializer {
|
|||
}
|
||||
|
||||
static {
|
||||
File configDir = new File(FabricLoader.getInstance().getConfigDirectory(), "fabric");
|
||||
File configDir = FabricLoader.getInstance().getConfigDir().resolve("fabric").toFile();
|
||||
|
||||
if (!configDir.exists()) {
|
||||
if (!configDir.mkdir()) {
|
||||
|
|
|
@ -28,16 +28,15 @@ import static net.minecraft.util.math.Direction.UP;
|
|||
import static net.minecraft.util.math.Direction.WEST;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.util.math.Vec3f;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3f;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
|
@ -55,10 +54,15 @@ import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
|||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class AoCalculator {
|
||||
@FunctionalInterface
|
||||
public interface BrightnessFunc {
|
||||
int apply(BlockPos pos, BlockState state);
|
||||
}
|
||||
|
||||
/** Used to receive a method reference in constructor for ao value lookup. */
|
||||
@FunctionalInterface
|
||||
public interface AoFunc {
|
||||
float apply(BlockPos pos);
|
||||
float apply(BlockPos pos, BlockState state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,10 +85,10 @@ public class AoCalculator {
|
|||
private final BlockPos.Mutable lightPos = new BlockPos.Mutable();
|
||||
private final BlockPos.Mutable searchPos = new BlockPos.Mutable();
|
||||
private final BlockRenderInfo blockInfo;
|
||||
private final ToIntFunction<BlockPos> brightnessFunc;
|
||||
private final BrightnessFunc brightnessFunc;
|
||||
private final AoFunc aoFunc;
|
||||
|
||||
/** caches results of {@link #computeFace(Direction, boolean)} for the current block. */
|
||||
/** caches results of {@link #computeFace(Direction, boolean, boolean)} for the current block. */
|
||||
private final AoFaceData[] faceData = new AoFaceData[12];
|
||||
|
||||
/** indicates which elements of {@link #faceData} have been computed for the current block. */
|
||||
|
@ -97,7 +101,7 @@ public class AoCalculator {
|
|||
public final float[] ao = new float[4];
|
||||
public final int[] light = new int[4];
|
||||
|
||||
public AoCalculator(BlockRenderInfo blockInfo, ToIntFunction<BlockPos> brightnessFunc, AoFunc aoFunc) {
|
||||
public AoCalculator(BlockRenderInfo blockInfo, BrightnessFunc brightnessFunc, AoFunc aoFunc) {
|
||||
this.blockInfo = blockInfo;
|
||||
this.brightnessFunc = brightnessFunc;
|
||||
this.aoFunc = aoFunc;
|
||||
|
@ -198,7 +202,7 @@ public class AoCalculator {
|
|||
int flags = quad.geometryFlags();
|
||||
|
||||
// force to block face if shape is full cube - matches vanilla logic
|
||||
if ((flags & LIGHT_FACE_FLAG) == 0 && (flags & AXIS_ALIGNED_FLAG) == AXIS_ALIGNED_FLAG && Block.isShapeFullCube(blockInfo.blockState.getCollisionShape(blockInfo.blockView, blockInfo.blockPos))) {
|
||||
if ((flags & LIGHT_FACE_FLAG) == 0 && (flags & AXIS_ALIGNED_FLAG) != 0 && blockInfo.blockState.isFullCube(blockInfo.blockView, blockInfo.blockPos)) {
|
||||
flags |= LIGHT_FACE_FLAG;
|
||||
}
|
||||
|
||||
|
@ -360,7 +364,7 @@ public class AoCalculator {
|
|||
|
||||
/**
|
||||
* Computes smoothed brightness and Ao shading for four corners of a block face.
|
||||
* Outer block face is what you normally see and what you get get when second
|
||||
* Outer block face is what you normally see and what you get when the second
|
||||
* parameter is true. Inner is light *within* the block and usually darker.
|
||||
* It is blended with the outer face for inset surfaces, but is also used directly
|
||||
* in vanilla logic for some blocks that aren't full opaque cubes.
|
||||
|
@ -376,45 +380,76 @@ public class AoCalculator {
|
|||
|
||||
final BlockRenderView world = blockInfo.blockView;
|
||||
final BlockPos pos = blockInfo.blockPos;
|
||||
final BlockState blockState = blockInfo.blockState;
|
||||
final BlockPos.Mutable lightPos = this.lightPos;
|
||||
final BlockPos.Mutable searchPos = this.searchPos;
|
||||
BlockState searchState;
|
||||
|
||||
if (isOnBlockFace) {
|
||||
lightPos.set(pos, lightFace);
|
||||
} else {
|
||||
lightPos.set(pos);
|
||||
}
|
||||
|
||||
lightPos.set(isOnBlockFace ? pos.offset(lightFace) : pos);
|
||||
AoFace aoFace = AoFace.get(lightFace);
|
||||
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[0]);
|
||||
final int light0 = brightnessFunc.applyAsInt(searchPos);
|
||||
final float ao0 = aoFunc.apply(searchPos);
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[1]);
|
||||
final int light1 = brightnessFunc.applyAsInt(searchPos);
|
||||
final float ao1 = aoFunc.apply(searchPos);
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[2]);
|
||||
final int light2 = brightnessFunc.applyAsInt(searchPos);
|
||||
final float ao2 = aoFunc.apply(searchPos);
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[3]);
|
||||
final int light3 = brightnessFunc.applyAsInt(searchPos);
|
||||
final float ao3 = aoFunc.apply(searchPos);
|
||||
// Vanilla was further offsetting the positions for opaque block checks in the
|
||||
// direction of the light face, but it was actually mis-sampling and causing
|
||||
// visible artifacts in certain situations
|
||||
|
||||
// vanilla was further offsetting these in the direction of the light face
|
||||
// but it was actually mis-sampling and causing visible artifacts in certain situation
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[0]); //.setOffset(lightFace);
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) searchPos.move(lightFace);
|
||||
final boolean isClear0 = world.getBlockState(searchPos).getOpacity(world, searchPos) == 0;
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[1]); //.setOffset(lightFace);
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) searchPos.move(lightFace);
|
||||
final boolean isClear1 = world.getBlockState(searchPos).getOpacity(world, searchPos) == 0;
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[2]); //.setOffset(lightFace);
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) searchPos.move(lightFace);
|
||||
final boolean isClear2 = world.getBlockState(searchPos).getOpacity(world, searchPos) == 0;
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[3]); //.setOffset(lightFace);
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) searchPos.move(lightFace);
|
||||
final boolean isClear3 = world.getBlockState(searchPos).getOpacity(world, searchPos) == 0;
|
||||
searchPos.set(lightPos, aoFace.neighbors[0]);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
final int light0 = brightnessFunc.apply(searchPos, searchState);
|
||||
final float ao0 = aoFunc.apply(searchPos, searchState);
|
||||
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) {
|
||||
searchPos.move(lightFace);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
}
|
||||
|
||||
final boolean isClear0 = !searchState.shouldBlockVision(world, searchPos) || searchState.getOpacity(world, searchPos) == 0;
|
||||
|
||||
searchPos.set(lightPos, aoFace.neighbors[1]);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
final int light1 = brightnessFunc.apply(searchPos, searchState);
|
||||
final float ao1 = aoFunc.apply(searchPos, searchState);
|
||||
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) {
|
||||
searchPos.move(lightFace);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
}
|
||||
|
||||
final boolean isClear1 = !searchState.shouldBlockVision(world, searchPos) || searchState.getOpacity(world, searchPos) == 0;
|
||||
|
||||
searchPos.set(lightPos, aoFace.neighbors[2]);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
final int light2 = brightnessFunc.apply(searchPos, searchState);
|
||||
final float ao2 = aoFunc.apply(searchPos, searchState);
|
||||
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) {
|
||||
searchPos.move(lightFace);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
}
|
||||
|
||||
final boolean isClear2 = !searchState.shouldBlockVision(world, searchPos) || searchState.getOpacity(world, searchPos) == 0;
|
||||
|
||||
searchPos.set(lightPos, aoFace.neighbors[3]);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
final int light3 = brightnessFunc.apply(searchPos, searchState);
|
||||
final float ao3 = aoFunc.apply(searchPos, searchState);
|
||||
|
||||
if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) {
|
||||
searchPos.move(lightFace);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
}
|
||||
|
||||
final boolean isClear3 = !searchState.shouldBlockVision(world, searchPos) || searchState.getOpacity(world, searchPos) == 0;
|
||||
|
||||
// c = corner - values at corners of face
|
||||
int cLight0, cLight1, cLight2, cLight3;
|
||||
float cAo0, cAo1, cAo2, cAo3;
|
||||
|
||||
// If neighbors on both side of the corner are opaque, then apparently we use the light/shade
|
||||
// If neighbors on both sides of the corner are opaque, then apparently we use the light/shade
|
||||
// from one of the sides adjacent to the corner. If either neighbor is clear (no light subtraction)
|
||||
// then we use values from the outwardly diagonal corner. (outwardly = position is one more away from light face)
|
||||
if (!isClear2 && !isClear0) {
|
||||
|
@ -422,8 +457,9 @@ public class AoCalculator {
|
|||
cLight0 = light0;
|
||||
} else {
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[0]).move(aoFace.neighbors[2]);
|
||||
cAo0 = aoFunc.apply(searchPos);
|
||||
cLight0 = brightnessFunc.applyAsInt(searchPos);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
cAo0 = aoFunc.apply(searchPos, searchState);
|
||||
cLight0 = brightnessFunc.apply(searchPos, searchState);
|
||||
}
|
||||
|
||||
if (!isClear3 && !isClear0) {
|
||||
|
@ -431,8 +467,9 @@ public class AoCalculator {
|
|||
cLight1 = light0;
|
||||
} else {
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[0]).move(aoFace.neighbors[3]);
|
||||
cAo1 = aoFunc.apply(searchPos);
|
||||
cLight1 = brightnessFunc.applyAsInt(searchPos);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
cAo1 = aoFunc.apply(searchPos, searchState);
|
||||
cLight1 = brightnessFunc.apply(searchPos, searchState);
|
||||
}
|
||||
|
||||
if (!isClear2 && !isClear1) {
|
||||
|
@ -440,8 +477,9 @@ public class AoCalculator {
|
|||
cLight2 = light1;
|
||||
} else {
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[1]).move(aoFace.neighbors[2]);
|
||||
cAo2 = aoFunc.apply(searchPos);
|
||||
cLight2 = brightnessFunc.applyAsInt(searchPos);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
cAo2 = aoFunc.apply(searchPos, searchState);
|
||||
cLight2 = brightnessFunc.apply(searchPos, searchState);
|
||||
}
|
||||
|
||||
if (!isClear3 && !isClear1) {
|
||||
|
@ -449,22 +487,24 @@ public class AoCalculator {
|
|||
cLight3 = light1;
|
||||
} else {
|
||||
searchPos.set(lightPos).move(aoFace.neighbors[1]).move(aoFace.neighbors[3]);
|
||||
cAo3 = aoFunc.apply(searchPos);
|
||||
cLight3 = brightnessFunc.applyAsInt(searchPos);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
cAo3 = aoFunc.apply(searchPos, searchState);
|
||||
cLight3 = brightnessFunc.apply(searchPos, searchState);
|
||||
}
|
||||
|
||||
// If on block face or neighbor isn't occluding, "center" will be neighbor brightness
|
||||
// Doesn't use light pos because logic not based solely on this block's geometry
|
||||
int lightCenter;
|
||||
searchPos.set(pos).move(lightFace);
|
||||
searchPos.set(pos, lightFace);
|
||||
searchState = world.getBlockState(searchPos);
|
||||
|
||||
if (isOnBlockFace || !world.getBlockState(searchPos).isOpaqueFullCube(world, searchPos)) {
|
||||
lightCenter = brightnessFunc.applyAsInt(searchPos);
|
||||
if (isOnBlockFace || !searchState.isOpaqueFullCube(world, searchPos)) {
|
||||
lightCenter = brightnessFunc.apply(searchPos, searchState);
|
||||
} else {
|
||||
lightCenter = brightnessFunc.applyAsInt(pos);
|
||||
lightCenter = brightnessFunc.apply(pos, blockState);
|
||||
}
|
||||
|
||||
float aoCenter = aoFunc.apply(isOnBlockFace ? lightPos : pos);
|
||||
float aoCenter = aoFunc.apply(lightPos, world.getBlockState(lightPos));
|
||||
float worldBrightness = world.getBrightness(lightFace, shade);
|
||||
|
||||
result.a0 = ((ao3 + ao0 + cAo1 + aoCenter) * 0.25F) * worldBrightness;
|
||||
|
@ -500,12 +540,12 @@ public class AoCalculator {
|
|||
if (b == 0) b = d;
|
||||
if (c == 0) c = d;
|
||||
// bitwise divide by 4, clamp to expected (positive) range
|
||||
return a + b + c + d >> 2 & 16711935;
|
||||
return a + b + c + d >> 2 & 0xFF00FF;
|
||||
}
|
||||
|
||||
private static int meanInnerBrightness(int a, int b, int c, int d) {
|
||||
// bitwise divide by 4, clamp to expected (positive) range
|
||||
return a + b + c + d >> 2 & 16711935;
|
||||
return a + b + c + d >> 2 & 0xFF00FF;
|
||||
}
|
||||
|
||||
private static int nonZeroMin(int a, int b) {
|
||||
|
|
|
@ -28,16 +28,15 @@ import net.fabricmc.fabric.impl.client.indigo.Indigo;
|
|||
*/
|
||||
@FunctionalInterface
|
||||
public interface AoLuminanceFix {
|
||||
float apply(BlockView view, BlockPos pos);
|
||||
float apply(BlockView view, BlockPos pos, BlockState state);
|
||||
|
||||
AoLuminanceFix INSTANCE = Indigo.FIX_LUMINOUS_AO_SHADE ? AoLuminanceFix::fixed : AoLuminanceFix::vanilla;
|
||||
|
||||
static float vanilla(BlockView view, BlockPos pos) {
|
||||
return view.getBlockState(pos).getAmbientOcclusionLightLevel(view, pos);
|
||||
static float vanilla(BlockView view, BlockPos pos, BlockState state) {
|
||||
return state.getAmbientOcclusionLightLevel(view, pos);
|
||||
}
|
||||
|
||||
static float fixed(BlockView view, BlockPos pos) {
|
||||
final BlockState state = view.getBlockState(pos);
|
||||
static float fixed(BlockView view, BlockPos pos, BlockState state) {
|
||||
return state.getLuminance() == 0 ? state.getAmbientOcclusionLightLevel(view, pos) : 1f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ package net.fabricmc.fabric.impl.client.indigo.renderer.render;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
|
||||
|
@ -93,25 +92,22 @@ public abstract class AbstractMeshConsumer extends AbstractQuadRenderer implemen
|
|||
return;
|
||||
}
|
||||
|
||||
final RenderMaterialImpl.Value mat = quad.material();
|
||||
|
||||
if (!mat.disableAo(0) && MinecraftClient.isAmbientOcclusionEnabled()) {
|
||||
// needs to happen before offsets are applied
|
||||
aoCalc.compute(quad, false);
|
||||
}
|
||||
|
||||
tessellateQuad(quad, mat, 0);
|
||||
tessellateQuad(quad, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines color index and render layer, then routes to appropriate
|
||||
* tessellate routine based on material properties.
|
||||
*/
|
||||
private void tessellateQuad(MutableQuadViewImpl quad, RenderMaterialImpl.Value mat, int textureIndex) {
|
||||
private void tessellateQuad(MutableQuadViewImpl quad, int textureIndex) {
|
||||
final RenderMaterialImpl.Value mat = quad.material();
|
||||
final int colorIndex = mat.disableColorIndex(textureIndex) ? -1 : quad.colorIndex();
|
||||
final RenderLayer renderLayer = blockInfo.effectiveRenderLayer(mat.blendMode(textureIndex));
|
||||
|
||||
if (blockInfo.defaultAo && !mat.disableAo(textureIndex)) {
|
||||
// needs to happen before offsets are applied
|
||||
aoCalc.compute(quad, false);
|
||||
|
||||
if (mat.emissive(textureIndex)) {
|
||||
tessellateSmoothEmissive(quad, renderLayer, colorIndex);
|
||||
} else {
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.client.indigo.renderer.render;
|
||||
|
||||
import static net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper.AXIS_ALIGNED_FLAG;
|
||||
import static net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper.LIGHT_FACE_FLAG;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.LightmapTextureManager;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
|
@ -177,8 +177,12 @@ public abstract class AbstractQuadRenderer {
|
|||
// for reference.
|
||||
if (quad.cullFace() != null) {
|
||||
mpos.move(quad.cullFace());
|
||||
} else if ((quad.geometryFlags() & LIGHT_FACE_FLAG) != 0 || Block.isShapeFullCube(blockState.getCollisionShape(blockInfo.blockView, pos))) {
|
||||
mpos.move(quad.lightFace());
|
||||
} else {
|
||||
final int flags = quad.geometryFlags();
|
||||
|
||||
if ((flags & LIGHT_FACE_FLAG) != 0 || ((flags & AXIS_ALIGNED_FLAG) != 0 && blockState.isFullCube(blockInfo.blockView, pos))) {
|
||||
mpos.move(quad.lightFace());
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately cannot use brightness cache here unless we implement one specifically for flat lighting. See #329
|
||||
|
|
|
@ -94,17 +94,17 @@ public class BlockRenderContext extends AbstractRenderContext {
|
|||
}
|
||||
};
|
||||
|
||||
private int brightness(BlockPos pos) {
|
||||
private int brightness(BlockPos pos, BlockState state) {
|
||||
if (blockInfo.blockView == null) {
|
||||
return LightmapTextureManager.MAX_LIGHT_COORDINATE;
|
||||
}
|
||||
|
||||
return WorldRenderer.getLightmapCoordinates(blockInfo.blockView, blockInfo.blockView.getBlockState(pos), pos);
|
||||
return WorldRenderer.getLightmapCoordinates(blockInfo.blockView, state, pos);
|
||||
}
|
||||
|
||||
private float aoLevel(BlockPos pos) {
|
||||
private float aoLevel(BlockPos pos, BlockState state) {
|
||||
final BlockRenderView blockView = blockInfo.blockView;
|
||||
return blockView == null ? 1f : AoLuminanceFix.INSTANCE.apply(blockView, pos);
|
||||
return blockView == null ? 1f : AoLuminanceFix.INSTANCE.apply(blockView, pos, state);
|
||||
}
|
||||
|
||||
private VertexConsumer outputBuffer(RenderLayer renderLayer) {
|
||||
|
|
|
@ -119,27 +119,27 @@ public class ChunkRenderInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* Cached values for {@link BlockState#getBlockBrightness(BlockRenderView, BlockPos)}.
|
||||
* Cached values for {@link WorldRenderer#getLightmapCoordinates(BlockRenderView, BlockState, BlockPos)}.
|
||||
* See also the comments for {@link #brightnessCache}.
|
||||
*/
|
||||
int cachedBrightness(BlockPos pos) {
|
||||
int cachedBrightness(BlockPos pos, BlockState state) {
|
||||
long key = pos.asLong();
|
||||
int result = brightnessCache.get(key);
|
||||
|
||||
if (result == Integer.MAX_VALUE) {
|
||||
result = WorldRenderer.getLightmapCoordinates(blockView, blockView.getBlockState(pos), pos);
|
||||
result = WorldRenderer.getLightmapCoordinates(blockView, state, pos);
|
||||
brightnessCache.put(key, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float cachedAoLevel(BlockPos pos) {
|
||||
float cachedAoLevel(BlockPos pos, BlockState state) {
|
||||
long key = pos.asLong();
|
||||
float result = aoLevelCache.get(key);
|
||||
|
||||
if (result == Float.MAX_VALUE) {
|
||||
result = AoLuminanceFix.INSTANCE.apply(blockView, pos);
|
||||
result = AoLuminanceFix.INSTANCE.apply(blockView, pos, state);
|
||||
aoLevelCache.put(key, result);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue