proper light map, proper sky light

This commit is contained in:
Bixilon 2021-07-01 16:51:11 +02:00
parent 2c2ec5bd9f
commit 80ca0bf788
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
15 changed files with 279 additions and 31 deletions

View File

@ -30,4 +30,5 @@ data class GameConfig(
var sound: SoundConfig = SoundConfig(),
var entities: EntitiesConfig = EntitiesConfig(),
var world: WorldConfig = WorldConfig(),
var light: LightConfig = LightConfig(),
)

View File

@ -0,0 +1,18 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.config.config.game
data class LightConfig(
var gamma: Float = 1.0f,
)

View File

@ -16,6 +16,7 @@ import com.google.gson.JsonObject
import de.bixilon.minosoft.data.registries.registry.RegistryItem
import de.bixilon.minosoft.data.registries.registry.ResourceLocationDeserializer
import de.bixilon.minosoft.data.registries.versions.Registries
import de.bixilon.minosoft.gui.rendering.util.VecUtil.lerp
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.nullCast
@ -48,6 +49,18 @@ data class Dimension(
} else {
height / ProtocolDefinition.SECTION_HEIGHT_Y
}
val lightLevels = FloatArray(16)
init {
val ambientLight = 0.0f // ToDo: 0.1 in nether
for (i in lightLevels.indices) {
val asFloat = i / 15.0f
lightLevels[i] = lerp(ambientLight, asFloat / (4.0f - 3.0f * asFloat), 1.0f)
}
}
override fun toString(): String {
return resourceLocation.full

View File

@ -23,4 +23,6 @@ object DefaultStatusEffects {
val HASTE = "minecraft:haste".asResourceLocation()
val MINING_FATIGUE = "minecraft:mining_fatigue".asResourceLocation()
val DOLPHINS_GRACE = "minecraft:dolphins_grace".asResourceLocation()
val NIGHT_VISION = "minecraft:night_vision".asResourceLocation()
val CONDUIT_POWER = "minecraft:conduit_power".asResourceLocation()
}

View File

@ -16,7 +16,15 @@ package de.bixilon.minosoft.data.registries.other.game.event
import de.bixilon.minosoft.data.registries.DefaultFactory
import de.bixilon.minosoft.data.registries.other.game.event.handlers.GameEventHandler
import de.bixilon.minosoft.data.registries.other.game.event.handlers.GameMoveChangeGameEventHandler
import de.bixilon.minosoft.data.registries.other.game.event.handlers.gradients.RainGradientSetGameEventHandler
import de.bixilon.minosoft.data.registries.other.game.event.handlers.gradients.ThunderGradientSetGameEventHandler
import de.bixilon.minosoft.data.registries.other.game.event.handlers.rain.RainStartGameEventHandler
import de.bixilon.minosoft.data.registries.other.game.event.handlers.rain.RainStopGameEventHandler
object DefaultGameEventHandlers : DefaultFactory<GameEventHandler>(
GameMoveChangeGameEventHandler
GameMoveChangeGameEventHandler,
RainStartGameEventHandler,
RainStopGameEventHandler,
RainGradientSetGameEventHandler,
ThunderGradientSetGameEventHandler,
)

View File

@ -0,0 +1,27 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.registries.other.game.event.handlers.gradients
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.other.game.event.handlers.GameEventHandler
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.asResourceLocation
object RainGradientSetGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_gradient_set".asResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.rainGradient = data
}
}

View File

@ -0,0 +1,27 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.registries.other.game.event.handlers.gradients
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.other.game.event.handlers.GameEventHandler
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.asResourceLocation
object ThunderGradientSetGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:thunder_gradient_set".asResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.thunderGradient = data
}
}

View File

@ -0,0 +1,28 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.registries.other.game.event.handlers.rain
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.other.game.event.handlers.GameEventHandler
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.asResourceLocation
object RainStartGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_start".asResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.raining = true
connection.world.rainGradient = 1.0f
}
}

View File

