From c1717c7a54aaf17ff198715a93e1bde6c6a674b6 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Fri, 22 Sep 2023 21:32:34 +0900 Subject: [PATCH] new cloud colour model --- assets/clut/skyboxavr.png | 4 +-- .../clut/GenerateSkyboxTextureAtlas.kt | 32 +++++++++++++---- .../torvald/terrarum/weather/WeatherMixer.kt | 35 +++++++++++-------- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/assets/clut/skyboxavr.png b/assets/clut/skyboxavr.png index 5f7f2615e..6c7000093 100644 --- a/assets/clut/skyboxavr.png +++ b/assets/clut/skyboxavr.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:924af7adbd863fefb11ebb3a0a1a9292e98a36b105f6c69bd07700eb906d5c3e -size 39510 +oid sha256:5cae7d530644c156b2af72a36084d7ebeceea9629576234f83214cc53fec3c18 +size 50133 diff --git a/src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt b/src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt index 9eb66153a..b77226e36 100644 --- a/src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt +++ b/src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt @@ -1,8 +1,10 @@ package net.torvald.terrarum.clut import net.torvald.colourutil.CIEXYZ +import net.torvald.colourutil.HUSLColorConverter import net.torvald.colourutil.toColor import net.torvald.colourutil.toRGB +import net.torvald.gdx.graphics.Cvec import net.torvald.parametricsky.ArHosekSkyModel import net.torvald.terrarum.abs import net.torvald.terrarum.clut.Skybox.coerceInSmoothly @@ -11,7 +13,6 @@ import net.torvald.terrarum.clut.Skybox.scaleToFit import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI import net.torvald.terrarum.serialise.toLittle import net.torvald.terrarum.serialise.toUint -import net.torvald.terrarum.sqrt import java.io.File import kotlin.math.PI import kotlin.math.cos @@ -170,19 +171,26 @@ class GenerateSkyboxTextureAtlas { println("....... Turbidity=$turbidity") for (elev0 in 0 until Skybox.elevCnt) { - val pixelValueAvrB = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 0).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().times(255.0).roundToInt().toByte() - val pixelValueAvrG = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 1).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().times(255.0).roundToInt().toByte() - val pixelValueAvrR = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 2).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().times(255.0).roundToInt().toByte() - val pixelValueAvrA = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 3).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().times(255.0).roundToInt().toByte() + val avrB = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 0).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().toFloat() + val avrG = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 1).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().toFloat() + val avrR = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 2).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().toFloat() + val avrA = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 3).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().toFloat() - val colour = arrayOf(pixelValueAvrB, pixelValueAvrG, pixelValueAvrR, pixelValueAvrA) + val colour = Cvec(avrR, avrG, avrB, avrA).saturate(1.6666667f) + + val colourBytes = arrayOf( + colour.b.times(255f).roundToInt().coerceIn(0..255).toByte(), + colour.g.times(255f).roundToInt().coerceIn(0..255).toByte(), + colour.r.times(255f).roundToInt().coerceIn(0..255).toByte(), + colour.a.times(255f).roundToInt().coerceIn(0..255).toByte() + ) val imgOffX = albedo0 * Skybox.elevCnt + elev0 + Skybox.elevCnt * Skybox.albedoCnt * gammaPair val imgOffY = texh2 - 1 - turb0 val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX) for (i in 0..3) { - bytes2[fileOffset + i] = colour[i] + bytes2[fileOffset + i] = colourBytes[i] } } @@ -207,6 +215,16 @@ class GenerateSkyboxTextureAtlas { this * 12.92 } + private fun Cvec.saturate(intensity: Float): Cvec { + val luv = HUSLColorConverter.rgbToHsluv(floatArrayOf(this.r, this.g, this.b)) + luv[1] *= intensity + val rgb = HUSLColorConverter.hsluvToRgb(luv) + this.r = rgb[0] + this.g = rgb[1] + this.b = rgb[2] + return this + } + private val bytesLut = arrayOf(2, 1, 0, 3, 2, 1, 0, 3) // For some reason BGRA order is what makes it work } diff --git a/src/net/torvald/terrarum/weather/WeatherMixer.kt b/src/net/torvald/terrarum/weather/WeatherMixer.kt index d64ed4a4a..5e1976c97 100644 --- a/src/net/torvald/terrarum/weather/WeatherMixer.kt +++ b/src/net/torvald/terrarum/weather/WeatherMixer.kt @@ -549,6 +549,13 @@ internal object WeatherMixer : RNGConsumer { private val parallaxDomainSize = 550f private val turbidityDomainSize = parallaxDomainSize * 1.3333334f + private val CLOUD_SOLARDEG_OFFSET = 0.9f + + private val globalLightBySun = Cvec() + private val globalLightByMoon = Cvec() + private val cloudCol1 = Cvec() + private val cloudCol2 = Cvec() + private fun drawSkybox(camera: OrthographicCamera, batch: FlippingSpriteBatch, world: GameWorld) { val weatherbox = world.weatherbox val currentWeather = world.weatherbox.currentWeather @@ -559,8 +566,8 @@ internal object WeatherMixer : RNGConsumer { val daylightClut = currentWeather.daylightClut // calculate global light val moonSize = (-(2.0 * world.worldTime.moonPhase - 1.0).abs() + 1.0).toFloat() - val globalLightBySun: Cvec = getGradientColour2(daylightClut, solarElev, timeNow) - val globalLightByMoon: Cvec = moonlightMax * moonSize + globalLightBySun.set(getGradientColour2(daylightClut, solarElev, timeNow)) + globalLightByMoon.set(moonlightMax * moonSize) globalLightNow.set(globalLightBySun max globalLightByMoon) /* (copied from the shader source) @@ -598,8 +605,9 @@ internal object WeatherMixer : RNGConsumer { - val cloudCol1 = getGradientCloud(skyboxavr, solarElev, mornNoonBlend.toDouble(), turbidity, albedo) - cloudDrawColour.set(lerp(0.5, cloudCol1, globalLightNow)) + cloudCol1.set(getGradientCloud(skyboxavr, solarElev, mornNoonBlend.toDouble(), turbidity, albedo)) + cloudCol2.set(getGradientColour2(daylightClut, solarElev + CLOUD_SOLARDEG_OFFSET, timeNow) max globalLightByMoon) + cloudDrawColour.set(lerp(0.5, cloudCol1, cloudCol2)) @@ -728,11 +736,14 @@ internal object WeatherMixer : RNGConsumer { return Cvec(newColRGB, newColUV.r) } - fun getGradientCloud(colorMap: GdxColorMap, solarAngleInDeg: Double, mornNoonBlend: Double, turbidity: Double, albedo: Double): Cvec { + fun getGradientCloud(colorMap: GdxColorMap, solarAngleInDeg0: Double, mornNoonBlend: Double, turbidity: Double, albedo: Double): Cvec { + val solarAngleInDeg = solarAngleInDeg0 + CLOUD_SOLARDEG_OFFSET // add a small offset + val solarAngleInDegInt = solarAngleInDeg.floorToInt() + // fine-grained - val angleX1 = solarAngleInDeg.toInt() + 75 + val angleX1 = (solarAngleInDegInt + 75).coerceAtMost(150) val angleX2 = (angleX1 + 1).coerceAtMost(150) - val ax = solarAngleInDeg % 1.0 + val ax = solarAngleInDeg - solarAngleInDegInt // fine-grained val turbY = turbidity.coerceIn(Skybox.turbiditiesD.first(), Skybox.turbiditiesD.last()).minus(1.0).times(Skybox.turbDivisor) val turbY1 = turbY.floorToInt() @@ -752,7 +763,6 @@ internal object WeatherMixer : RNGConsumer { val a2t1b2A = colorMap.getCvec(albX2 * elevCnt + angleX2, turbY1) val a1t2b2A = colorMap.getCvec(albX2 * elevCnt + angleX1, turbY2) val a2t2b2A = colorMap.getCvec(albX2 * elevCnt + angleX2, turbY2) - val a1t1b1B = colorMap.getCvec(albX1 * elevCnt + angleX1 + Skybox.albedoCnt * elevCnt, turbY1) val a2t1b1B = colorMap.getCvec(albX1 * elevCnt + angleX2 + Skybox.albedoCnt * elevCnt, turbY1) val a1t2b1B = colorMap.getCvec(albX1 * elevCnt + angleX1 + Skybox.albedoCnt * elevCnt, turbY2) @@ -766,20 +776,17 @@ internal object WeatherMixer : RNGConsumer { val t2b1A = lerp(ax, a1t2b1A, a2t2b1A) val t1b2A = lerp(ax, a1t1b2A, a2t1b2A) val t2b2A = lerp(ax, a1t2b2A, a2t2b2A) - - val b1A = lerp(tx, t1b1A, t2b1A) - val b2A = lerp(tx, t1b2A, t2b2A) - - val A = lerp(bx, b1A, b2A) - val t1b1B = lerp(ax, a1t1b1B, a2t1b1B) val t2b1B = lerp(ax, a1t2b1B, a2t2b1B) val t1b2B = lerp(ax, a1t1b2B, a2t1b2B) val t2b2B = lerp(ax, a1t2b2B, a2t2b2B) + val b1A = lerp(tx, t1b1A, t2b1A) + val b2A = lerp(tx, t1b2A, t2b2A) val b1B = lerp(tx, t1b1B, t2b1B) val b2B = lerp(tx, t1b2B, t2b2B) + val A = lerp(bx, b1A, b2A) val B = lerp(bx, b1B, b2B) return lerp(mornNoonBlend, A, B)