new cloud colour model

This commit is contained in:
minjaesong
2023-09-22 21:32:34 +09:00
parent 153fdb4a2c
commit c1717c7a54
3 changed files with 48 additions and 23 deletions

Binary file not shown.

View File

@@ -1,8 +1,10 @@
package net.torvald.terrarum.clut package net.torvald.terrarum.clut
import net.torvald.colourutil.CIEXYZ import net.torvald.colourutil.CIEXYZ
import net.torvald.colourutil.HUSLColorConverter
import net.torvald.colourutil.toColor import net.torvald.colourutil.toColor
import net.torvald.colourutil.toRGB import net.torvald.colourutil.toRGB
import net.torvald.gdx.graphics.Cvec
import net.torvald.parametricsky.ArHosekSkyModel import net.torvald.parametricsky.ArHosekSkyModel
import net.torvald.terrarum.abs import net.torvald.terrarum.abs
import net.torvald.terrarum.clut.Skybox.coerceInSmoothly 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.modulebasegame.worldgenerator.HALF_PI
import net.torvald.terrarum.serialise.toLittle import net.torvald.terrarum.serialise.toLittle
import net.torvald.terrarum.serialise.toUint import net.torvald.terrarum.serialise.toUint
import net.torvald.terrarum.sqrt
import java.io.File import java.io.File
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
@@ -170,19 +171,26 @@ class GenerateSkyboxTextureAtlas {
println("....... Turbidity=$turbidity") println("....... Turbidity=$turbidity")
for (elev0 in 0 until Skybox.elevCnt) { 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 avrB = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 0).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().toFloat()
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 avrG = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 1).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().toFloat()
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 avrR = (gradSizes.sumOf { getByte(gammaPair, albedo0, turb0, elev0, it, 2).toUint() }.toDouble() / Skybox.gradSize).div(255.0).srgbLinearise().toFloat()
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 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 imgOffX = albedo0 * Skybox.elevCnt + elev0 + Skybox.elevCnt * Skybox.albedoCnt * gammaPair
val imgOffY = texh2 - 1 - turb0 val imgOffY = texh2 - 1 - turb0
val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX) val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX)
for (i in 0..3) { for (i in 0..3) {
bytes2[fileOffset + i] = colour[i] bytes2[fileOffset + i] = colourBytes[i]
} }
} }
@@ -207,6 +215,16 @@ class GenerateSkyboxTextureAtlas {
this * 12.92 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 private val bytesLut = arrayOf(2, 1, 0, 3, 2, 1, 0, 3) // For some reason BGRA order is what makes it work
} }

View File

@@ -549,6 +549,13 @@ internal object WeatherMixer : RNGConsumer {
private val parallaxDomainSize = 550f private val parallaxDomainSize = 550f
private val turbidityDomainSize = parallaxDomainSize * 1.3333334f 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) { private fun drawSkybox(camera: OrthographicCamera, batch: FlippingSpriteBatch, world: GameWorld) {
val weatherbox = world.weatherbox val weatherbox = world.weatherbox
val currentWeather = world.weatherbox.currentWeather val currentWeather = world.weatherbox.currentWeather
@@ -559,8 +566,8 @@ internal object WeatherMixer : RNGConsumer {
val daylightClut = currentWeather.daylightClut val daylightClut = currentWeather.daylightClut
// calculate global light // calculate global light
val moonSize = (-(2.0 * world.worldTime.moonPhase - 1.0).abs() + 1.0).toFloat() val moonSize = (-(2.0 * world.worldTime.moonPhase - 1.0).abs() + 1.0).toFloat()
val globalLightBySun: Cvec = getGradientColour2(daylightClut, solarElev, timeNow) globalLightBySun.set(getGradientColour2(daylightClut, solarElev, timeNow))
val globalLightByMoon: Cvec = moonlightMax * moonSize globalLightByMoon.set(moonlightMax * moonSize)
globalLightNow.set(globalLightBySun max globalLightByMoon) globalLightNow.set(globalLightBySun max globalLightByMoon)
/* (copied from the shader source) /* (copied from the shader source)
@@ -598,8 +605,9 @@ internal object WeatherMixer : RNGConsumer {
val cloudCol1 = getGradientCloud(skyboxavr, solarElev, mornNoonBlend.toDouble(), turbidity, albedo) cloudCol1.set(getGradientCloud(skyboxavr, solarElev, mornNoonBlend.toDouble(), turbidity, albedo))
cloudDrawColour.set(lerp(0.5, cloudCol1, globalLightNow)) 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) 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 // fine-grained
val angleX1 = solarAngleInDeg.toInt() + 75 val angleX1 = (solarAngleInDegInt + 75).coerceAtMost(150)
val angleX2 = (angleX1 + 1).coerceAtMost(150) val angleX2 = (angleX1 + 1).coerceAtMost(150)
val ax = solarAngleInDeg % 1.0 val ax = solarAngleInDeg - solarAngleInDegInt
// fine-grained // fine-grained
val turbY = turbidity.coerceIn(Skybox.turbiditiesD.first(), Skybox.turbiditiesD.last()).minus(1.0).times(Skybox.turbDivisor) val turbY = turbidity.coerceIn(Skybox.turbiditiesD.first(), Skybox.turbiditiesD.last()).minus(1.0).times(Skybox.turbDivisor)
val turbY1 = turbY.floorToInt() val turbY1 = turbY.floorToInt()
@@ -752,7 +763,6 @@ internal object WeatherMixer : RNGConsumer {
val a2t1b2A = colorMap.getCvec(albX2 * elevCnt + angleX2, turbY1) val a2t1b2A = colorMap.getCvec(albX2 * elevCnt + angleX2, turbY1)
val a1t2b2A = colorMap.getCvec(albX2 * elevCnt + angleX1, turbY2) val a1t2b2A = colorMap.getCvec(albX2 * elevCnt + angleX1, turbY2)
val a2t2b2A = colorMap.getCvec(albX2 * elevCnt + angleX2, turbY2) val a2t2b2A = colorMap.getCvec(albX2 * elevCnt + angleX2, turbY2)
val a1t1b1B = colorMap.getCvec(albX1 * elevCnt + angleX1 + Skybox.albedoCnt * elevCnt, turbY1) val a1t1b1B = colorMap.getCvec(albX1 * elevCnt + angleX1 + Skybox.albedoCnt * elevCnt, turbY1)
val a2t1b1B = colorMap.getCvec(albX1 * elevCnt + angleX2 + 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) 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 t2b1A = lerp(ax, a1t2b1A, a2t2b1A)
val t1b2A = lerp(ax, a1t1b2A, a2t1b2A) val t1b2A = lerp(ax, a1t1b2A, a2t1b2A)
val t2b2A = lerp(ax, a1t2b2A, a2t2b2A) 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 t1b1B = lerp(ax, a1t1b1B, a2t1b1B)
val t2b1B = lerp(ax, a1t2b1B, a2t2b1B) val t2b1B = lerp(ax, a1t2b1B, a2t2b1B)
val t1b2B = lerp(ax, a1t1b2B, a2t1b2B) val t1b2B = lerp(ax, a1t1b2B, a2t1b2B)
val t2b2B = lerp(ax, a1t2b2B, a2t2b2B) 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 b1B = lerp(tx, t1b1B, t2b1B)
val b2B = lerp(tx, t1b2B, t2b2B) val b2B = lerp(tx, t1b2B, t2b2B)
val A = lerp(bx, b1A, b2A)
val B = lerp(bx, b1B, b2B) val B = lerp(bx, b1B, b2B)
return lerp(mornNoonBlend, A, B) return lerp(mornNoonBlend, A, B)