From 78075d779b28e35cd0783a76a4ea4b421d0de944 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 2 Sep 2023 02:40:27 +0900 Subject: [PATCH] each cloud now carry its own gamma value --- .../basegame/weathers/WeatherGeneric.json | 4 +- .../basegame/weathers/WeatherGeneric2.json | 4 +- .../basegame/weathers/WeatherOvercast.json | 4 +- .../terrarum/weather/BaseModularWeather.kt | 10 +++ .../torvald/terrarum/weather/WeatherMixer.kt | 26 +++--- .../terrarum/weather/WeatherObjectCloud.kt | 79 ++++++++++++++++--- .../torvald/terrarum/weather/Weatherbox.kt | 7 +- src/shaders/clouds.frag | 56 +++++++++++-- src/shaders/default.vert | 2 +- 9 files changed, 157 insertions(+), 35 deletions(-) diff --git a/assets/mods/basegame/weathers/WeatherGeneric.json b/assets/mods/basegame/weathers/WeatherGeneric.json index ea353bf7d..0cab4ed28 100644 --- a/assets/mods/basegame/weathers/WeatherGeneric.json +++ b/assets/mods/basegame/weathers/WeatherGeneric.json @@ -4,8 +4,8 @@ "daylightClut": "clut_daylight.tga", "classification": "generic", "cloudChance": 125, - "cloudGamma": [0.48, 2.4], - "cloudGammaVariance": [0.1, 0.1], + "cloudGamma": [0.45, 2.4], + "cloudGammaVariance": [0.1, 0.0], "windSpeed": 0.25, "windSpeedVariance": 1.0, "clouds": { diff --git a/assets/mods/basegame/weathers/WeatherGeneric2.json b/assets/mods/basegame/weathers/WeatherGeneric2.json index 5ce3615dd..ee5086973 100644 --- a/assets/mods/basegame/weathers/WeatherGeneric2.json +++ b/assets/mods/basegame/weathers/WeatherGeneric2.json @@ -4,8 +4,8 @@ "daylightClut": "clut_daylight.tga", "classification": "generic2", "cloudChance": 800, - "cloudGamma": [0.48, 2.4], - "cloudGammaVariance": [0.1, 0.1], + "cloudGamma": [0.6, 2.4], + "cloudGammaVariance": [0.1, 0.0], "windSpeed": 0.25, "windSpeedVariance": 1.0, "clouds": { diff --git a/assets/mods/basegame/weathers/WeatherOvercast.json b/assets/mods/basegame/weathers/WeatherOvercast.json index 5cd86ed5c..4bf0cfd93 100644 --- a/assets/mods/basegame/weathers/WeatherOvercast.json +++ b/assets/mods/basegame/weathers/WeatherOvercast.json @@ -4,8 +4,8 @@ "daylightClut": "clut_daylight.tga", "classification": "overcast", "cloudChance": 300, - "cloudGamma": [2.2, 2.0], - "cloudGammaVariance": [0.1, 0.1], + "cloudGamma": [3.7, 1.6], + "cloudGammaVariance": [0.0, 0.0], "windSpeed": 10.45, "windSpeedVariance": 0.5, "clouds": { diff --git a/src/net/torvald/terrarum/weather/BaseModularWeather.kt b/src/net/torvald/terrarum/weather/BaseModularWeather.kt index cf6c193e0..4667bc639 100644 --- a/src/net/torvald/terrarum/weather/BaseModularWeather.kt +++ b/src/net/torvald/terrarum/weather/BaseModularWeather.kt @@ -40,6 +40,16 @@ data class BaseModularWeather( val v = 1f + rnd.absoluteValue * windSpeedVariance return if (rnd < 0) windSpeed / v else windSpeed * v } + + fun getRandomCloudGamma(rnd1: Float, rnd2: Float): Vector2 { + val v = 1f + rnd1.absoluteValue * cloudGammaVariance.x + val gx = if (rnd1 < 0) cloudGamma.x / v else cloudGamma.x * v + + val u = 1f + rnd2.absoluteValue * cloudGammaVariance.y + val gy = if (rnd2 < 0) cloudGamma.y / u else cloudGamma.y * u + + return Vector2(gx, gy) + } } data class CloudProps( diff --git a/src/net/torvald/terrarum/weather/WeatherMixer.kt b/src/net/torvald/terrarum/weather/WeatherMixer.kt index e7852f7fe..9eccc76bd 100644 --- a/src/net/torvald/terrarum/weather/WeatherMixer.kt +++ b/src/net/torvald/terrarum/weather/WeatherMixer.kt @@ -146,24 +146,22 @@ internal object WeatherMixer : RNGConsumer { oldCamPos.set(WorldCamera.camVector) weatherbox = Weatherbox() - weatherbox.initWith(weatherDict["generic01"]!!, 3600L) + weatherbox.initWith(weatherDict["generic01"]!!, 7200L) // TEST FILL WITH RANDOM VALUES - (0..5).map { takeUniformRand(0f..1f) }.let { + (0..4).map { takeUniformRand(0f..1f) }.let { weatherbox.windDir.pM1 = it[0] weatherbox.windDir.p0 = it[1] weatherbox.windDir.p1 = it[2] weatherbox.windDir.p2 = it[3] weatherbox.windDir.p3 = it[4] -// weatherbox.windDir.p4 = it[5] } - (0..5).map { takeUniformRand(-1f..1f) }.let { + (0..4).map { takeUniformRand(-1f..1f) }.let { weatherbox.windSpeed.pM1 = currentWeather.getRandomWindSpeed(it[0]) weatherbox.windSpeed.p0 = currentWeather.getRandomWindSpeed(it[1]) weatherbox.windSpeed.p1 = currentWeather.getRandomWindSpeed(it[2]) weatherbox.windSpeed.p2 = currentWeather.getRandomWindSpeed(it[3]) weatherbox.windSpeed.p3 = currentWeather.getRandomWindSpeed(it[4]) -// weatherbox.windSpeed.p4 = currentWeather.getRandomWindSpeed(it[5]) } } @@ -301,7 +299,7 @@ internal object WeatherMixer : RNGConsumer { it.posX += camDelta.x * cloudParallaxMultX it.posY += camDelta.y * cloudParallaxMultY - it.update(windVector) + it.update(world, windVector) if (DEBUG_CAUSE_OF_DESPAWN && it.life == 0) { immDespawnCount += 1 @@ -450,7 +448,15 @@ internal object WeatherMixer : RNGConsumer { val sheetX = rA % cloud.spriteSheet.horizontalCount val sheetY = rB % cloud.spriteSheet.verticalCount - WeatherObjectCloud(cloud.spriteSheet.get(sheetX, sheetY), flip).also { + + val cloudGamma = currentWeather.getRandomCloudGamma(takeUniformRand(-1f..1f), takeUniformRand(-1f..1f)) + + WeatherObjectCloud( + cloud.spriteSheet.get(sheetX, sheetY), + flip, + cloudGamma.x, + cloudGamma.y + ).also { it.scale = cloudScale * cloudSizeMult it.pos.set(precalculatedPos ?: getCloudSpawningPosition(cloud, hCloudSize, windVector)) @@ -492,7 +498,7 @@ internal object WeatherMixer : RNGConsumer { internal fun titleScreenInitWeather() { weatherbox.initWith(weatherDict["titlescreen"]!!, Long.MAX_VALUE) - forceWindVec = Vector3(-0.98f, 0f, -0.21f) + forceWindVec = Vector3(-0.98f, 0f, -0.21f).scl(1f/30f) // value taken from TitleScreen.kt; search for 'demoWorld.worldTime.timeDelta = ' initClouds() } @@ -525,12 +531,10 @@ internal object WeatherMixer : RNGConsumer { private fun drawClouds(batch: SpriteBatch) { batch.inUse { _ -> batch.shader = shaderClouds - batch.shader.setUniformf("gamma", currentWeather.cloudGamma) batch.shader.setUniformf("shadeCol", 0.06f, 0.07f, 0.08f, 1f) // TODO temporary value clouds.forEach { - batch.color = Color(cloudDrawColour.r, cloudDrawColour.g, cloudDrawColour.b, it.alpha) - it.render(batch, 0f, 0f) + it.render(batch, cloudDrawColour) } } } diff --git a/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt b/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt index 1609f6e2d..9ea40951a 100644 --- a/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt +++ b/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt @@ -1,12 +1,14 @@ package net.torvald.terrarum.weather +import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.TextureRegion -import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector3 import com.jme3.math.FastMath import net.torvald.terrarum.App import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.gameworld.GameWorld +import kotlin.math.absoluteValue import kotlin.math.pow import kotlin.math.roundToInt import kotlin.math.sign @@ -14,7 +16,12 @@ import kotlin.math.sign /** * Created by minjaesong on 2023-08-21. */ -class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: Boolean) : WeatherObject(), Comparable { +class WeatherObjectCloud( + private val texture: TextureRegion, + private val flipW: Boolean, + private val rgbGamma: Float, + private val aGamma: Float +) : WeatherObject(), Comparable { override fun update() { throw UnsupportedOperationException() @@ -33,11 +40,12 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: * FlowVector: In which direction the cloud flows. Vec3(dX, dY, dScale) * Resulting vector: (x + dX, y + dY, scale * dScale) */ - fun update(flowVector: Vector3) { + fun update(world: GameWorld, flowVector: Vector3) { pos.add( flowVector.cpy(). scl(1f, 1f, getZflowMult(posZ)). // this will break the perspective if flowVector.z.abs() is close to 1, but it has to be here to "keep the distance" - scl(vecMult) + scl(vecMult). + scl(world.worldTime.timeDelta.toFloat()) ) eigenAlpha = if (posZ < 1f) posZ.pow(0.5f) else -((posZ - 1f) / ALPHA_ROLLOFF_Z) + 1f @@ -66,19 +74,43 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: private val h = App.scr.hf * 0.5f private val vecMult = Vector3(1f, 1f, 1f / (4f * h)) - /** - * X/Y position is a bottom-centre point of the image - * Shader must be prepared prior to the render() call - */ - override fun render(batch: SpriteBatch, offsetX: Float, offsetY: Float) { + private fun roundRgbGamma(x: Float): Int { + return RGB_GAMMA_TABLE.mapIndexed { i, f -> (f - x).absoluteValue to i }.minBy { it.first }.second + } + private fun roundAgamma(x: Float): Int { + return A_GAMMA_TABLE.mapIndexed { i, f -> (f - x).absoluteValue to i }.minBy { it.first }.second + } + + fun render(batch: SpriteBatch, cloudDrawColour: Color) { val sc = screenCoord + val rgbGammaIndex = roundRgbGamma(rgbGamma) + val aGammaIndex = roundAgamma(aGamma) + +// printdbg(this, "gamma: (${rgbGamma}, ${aGamma}) index: ($rgbGammaIndex, $aGammaIndex)") + + val lightBits = cloudDrawColour.toIntBits() + val rbits = lightBits.ushr( 0).and(252) or rgbGammaIndex.ushr(2).and(3) + val gbits = lightBits.ushr( 8).and(252) or rgbGammaIndex.ushr(0).and(3) + val bbits = lightBits.ushr(16).and(252) or aGammaIndex + val abits = (alpha * 255).toInt() + + batch.color = Color(rbits.shl(24) or gbits.shl(16) or bbits.shl(8) or abits) + if (flipW) batch.draw(texture, sc.x + texture.regionWidth / posZ, sc.y, -texture.regionWidth * sc.z, texture.regionHeight * sc.z) else batch.draw(texture, sc.x, sc.y, texture.regionWidth * sc.z, texture.regionHeight * sc.z) } + /** + * X/Y position is a bottom-centre point of the image + * Shader must be prepared prior to the render() call + */ + override fun render(batch: SpriteBatch, offsetX: Float, offsetY: Float) { + throw UnsupportedOperationException() + } + /** * vec3(screen X, screenY, draw scale) */ @@ -133,5 +165,34 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: fun screenXtoWorldX(screenX: Float, z: Float) = screenX * z - App.scr.halfwf * (z - 1f) const val ALPHA_ROLLOFF_Z = 64f const val OLD_AGE_DECAY = 4000f + + val RGB_GAMMA_TABLE = floatArrayOf( + 0.2f, + 0.3f, + 0.4f, + 0.5f, + + 0.7f, + 0.9f, + 1.1f, + 1.3f, + + 1.7f, + 2.1f, + 2.5f, + 2.9f, + + 3.7f, + 4.5f, + 5.3f, + 6.1f + ) + + val A_GAMMA_TABLE = floatArrayOf( + 1.6f, + 2.0f, + 2.4f, + 2.8f + ) } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/weather/Weatherbox.kt b/src/net/torvald/terrarum/weather/Weatherbox.kt index 14c92b2e3..e1b3a2855 100644 --- a/src/net/torvald/terrarum/weather/Weatherbox.kt +++ b/src/net/torvald/terrarum/weather/Weatherbox.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.weather import com.jme3.math.FastMath +import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.floorToInt import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.fmod @@ -11,7 +12,7 @@ data class WeatherSchedule(val weather: BaseModularWeather = WeatherMixer.DEFAUL class Weatherbox { companion object { - private val WIND_DIR_TIME_UNIT = 3600f * 5 // every 5hr + private val WIND_DIR_TIME_UNIT = 3600f * 6 // every 6hr private val WIND_SPEED_TIME_UNIT = 3600f * 2 // every 2hr private val HALF_PIF = 1.5707964f @@ -53,10 +54,10 @@ class Weatherbox { // TODO add more random weathers if (weatherSchedule.size == 1) { val newName = if (currentWeather.identifier == "generic01") "overcast01" else "generic01" - val newDuration = 3600L + val newDuration = 7200L weatherSchedule.add(WeatherSchedule(WeatherMixer.weatherDict[newName]!!, newDuration)) - println("Queueing next weather '$newName' that will last $newDuration seconds") +// printdbg(this, "Queueing next weather '$newName' that will last $newDuration seconds") } // subtract akku by old currentWeatherDuration diff --git a/src/shaders/clouds.frag b/src/shaders/clouds.frag index 9f1d16637..0410d1c91 100644 --- a/src/shaders/clouds.frag +++ b/src/shaders/clouds.frag @@ -14,17 +14,63 @@ out vec4 fragColor; const vec2 boolean = vec2(0.0, 1.0); -uniform vec2 gamma = vec2(10, 2.0); // vec2(gamma for RGB, gamma for A) - uniform LOWP vec4 shadeCol; +const float rgbGammas[16] = float[]( +0.2, +0.3, +0.4, +0.5, + +0.7, +0.9, +1.1, +1.3, + +1.7, +2.1, +2.5, +2.9, + +3.7, +4.5, +5.3, +6.1 +); + +const float aGammas[4] = float[]( +1.6, +2.0, +2.4, +2.8 +); + void main() { + // vertex colour format: + // rrrrrrMM ggggggLL bbbbbbAA aaaaaaaa + // where: + // rrrrrr: 6-bit red component + // gggggg: 6-bit green component + // bbbbbb: 6-bit blue component + // MMLL: index to the rgbGammas + // AA: index to the aGammas + vec4 cloudCol = vec4( + (int(v_color.r * 255) >> 2) * 4.0 / 255.0, + (int(v_color.g * 255) >> 2) * 4.0 / 255.0, + (int(v_color.b * 255) >> 2) * 4.0 / 255.0, + v_color.a + ); + float rgbGamma = rgbGammas[((int(v_color.r * 255) & 3) << 2) | (int(v_color.g * 255) & 3)]; + float aGamma = aGammas[int(v_color.b * 255) & 3]; + vec4 gamma = vec4(rgbGamma, rgbGamma, rgbGamma, aGamma); + + // cloud colour format: // r: bw diffuse map, g: normal, b: normal, a: bw diffuse alpha vec4 inCol = texture(u_texture, v_texCoords); - vec4 rawCol = pow(inCol, gamma.xxxy); + vec4 rawCol = pow(inCol, gamma); // do gradient mapping here - vec4 outCol = fma(mix(shadeCol, v_color, rawCol.r), boolean.yyyx, rawCol * boolean.xxxy); + vec4 outCol = fma(mix(shadeCol, cloudCol, rawCol.r), boolean.yyyx, rawCol * boolean.xxxy); - fragColor = outCol * fma(v_color, boolean.xxxy, boolean.yyyx); + fragColor = outCol * fma(cloudCol, boolean.xxxy, boolean.yyyx); } \ No newline at end of file diff --git a/src/shaders/default.vert b/src/shaders/default.vert index 09430c19a..0a8a7a980 100644 --- a/src/shaders/default.vert +++ b/src/shaders/default.vert @@ -11,7 +11,7 @@ out vec2 v_texCoords; void main() { v_color = a_color; - v_color.a = v_color.a * (255.0/254.0); + v_color.a = v_color.a * (255.0/254.0); // GDX will crush the alpha value to 0,2,4,6,8,10,...,254; see com.badlogic.gdx.utils.NumberUtils.intToFloatColor v_texCoords = a_texCoord0; gl_Position = u_projTrans * a_position; } \ No newline at end of file