From 2085878cf3545e592cc35941e072ddf95505bdeb Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 10 Nov 2022 19:51:51 +0100 Subject: [PATCH] far improved lightmap updater --- .../gui/rendering/sky/box/SkyboxRenderer.kt | 2 +- .../gui/rendering/world/light/Lightmap.kt | 4 +- .../updater/normal/NormalLightmapUpdater.kt | 156 ++++++++++++++++++ 3 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/world/light/updater/normal/NormalLightmapUpdater.kt diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt index b10c95331..2ec050fc2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sky/box/SkyboxRenderer.kt @@ -245,7 +245,7 @@ class SkyboxRenderer( return RGBColor(red / count, green / count, blue / count) } - private fun calculateLightingStrike(original: Vec3): Vec3 { + fun calculateLightingStrike(original: Vec3): Vec3 { val duration = this.strikeDuration val delta = millis() - lastStrike if (delta > duration) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/Lightmap.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/Lightmap.kt index 6044faff2..7dfa4079f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/Lightmap.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/Lightmap.kt @@ -35,8 +35,8 @@ class Lightmap(private val light: RenderLight) { private lateinit var defaultUpdater: LightmapUpdater fun init() { - // defaultUpdater = NormalLightmapUpdater(light.renderWindow.connection, light.renderWindow.renderer[SkyRenderer]) - defaultUpdater = LegacyLightmapUpdater(light.renderWindow.connection) + defaultUpdater = NormalLightmapUpdater(light.renderWindow.connection, light.renderWindow.renderer[SkyRenderer]) + // defaultUpdater = LegacyLightmapUpdater(light.renderWindow.connection) buffer.init() profile.light::fullbright.profileWatch(this, profile = profile) { setLightmapUpdater() } setLightmapUpdater() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/updater/normal/NormalLightmapUpdater.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/updater/normal/NormalLightmapUpdater.kt new file mode 100644 index 000000000..2c7c55640 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/updater/normal/NormalLightmapUpdater.kt @@ -0,0 +1,156 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.world.light.updater.normal + +import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kutil.watcher.DataWatcher.Companion.observe +import de.bixilon.minosoft.data.registries.dimension.DimensionProperties +import de.bixilon.minosoft.data.world.time.DayPhases +import de.bixilon.minosoft.data.world.time.WorldTime +import de.bixilon.minosoft.data.world.weather.WorldWeather +import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer +import de.bixilon.minosoft.gui.rendering.util.VecUtil.clamp +import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.interpolateLinear +import de.bixilon.minosoft.gui.rendering.world.light.LightmapBuffer +import de.bixilon.minosoft.gui.rendering.world.light.updater.LightmapUpdater +import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import kotlin.math.abs + +class NormalLightmapUpdater( + private val connection: PlayConnection, + private val skyRenderer: SkyRenderer?, +) : LightmapUpdater { + private val profile = connection.profiles.rendering.light + private var force = true + + init { + connection.world::dimension.observe(this) { force = true } + } + + override fun update(force: Boolean, buffer: LightmapBuffer) { + val dimension = connection.world.dimension ?: return + val skylight = dimension.hasSkyLight && dimension.effects.daylightCycle + + if (!force || !this.force) { + if (!skylight) { + // do not recalculate if skylight does not change (e.g. nether or end) + return + } + } + if (skylight) { + updateBlockSky(dimension, buffer) + } else { + updateBlock(dimension, buffer) + } + + this.force = false + } + + private fun updateBlock(dimension: DimensionProperties, buffer: LightmapBuffer) { + for (block in 0 until ProtocolDefinition.LIGHT_LEVELS) { + buffer[0, block] = calculateBlock(dimension.brightness[block]) + } + } + + private fun updateBlockSky(dimension: DimensionProperties, buffer: LightmapBuffer) { + val time = connection.world.time + val weather = connection.world.weather + val skyColors = Array(ProtocolDefinition.LIGHT_LEVELS.toInt()) { calculateSky(dimension.brightness[it], weather, time) } + val blockColors = Array(ProtocolDefinition.LIGHT_LEVELS.toInt()) { calculateBlock(dimension.brightness[it]) } + + for (sky in 0 until ProtocolDefinition.LIGHT_LEVELS) { + for (block in 0 until ProtocolDefinition.LIGHT_LEVELS) { + buffer[sky, block] = combine(skyColors[sky], blockColors[block]) + } + } + } + + private fun calculateBlock(brightness: Float): Vec3 { + val base = Vec3(brightness, brightness * ((brightness * 0.6f + 0.4f) * 0.6f + 0.4f), brightness * (brightness * brightness * 0.6f + 0.4f)) + return base + } + + private fun calculateDayBase(brightness: Float, progress: Float): Vec3 { + val base = Vec3(0.98f) + + return interpolateLinear((abs(progress - 0.5f) * 2.0f), base, base * 0.9f) * brightness + } + + private fun calculateSunset(brightness: Float, progress: Float, time: WorldTime): Vec3 { + val day = calculateDayBase(brightness, 1.0f) + val night = calculateNightBase(brightness, 0.0f, time) + + return interpolateLinear(progress, day, night) + } + + private fun calculateNightBase(brightness: Float, progress: Float, time: WorldTime): Vec3 { + val max = Vec3(0.10f, 0.10f, 0.30f) + + return interpolateLinear((abs(progress - 0.6f) + 0.4f), max * 0.1f, max) * brightness * time.moonPhase.light + } + + private fun calculateSunrise(brightness: Float, progress: Float, time: WorldTime): Vec3 { + val night = calculateNightBase(brightness, 1.0f, time) + val day = calculateDayBase(brightness, 0.0f) + + return interpolateLinear(progress, night, day) + } + + private fun calculateThunder(base: Vec3, brightness: Float, thunder: Float): Vec3 { + val baseBrightness = base.length() + + var color = interpolateLinear(baseBrightness, Vec3(0.55f, 0.35f, 0.58f), Vec3(0.65f, 0.4f, 0.7f)) * baseBrightness * brightness * 0.3f + + skyRenderer?.let { color = interpolateLinear(brightness * 5.0f + 0.5f, color, it.box.calculateLightingStrike(color)) } + return interpolateLinear(thunder, base, color) + } + + private fun calculateRain(base: Vec3, brightness: Float, rain: Float): Vec3 { + val baseBrightness = base.length() + + val color = interpolateLinear(baseBrightness, Vec3(0.4f, 0.4f, 0.8f), Vec3(0.5f, 0.5f, 0.9f)) * baseBrightness * brightness * 0.4f + + return interpolateLinear(rain, base, color) + } + + private fun calculateSky(brightness: Float, weather: WorldWeather, time: WorldTime): Vec3 { + var color = when (time.phase) { + DayPhases.DAY -> calculateDayBase(brightness, time.progress) + DayPhases.NIGHT -> calculateNightBase(brightness, time.progress, time) + DayPhases.SUNRISE -> calculateSunrise(brightness, time.progress, time) + DayPhases.SUNSET -> calculateSunset(brightness, time.progress, time) + } + if (weather.thunder > 0.0f) { + color = calculateThunder(color, brightness, weather.thunder) + } else if (weather.rain > 0.0f) { + color = calculateRain(color, brightness, weather.rain) + } + + return color.brighten(0.05f) + } + + + private fun combine(sky: Vec3, block: Vec3): Vec3 { + var color = sky + block + + color = color.clamp(0.0f, 1.0f) + + return color + } + + private fun Vec3.brighten(value: Float): Vec3 { + return this * (1.0f - value) + value + } +}