@ -0,0 +1,28 @@
/*
* Minosoft
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.registries.other.game.event.handlers.rain
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.other.game.event.handlers.GameEventHandler
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.asResourceLocation
object RainStopGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:rain_stop".asResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.world.raining = false
connection.world.rainGradient = 0.0f
}
}

View File

@ -39,11 +39,17 @@ import de.bixilon.minosoft.modding.event.EventInitiators
import de.bixilon.minosoft.modding.event.events.BlockSetEvent
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import de.bixilon.minosoft.util.MMath
import glm_.func.common.clamp
import glm_.vec2.Vec2i
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.cos
import kotlin.random.Random
/**
@ -63,6 +69,9 @@ class World(
var biomeAccessor: BiomeAccessor = NullBiomeAccessor
var time = 0L
var age = 0L
var raining = false
var rainGradient = 0.0f
var thunderGradient = 0.0f
private val random = Random
var audioPlayer: AudioPlayer? = null
@ -252,6 +261,24 @@ class World(
return true
}
val skyAngle: Double
get() {
val fractionalPath = MMath.fractionalPart(abs(time) / ProtocolDefinition.TICKS_PER_DAYf - 0.25)
val angle = 0.5 - cos(fractionalPath * Math.PI) / 2.0
return (fractionalPath * 2.0 + angle) / 3.0
}
val lightBase: Double
get() {
var base = 1.0f - (cos(skyAngle * 2.0 * PI) * 2.0 + 0.2)
base = base.clamp(0.0, 1.0)
base = 1.0 - base
base *= 1.0 - ((rainGradient * 5.0) / 16.0)
base *= 1.0 - (((thunderGradient * rainGradient) * 5.0) / 16.0)
return base * 0.8 + 0.2
}
companion object {
const val MAX_SIZE = 29999999
const val MAX_SIZEf = MAX_SIZE.toFloat()

View File

@ -13,16 +13,27 @@
package de.bixilon.minosoft.gui.rendering.block
import de.bixilon.minosoft.data.text.RGBColor.Companion.asGray
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.data.registries.effects.DefaultStatusEffects
import de.bixilon.minosoft.gui.rendering.system.base.shader.Shader
import de.bixilon.minosoft.gui.rendering.system.opengl.FloatUniformBuffer
import de.bixilon.minosoft.gui.rendering.util.VecUtil.ONE
import de.bixilon.minosoft.gui.rendering.util.VecUtil.clamp
import de.bixilon.minosoft.gui.rendering.util.VecUtil.lerp
import de.bixilon.minosoft.gui.rendering.util.VecUtil.modify
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import glm_.glm
import glm_.vec3.Vec3
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.sin
class LightMap(private val connection: PlayConnection) {
private val nightVisionStatusEffect = connection.registries.statusEffectRegistry[DefaultStatusEffects.NIGHT_VISION]
private val conduitPowerStatusEffect = connection.registries.statusEffectRegistry[DefaultStatusEffects.CONDUIT_POWER]
private val uniformBuffer = FloatUniformBuffer(1, FloatArray(16 * 16 * 4) { 1.0f })
private var lastUpdate = -1L
fun init() {
@ -35,22 +46,69 @@ class LightMap(private val connection: PlayConnection) {
}
fun update() {
val currentTime = System.currentTimeMillis()
if (currentTime - lastUpdate < ProtocolDefinition.TICK_TIME * 10) {
return
}
lastUpdate = currentTime
val skyGradient = connection.world.lightBase.toFloat()
// ToDo: Lightning
val underwaterVisibility = 0.0f // ToDo
val nightVisionEffect = connection.player.activeStatusEffects[nightVisionStatusEffect]
val nightVisionVisibility = if (nightVisionEffect != null) {
if (nightVisionEffect.duration > 200) {
1.0f
} else {
0.7f + sin((nightVisionEffect.duration.toFloat()) * glm.PIf * 0.2f) * 0.3f
}
} else if (underwaterVisibility > 0.0f && connection.player.activeStatusEffects[conduitPowerStatusEffect] != null) {
underwaterVisibility
} else {
0.0f
}
var skyGradientColor = Vec3(skyGradient, skyGradient, 1.0f)
skyGradientColor = lerp(0.35f, skyGradientColor, Vec3.ONE)
// ToDo
for (skyLight in 0 until 16) {
for (blockLight in 0 until 16) {
val index = ((skyLight shl 4) or blockLight) * 4
val color = ((blockLight + skyLight) / 30.0f).asGray()
uniformBuffer.data[index + 0] = color.floatRed
uniformBuffer.data[index + 1] = color.floatRed
uniformBuffer.data[index + 2] = color.floatGreen
val skyLightBrightness = (connection.world.dimension?.lightLevels?.get(skyLight) ?: 1.0f) * (skyGradient * 0.95f + 0.05f)
val blockLightBrightness = (connection.world.dimension?.lightLevels?.get(blockLight) ?: 1.0f) * 1.5// ToDo: multiply with time somewhat thing?
var color = Vec3(blockLightBrightness, blockLightBrightness * ((blockLightBrightness * 0.6f + 0.4f) * 0.6f + 0.4f), blockLightBrightness * (blockLightBrightness * blockLightBrightness * 0.6f + 0.4f))
// ToDo: Lightning
let {
color = color + (skyGradientColor * skyLightBrightness)
color = lerp(0.04f, color, Vec3(0.75f))
// ToDo: Sky darkness
}
color = color.clamp(0.0f, 1.0f)
if (nightVisionVisibility > 0.0f) {
val gamma = max(color.x, max(color.y, color.z))
if (gamma < 1.0f) {
val copy = color.toVec3 * (1.0f / gamma)
color = lerp(nightVisionVisibility, color, copy)
}
}
color = lerp(Minosoft.config.config.game.light.gamma, color, color.toVec3 modify { 1.0f - (1.0f - it).pow(4) })
color = lerp(0.04f, color, Vec3(0.75f))
color = color.clamp(0.0f, 1.0f)
uniformBuffer.data[index + 0] = color.x
uniformBuffer.data[index + 1] = color.y
uniformBuffer.data[index + 2] = color.z
}
}
uniformBuffer.upload()

View File

@ -54,7 +54,10 @@ class FluidRenderer(
if (!RenderConstants.RENDER_FLUIDS) {
return
}
val lightLevel = context.lightAccessor.getLightLevel(context.blockPosition)
val blockLight = context.lightAccessor.getBlockLight(context.blockPosition)
val skyLight = context.lightAccessor.getSkyLight(context.blockPosition)
val light = (skyLight shl 4) or blockLight
val heights = calculateHeights(context.neighbourBlocks, context.blockState, context.world, context.blockPosition)
val isFlowing = isLiquidFlowing(heights)
@ -88,7 +91,7 @@ class FluidRenderer(
tintColor = context.renderWindow.tintColorCalculator.getAverageTint(biome, context.blockState, context.blockPosition)
}
createQuad(drawPositions, face.getTexturePositionArray(direction), texture, context.blockPosition, context.meshCollection, tintColor, lightLevel)
createQuad(drawPositions, face.getTexturePositionArray(direction), texture, context.blockPosition, context.meshCollection, tintColor, light)
}
}
@ -135,7 +138,7 @@ class FluidRenderer(
return heights.toSet().size != 1 // liquid is flowing, if not all of the heights are the same
}
private fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>, texture: Texture, blockPosition: Vec3i, meshCollection: ChunkSectionMeshCollection, tintColor: RGBColor?, lightLevel: Int) {
private fun createQuad(drawPositions: Array<Vec3>, texturePositions: Array<Vec2?>, texture: Texture, blockPosition: Vec3i, meshCollection: ChunkSectionMeshCollection, tintColor: RGBColor?, light: Int) {
val mesh = ElementRenderer.getMesh(meshCollection, texture.transparency)
for (vertex in ElementRenderer.DRAW_ODER) {
mesh.addVertex(
@ -143,7 +146,7 @@ class FluidRenderer(
textureCoordinates = texturePositions[vertex.second]!!,
texture = texture,
tintColor = tintColor,
light = lightLevel,
light = light,
)
}
}

View File

@ -27,14 +27,12 @@ import de.bixilon.minosoft.modding.event.CallbackEventInvoker
import de.bixilon.minosoft.modding.event.events.TimeChangeEvent
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.MMath
import glm_.func.rad
import glm_.mat4x4.Mat4
import glm_.mat4x4.Mat4d
import glm_.vec2.Vec2
import glm_.vec3.Vec3
import glm_.vec3.Vec3d
import kotlin.math.cos
class SkyRenderer(
private val connection: PlayConnection,
@ -73,7 +71,7 @@ class SkyRenderer(
}
private fun setSunMatrix(projectionViewMatrix: Mat4d) {
val timeAngle = ((getSkyAngle(connection.world.time) * 360.0) + 180.0).rad
val timeAngle = (connection.world.skyAngle * 360.0).rad
val rotatedMatrix = if (timeAngle == 0.0) {
projectionViewMatrix
} else {
@ -151,11 +149,5 @@ class SkyRenderer(
override fun build(connection: PlayConnection, renderWindow: RenderWindow): SkyRenderer {
return SkyRenderer(connection, renderWindow)
}
fun getSkyAngle(time: Long): Double {
val fractionalPath = MMath.fractionalPart(time / ProtocolDefinition.TICKS_PER_DAYf - 0.25)
val angle = 0.5 - cos(fractionalPath * Math.PI) / 2.0
return (fractionalPath * 2.0 + angle) / 3.0
}
}
}

View File

@ -87,6 +87,22 @@ object VecUtil {
)
}
infix operator fun Vec3.times(lambda: () -> Float): Vec3 {
return Vec3(
x = x * lambda(),
y = y * lambda(),
z = z * lambda(),
)
}
infix fun Vec3.modify(lambda: (Float) -> Float): Vec3 {
return Vec3(
x = lambda(x),
y = lambda(y),
z = lambda(z),
)
}
infix operator fun Vec3d.plus(lambda: () -> Double): Vec3d {
return Vec3d(
x = x + lambda(),

View File

@ -536,10 +536,10 @@
"minecraft:arrow_player_hit": {
"id": 6
},
"minecraft:rain_level_set": {
"minecraft:rain_gradient_set": {
"id": 7
},
"minecraft:thunder_level_Set": {
"minecraft:thunder_gradient_set": {
"id": 8
},
"minecraft:pufferfish_sting": {
@ -571,10 +571,10 @@
"minecraft:arrow_player_hit": {
"id": 6
},
"minecraft:rain_level_set": {
"minecraft:rain_gradient_set": {
"id": 7
},
"minecraft:thunder_level_Set": {
"minecraft:thunder_gradient_set": {
"id": 8
},
"minecraft:pufferfish_sting": {