In the right direction

- Use vanilla light directions for diffuse lighting
- Copy mc's glsl code for it, but assume directions are normalized
- Add command/config to toggle use of light directions vs chunk accurate
  diffuse
- Always use shade in getItemMaterial
- Do not reload resource packs when updating light smoothness config,
  we don't need to anymore with lazy compilation
This commit is contained in:
Jozufozu 2024-09-29 11:52:35 -07:00
parent 22b5676e47
commit 40577420d5
13 changed files with 146 additions and 12 deletions

View file

@ -11,4 +11,6 @@ public interface BackendConfig {
* @return The current light smoothness setting.
*/
LightSmoothness lightSmoothness();
boolean useLightDirections();
}

View file

@ -1,15 +1,21 @@
package dev.engine_room.flywheel.backend.engine.uniform;
import org.joml.Vector3f;
import dev.engine_room.flywheel.api.RenderContext;
import dev.engine_room.flywheel.backend.BackendConfig;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
public final class LevelUniforms extends UniformWriter {
private static final int SIZE = 16 * 2 + 4 * 13;
private static final int SIZE = 16 * 4 + 4 * 13;
static final UniformBuffer BUFFER = new UniformBuffer(Uniforms.LEVEL_INDEX, SIZE);
public static final Vector3f LIGHT0_DIRECTION = new Vector3f();
public static final Vector3f LIGHT1_DIRECTION = new Vector3f();
private LevelUniforms() {
}
@ -24,6 +30,9 @@ public final class LevelUniforms extends UniformWriter {
ptr = writeVec4(ptr, (float) skyColor.x, (float) skyColor.y, (float) skyColor.z, 1f);
ptr = writeVec4(ptr, (float) cloudColor.x, (float) cloudColor.y, (float) cloudColor.z, 1f);
ptr = writeVec3(ptr, LIGHT0_DIRECTION);
ptr = writeVec3(ptr, LIGHT1_DIRECTION);
long dayTime = level.getDayTime();
long levelDay = dayTime / 24000L;
float timeOfDay = (float) (dayTime - levelDay * 24000L) / 24000f;
@ -46,6 +55,8 @@ public final class LevelUniforms extends UniformWriter {
ptr = writeInt(ptr, level.effects().constantAmbientLight() ? 1 : 0);
ptr = writeInt(ptr, BackendConfig.INSTANCE.useLightDirections() ? 1 : 0);
// TODO: use defines for custom dimension ids
int dimensionId;
ResourceKey<Level> dimension = level.dimension();

View file

@ -1,6 +1,7 @@
package dev.engine_room.flywheel.backend.engine.uniform;
import org.joml.Matrix4f;
import org.joml.Vector3fc;
import org.lwjgl.system.MemoryUtil;
import dev.engine_room.flywheel.lib.util.ExtraMemoryOps;
@ -37,6 +38,10 @@ class UniformWriter {
return ptr + 16;
}
static long writeVec3(long ptr, Vector3fc vec) {
return writeVec3(ptr, vec.x(), vec.y(), vec.z());
}
static long writeVec4(long ptr, float x, float y, float z, float w) {
MemoryUtil.memPutFloat(ptr, x);
MemoryUtil.memPutFloat(ptr + 4, y);

View file

@ -1,5 +1,7 @@
package dev.engine_room.flywheel.backend.mixin;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -7,6 +9,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.blaze3d.platform.GlStateManager;
import dev.engine_room.flywheel.backend.engine.uniform.LevelUniforms;
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
import dev.engine_room.flywheel.backend.gl.buffer.GlBufferType;
@ -26,4 +29,12 @@ abstract class GlStateManagerMixin {
private static void flywheel$onUseProgram(int program, CallbackInfo ci) {
GlStateTracker._setProgram(program);
}
@Inject(method = "setupLevelDiffuseLighting", at = @At("HEAD"))
private static void flywheel$onSetupLevelDiffuseLighting(Vector3f vector3f, Vector3f vector3f2, Matrix4f matrix4f, CallbackInfo ci) {
// Capture the light directions before they're transformed into screen space
// Basically all usages of assigning light direction go through here so I think this is safe
LevelUniforms.LIGHT0_DIRECTION.set(vector3f);
LevelUniforms.LIGHT1_DIRECTION.set(vector3f2);
}
}

View file

@ -21,10 +21,14 @@ out vec4 _flw_outputColor;
float _flw_diffuseFactor() {
if (flw_material.diffuse) {
if (flw_constantAmbientLight == 1u) {
return diffuseNether(flw_vertexNormal);
if (flw_useLightDirections == 1u) {
return diffuseFromLightDirections(flw_vertexNormal);
} else {
return diffuse(flw_vertexNormal);
if (flw_constantAmbientLight == 1u) {
return diffuseNether(flw_vertexNormal);
} else {
return diffuse(flw_vertexNormal);
}
}
} else {
return 1.;

View file

@ -7,3 +7,11 @@ float diffuseNether(vec3 normal) {
vec3 n2 = normal * normal * vec3(.6, .9, .8);
return min(n2.x + n2.y + n2.z, 1.);
}
float diffuseFromLightDirections(vec3 normal) {
// We assume the directions are normalized before upload.
float light0 = max(0.0, dot(flw_light0Direction, normal));
float light1 = max(0.0, dot(flw_light1Direction, normal));
return min(1.0, (light0 + light1) * 0.6 + 0.4);
}

View file

@ -2,6 +2,9 @@ layout(std140) uniform _FlwLevelUniforms {
vec4 flw_skyColor;
vec4 flw_cloudColor;
vec4 _flw_light0Direction;
vec4 _flw_light1Direction;
/** The current day number of the level. */
uint flw_levelDay;
/** The current fraction of the current day that has elapsed. */
@ -23,11 +26,15 @@ layout(std140) uniform _FlwLevelUniforms {
float flw_skyDarken;
uint flw_constantAmbientLight;
uint flw_useLightDirections;
/** Use FLW_DIMENSION_* ids to determine the dimension. May eventually be implemented for custom dimensions. */
uint flw_dimension;
};
#define flw_light0Direction (_flw_light0Direction.xyz)
#define flw_light1Direction (_flw_light1Direction.xyz)
#define FLW_DIMENSION_OVERWORLD 0
#define FLW_DIMENSION_NETHER 1
#define FLW_DIMENSION_END 2

View file

@ -50,15 +50,15 @@ public final class ModelUtil {
}
@Nullable
public static Material getItemMaterial(RenderType renderType, boolean shaded) {
var chunkMaterial = getMaterial(renderType, shaded);
public static Material getItemMaterial(RenderType renderType) {
var chunkMaterial = getMaterial(renderType, true);
if (chunkMaterial != null) {
return chunkMaterial;
}
if (renderType == Sheets.translucentCullBlockSheet() || renderType == Sheets.translucentItemSheet()) {
return shaded ? Materials.CUTOUT_BLOCK : Materials.CUTOUT_UNSHADED_BLOCK;
return Materials.CUTOUT_BLOCK;
}
if (renderType == RenderType.glint() || renderType == RenderType.glintDirect()) {
return Materials.GLINT;

View file

@ -6,5 +6,9 @@
"command.flywheel.limit_updates.get.off": "Update limiting is currently disabled",
"command.flywheel.limit_updates.get.on": "Update limiting is currently enabled",
"command.flywheel.limit_updates.set.off": "Update limiting is now disabled",
"command.flywheel.limit_updates.set.on": "Update limiting is now enabled"
"command.flywheel.limit_updates.set.on" : "Update limiting is now enabled",
"command.flywheel.use_light_directions.get.off" : "Not using light directions",
"command.flywheel.use_light_directions.get.on" : "Using light directions",
"command.flywheel.use_light_directions.set.off" : "Set light directions to off",
"command.flywheel.use_light_directions.set.on" : "Set light directions to on"
}

View file

@ -185,16 +185,24 @@ public class FabricFlwConfig implements FlwConfig {
public static class FabricBackendConfig implements BackendConfig {
public static final LightSmoothness LIGHT_SMOOTHNESS_DEFAULT = LightSmoothness.SMOOTH;
public static final boolean USE_LIGHT_DIRECTIONS_DEFAULT = true;
public LightSmoothness lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT;
public boolean useLightDirections = USE_LIGHT_DIRECTIONS_DEFAULT;
@Override
public LightSmoothness lightSmoothness() {
return lightSmoothness;
}
@Override
public boolean useLightDirections() {
return useLightDirections;
}
public void fromJson(JsonObject object) {
readLightSmoothness(object);
readUseLightDirections(object);
}
private void readLightSmoothness(JsonObject object) {
@ -224,9 +232,23 @@ public class FabricFlwConfig implements FlwConfig {
lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT;
}
private void readUseLightDirections(JsonObject object) {
var useLightDirectionsJson = object.get("useLightDirections");
if (useLightDirectionsJson instanceof JsonPrimitive primitive && primitive.isBoolean()) {
useLightDirections = primitive.getAsBoolean();
return;
} else if (useLightDirectionsJson != null) {
FlwBackend.LOGGER.warn("'useLightDirections' value must be a boolean");
}
useLightDirections = USE_LIGHT_DIRECTIONS_DEFAULT;
}
public JsonObject toJson() {
JsonObject object = new JsonObject();
object.addProperty("lightSmoothness", lightSmoothness.getSerializedName());
object.addProperty("useLightDirections", useLightDirections);
return object;
}
}

View file

@ -9,6 +9,7 @@ import com.mojang.brigadier.context.CommandContext;
import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import dev.engine_room.flywheel.backend.compile.PipelineCompiler;
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
@ -133,12 +134,39 @@ public final class FlwCommands {
if (oldValue != newValue) {
FabricFlwConfig.INSTANCE.backendConfig.lightSmoothness = newValue;
FabricFlwConfig.INSTANCE.save();
Minecraft.getInstance()
.reloadResourcePacks();
PipelineCompiler.deleteAll();
}
return Command.SINGLE_SUCCESS;
})));
command.then(ClientCommandManager.literal("useLightDirections")
.executes(context -> {
if (FabricFlwConfig.INSTANCE.backendConfig.useLightDirections) {
context.getSource()
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.get.on"));
} else {
context.getSource()
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.get.off"));
}
return Command.SINGLE_SUCCESS;
})
.then(ClientCommandManager.literal("on")
.executes(context -> {
FabricFlwConfig.INSTANCE.backendConfig.useLightDirections = true;
FabricFlwConfig.INSTANCE.save();
context.getSource()
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.set.on"));
return Command.SINGLE_SUCCESS;
}))
.then(ClientCommandManager.literal("off")
.executes(context -> {
FabricFlwConfig.INSTANCE.backendConfig.useLightDirections = false;
FabricFlwConfig.INSTANCE.save();
context.getSource()
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.set.off"));
return Command.SINGLE_SUCCESS;
})));
dispatcher.register(command);
}

View file

@ -7,6 +7,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import dev.engine_room.flywheel.backend.compile.PipelineCompiler;
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
import net.minecraft.client.Minecraft;
@ -131,12 +132,34 @@ public final class FlwCommands {
if (oldValue != newValue) {
lightSmoothnessValue.set(newValue);
Minecraft.getInstance()
.reloadResourcePacks();
PipelineCompiler.deleteAll();
}
return Command.SINGLE_SUCCESS;
})));
var useLightDirectionsValue = ForgeFlwConfig.INSTANCE.client.backendConfig.useLightDirections;
command.then(Commands.literal("useLightDirections")
.executes(context -> {
if (useLightDirectionsValue.get()) {
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.get.on"));
} else {
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.get.off"));
}
return Command.SINGLE_SUCCESS;
})
.then(Commands.literal("on")
.executes(context -> {
useLightDirectionsValue.set(true);
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.set.on"));
return Command.SINGLE_SUCCESS;
}))
.then(Commands.literal("off")
.executes(context -> {
useLightDirectionsValue.set(false);
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.set.off"));
return Command.SINGLE_SUCCESS;
})));
event.getDispatcher().register(command);
}

View file

@ -101,15 +101,24 @@ public class ForgeFlwConfig implements FlwConfig {
public static class ForgeBackendConfig implements BackendConfig {
public final ForgeConfigSpec.EnumValue<LightSmoothness> lightSmoothness;
public final ForgeConfigSpec.BooleanValue useLightDirections;
public ForgeBackendConfig(ForgeConfigSpec.Builder builder) {
lightSmoothness = builder.comment("How smooth flywheel's shader-based lighting should be. May have a large performance impact.")
.defineEnum("lightSmoothness", LightSmoothness.SMOOTH);
useLightDirections = builder.comment("If true, diffuse lighting is accurate to vanilla entities and block entities. If false, diffuse lighting is accurate to vanilla chunks. Zero performance impact, just a matter of visual preference.")
.define("useLightDirections", true);
}
@Override
public LightSmoothness lightSmoothness() {
return lightSmoothness.get();
}
@Override
public boolean useLightDirections() {
return useLightDirections.get();
}
}
}