mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-13 20:14:05 +09:00
cloud colour using 'correct' way of lerping for better mix
This commit is contained in:
@@ -82,7 +82,12 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
val globalLightNow = Cvec(0)
|
val globalLightNow = Cvec(0)
|
||||||
private val cloudDrawColour = Color()
|
private val cloudDrawColour = Color()
|
||||||
private val moonlightMax = Cvec(0.23f, 0.24f, 0.25f, 0.21f) // actual moonlight is around ~4100K but our mesopic vision makes it appear blueish (wikipedia: Purkinje effect)
|
private val moonlightMax = Cvec(
|
||||||
|
0.23f,
|
||||||
|
0.24f,
|
||||||
|
0.25f,
|
||||||
|
0.21f
|
||||||
|
) // actual moonlight is around ~4100K but our mesopic vision makes it appear blueish (wikipedia: Purkinje effect)
|
||||||
|
|
||||||
// Weather indices
|
// Weather indices
|
||||||
const val WEATHER_GENERIC = "generic"
|
const val WEATHER_GENERIC = "generic"
|
||||||
@@ -101,7 +106,8 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
it.texture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
|
it.texture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val shaderAstrum = App.loadShaderFromClasspath("shaders/blendSkyboxStars.vert", "shaders/blendSkyboxStars.frag")
|
private val shaderAstrum =
|
||||||
|
App.loadShaderFromClasspath("shaders/blendSkyboxStars.vert", "shaders/blendSkyboxStars.frag")
|
||||||
private val shaderClouds = App.loadShaderFromClasspath("shaders/default.vert", "shaders/clouds.frag")
|
private val shaderClouds = App.loadShaderFromClasspath("shaders/default.vert", "shaders/clouds.frag")
|
||||||
|
|
||||||
private var astrumOffX = 0f
|
private var astrumOffX = 0f
|
||||||
@@ -200,7 +206,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
private fun FloatArray.shiftAndPut(f: Float) {
|
private fun FloatArray.shiftAndPut(f: Float) {
|
||||||
for (k in 1 until this.size) {
|
for (k in 1 until this.size) {
|
||||||
this[k-1] = this[k]
|
this[k - 1] = this[k]
|
||||||
}
|
}
|
||||||
this[this.lastIndex] = f
|
this[this.lastIndex] = f
|
||||||
}
|
}
|
||||||
@@ -241,7 +247,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
private val oldCamPos = Vector2(0f, 0f)
|
private val oldCamPos = Vector2(0f, 0f)
|
||||||
private val camDelta = Vector2(0f, 0f)
|
private val camDelta = Vector2(0f, 0f)
|
||||||
|
|
||||||
val oobMarginR = 1.5f * App.scr.wf
|
val oobMarginR = 1.5f * App.scr.wf
|
||||||
val oobMarginL = -0.5f * App.scr.wf
|
val oobMarginL = -0.5f * App.scr.wf
|
||||||
private val oobMarginY = -0.5f * App.scr.hf
|
private val oobMarginY = -0.5f * App.scr.hf
|
||||||
|
|
||||||
@@ -266,7 +272,8 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
camDelta.set(testCamDelta)
|
camDelta.set(testCamDelta)
|
||||||
|
|
||||||
// try to spawn an cloud
|
// try to spawn an cloud
|
||||||
val cloudChanceEveryMin = 60f / (currentWeather.cloudChance * currentWeather.windSpeed) // if chance = 0, the result will be +inf
|
val cloudChanceEveryMin =
|
||||||
|
60f / (currentWeather.cloudChance * currentWeather.windSpeed) // if chance = 0, the result will be +inf
|
||||||
|
|
||||||
while (cloudUpdateAkku >= cloudChanceEveryMin) {
|
while (cloudUpdateAkku >= cloudChanceEveryMin) {
|
||||||
cloudUpdateAkku -= cloudChanceEveryMin
|
cloudUpdateAkku -= cloudChanceEveryMin
|
||||||
@@ -337,10 +344,16 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
fun takeUniformRand(range: ClosedFloatingPointRange<Float>) =
|
fun takeUniformRand(range: ClosedFloatingPointRange<Float>) =
|
||||||
FastMath.interpolateLinear(Math.random().toFloat(), range.start, range.endInclusive)
|
FastMath.interpolateLinear(Math.random().toFloat(), range.start, range.endInclusive)
|
||||||
|
|
||||||
fun takeTriangularRand(range: ClosedFloatingPointRange<Float>) =
|
fun takeTriangularRand(range: ClosedFloatingPointRange<Float>) =
|
||||||
FastMath.interpolateLinear((Math.random() + Math.random()).div(2f).toFloat(), range.start, range.endInclusive)
|
FastMath.interpolateLinear((Math.random() + Math.random()).div(2f).toFloat(), range.start, range.endInclusive)
|
||||||
|
|
||||||
fun takeGaussianRand(range: ClosedFloatingPointRange<Float>) =
|
fun takeGaussianRand(range: ClosedFloatingPointRange<Float>) =
|
||||||
FastMath.interpolateLinear((Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random()).div(8f).toFloat(), range.start, range.endInclusive)
|
FastMath.interpolateLinear(
|
||||||
|
(Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random()).div(
|
||||||
|
8f
|
||||||
|
).toFloat(), range.start, range.endInclusive
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns random point for clouds to spawn from, in the opposite side of the current wind vector
|
* Returns random point for clouds to spawn from, in the opposite side of the current wind vector
|
||||||
@@ -371,35 +384,45 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
return when (selectedQuadrant.floorToInt()) {
|
return when (selectedQuadrant.floorToInt()) {
|
||||||
-4, 0, 4 -> { // right side of the screen
|
-4, 0, 4 -> { // right side of the screen
|
||||||
val z = FastMath.interpolateLinear(rr, 1f, Z_POW_BASE).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
val z = FastMath.interpolateLinear(rr, 1f, Z_POW_BASE)
|
||||||
|
.pow(1.5f) // clouds are more likely to spawn with low Z-value
|
||||||
val posXscr = App.scr.width + halfCloudSize
|
val posXscr = App.scr.width + halfCloudSize
|
||||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z)
|
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z)
|
||||||
Vector3(x, y, z)
|
Vector3(x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
-3, 1, 5 -> { // z = inf
|
-3, 1, 5 -> { // z = inf
|
||||||
val z = ALPHA_ROLLOFF_Z
|
val z = ALPHA_ROLLOFF_Z
|
||||||
val posXscr = FastMath.interpolateLinear(rr, -halfCloudSize, App.scr.width + halfCloudSize)
|
val posXscr = FastMath.interpolateLinear(rr, -halfCloudSize, App.scr.width + halfCloudSize)
|
||||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM)
|
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM)
|
||||||
Vector3(x, y, z)
|
Vector3(x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
-2, 2, 6 -> { // left side of the screen
|
-2, 2, 6 -> { // left side of the screen
|
||||||
val z = FastMath.interpolateLinear(rr, Z_POW_BASE, 1f).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
val z = FastMath.interpolateLinear(rr, Z_POW_BASE, 1f)
|
||||||
|
.pow(1.5f) // clouds are more likely to spawn with low Z-value
|
||||||
val posXscr = -halfCloudSize
|
val posXscr = -halfCloudSize
|
||||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z)
|
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z)
|
||||||
Vector3(x, y, z)
|
Vector3(x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
-1, 3, 7 -> { // z = 0
|
-1, 3, 7 -> { // z = 0
|
||||||
val posXscr = FastMath.interpolateLinear(rr, -halfCloudSize, App.scr.width + halfCloudSize)
|
val posXscr = FastMath.interpolateLinear(rr, -halfCloudSize, App.scr.width + halfCloudSize)
|
||||||
val z = WeatherObjectCloud.worldYtoWorldZforScreenYof0(y)
|
val z = WeatherObjectCloud.worldYtoWorldZforScreenYof0(y)
|
||||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM)
|
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM)
|
||||||
Vector3(x, y, z)
|
Vector3(x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw InternalError()
|
else -> throw InternalError()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryToSpawnCloud(currentWeather: BaseModularWeather, precalculatedPos: Vector3? = null, ageOverride: Int = 0) {
|
private fun tryToSpawnCloud(
|
||||||
|
currentWeather: BaseModularWeather,
|
||||||
|
precalculatedPos: Vector3? = null,
|
||||||
|
ageOverride: Int = 0
|
||||||
|
) {
|
||||||
// printdbg(this, "Trying to spawn a cloud... (${cloudsSpawned} / ${cloudSpawnMax})")
|
// printdbg(this, "Trying to spawn a cloud... (${cloudsSpawned} / ${cloudSpawnMax})")
|
||||||
|
|
||||||
if (cloudsSpawned < cloudSpawnMax) {
|
if (cloudsSpawned < cloudSpawnMax) {
|
||||||
@@ -472,9 +495,11 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
// it does converge at ~6, but having it as an initial state does not make it stay converged
|
// it does converge at ~6, but having it as an initial state does not make it stay converged
|
||||||
repeat((currentWeather.cloudChance * 1.333f).ceilToInt()) {
|
repeat((currentWeather.cloudChance * 1.333f).ceilToInt()) {
|
||||||
|
|
||||||
val z = takeUniformRand(0.1f..ALPHA_ROLLOFF_Z / 4f - 0.1f).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
val z =
|
||||||
|
takeUniformRand(0.1f..ALPHA_ROLLOFF_Z / 4f - 0.1f).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
||||||
|
|
||||||
val zz = FastMath.interpolateLinear((z / ALPHA_ROLLOFF_Z) * 0.8f + 0.1f, ALPHA_ROLLOFF_Z / 4f, ALPHA_ROLLOFF_Z)
|
val zz =
|
||||||
|
FastMath.interpolateLinear((z / ALPHA_ROLLOFF_Z) * 0.8f + 0.1f, ALPHA_ROLLOFF_Z / 4f, ALPHA_ROLLOFF_Z)
|
||||||
|
|
||||||
val x = WeatherObjectCloud.screenXtoWorldX(takeUniformRand(0f..App.scr.wf), zz)
|
val x = WeatherObjectCloud.screenXtoWorldX(takeUniformRand(0f..App.scr.wf), zz)
|
||||||
|
|
||||||
@@ -485,7 +510,11 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
internal fun titleScreenInitWeather(weatherbox: Weatherbox) {
|
internal fun titleScreenInitWeather(weatherbox: Weatherbox) {
|
||||||
weatherbox.initWith(weatherDict["titlescreen"]!!, Long.MAX_VALUE)
|
weatherbox.initWith(weatherDict["titlescreen"]!!, Long.MAX_VALUE)
|
||||||
forceWindVec = Vector3(-0.98f, 0f, -0.21f).scl(1f/30f) // value taken from TitleScreen.kt; search for 'demoWorld.worldTime.timeDelta = '
|
forceWindVec = Vector3(
|
||||||
|
-0.98f,
|
||||||
|
0f,
|
||||||
|
-0.21f
|
||||||
|
).scl(1f / 30f) // value taken from TitleScreen.kt; search for 'demoWorld.worldTime.timeDelta = '
|
||||||
initClouds(weatherbox.currentWeather)
|
initClouds(weatherbox.currentWeather)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,6 +530,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
private var turbidity0 = 1.0
|
private var turbidity0 = 1.0
|
||||||
private var turbidity1 = 1.0
|
private var turbidity1 = 1.0
|
||||||
|
|
||||||
/** Interpolated value, controlled by the weatherbox */
|
/** Interpolated value, controlled by the weatherbox */
|
||||||
var turbidity = 1.0; private set
|
var turbidity = 1.0; private set
|
||||||
|
|
||||||
@@ -513,6 +543,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
internal var parallaxPos = 0f; private set
|
internal var parallaxPos = 0f; private set
|
||||||
private var solarElev = 0.0
|
private var solarElev = 0.0
|
||||||
private val HALF_DAY = DAY_LENGTH / 2
|
private val HALF_DAY = DAY_LENGTH / 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sub-portion of IngameRenderer. You are not supposed to directly deal with this.
|
* Sub-portion of IngameRenderer. You are not supposed to directly deal with this.
|
||||||
*/
|
*/
|
||||||
@@ -538,7 +569,10 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
batch.shader = shaderClouds
|
batch.shader = shaderClouds
|
||||||
val shadeLum = (globalLightNow.r * 3f + globalLightNow.g * 4f + globalLightNow.b * 1f) / 8f * 0.5f
|
val shadeLum = (globalLightNow.r * 3f + globalLightNow.g * 4f + globalLightNow.b * 1f) / 8f * 0.5f
|
||||||
batch.shader.setUniformf("shadeCol", shadeLum * 1.05f, shadeLum, shadeLum / 1.05f, 1f)
|
batch.shader.setUniformf("shadeCol", shadeLum * 1.05f, shadeLum, shadeLum / 1.05f, 1f)
|
||||||
batch.shader.setUniformf("shadiness", (1.0 / cosh(solarElev * 0.5)).toFloat().coerceAtLeast(if (solarElev < 0) 0.6666f else 0f))
|
batch.shader.setUniformf(
|
||||||
|
"shadiness",
|
||||||
|
(1.0 / cosh(solarElev * 0.5)).toFloat().coerceAtLeast(if (solarElev < 0) 0.6666f else 0f)
|
||||||
|
)
|
||||||
|
|
||||||
clouds.forEach {
|
clouds.forEach {
|
||||||
it.render(batch as UnpackedColourSpriteBatch, cloudDrawColour)
|
it.render(batch as UnpackedColourSpriteBatch, cloudDrawColour)
|
||||||
@@ -581,17 +615,21 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
.| = // parallax of +1
|
.| = // parallax of +1
|
||||||
-+ <- 0.0 =
|
-+ <- 0.0 =
|
||||||
*/
|
*/
|
||||||
val parallax = ((parallaxZeroPos - WorldCamera.gdxCamY.div(TILE_SIZEF)) / parallaxDomainSize).times(-1f).coerceIn(-1f, 1f)
|
val parallax =
|
||||||
val turbidityCoeff = ((parallaxZeroPos - WorldCamera.gdxCamY.div(TILE_SIZEF)) / turbidityDomainSize).times(-1f).coerceIn(-1f, 1f)
|
((parallaxZeroPos - WorldCamera.gdxCamY.div(TILE_SIZEF)) / parallaxDomainSize).times(-1f).coerceIn(-1f, 1f)
|
||||||
|
val turbidityCoeff =
|
||||||
|
((parallaxZeroPos - WorldCamera.gdxCamY.div(TILE_SIZEF)) / turbidityDomainSize).times(-1f).coerceIn(-1f, 1f)
|
||||||
parallaxPos = parallax
|
parallaxPos = parallax
|
||||||
// println(parallax) // parallax value works as intended.
|
// println(parallax) // parallax value works as intended.
|
||||||
|
|
||||||
gdxBlendNormalStraightAlpha()
|
gdxBlendNormalStraightAlpha()
|
||||||
|
|
||||||
val oldNewBlend = weatherbox.weatherBlend.times(2f).coerceAtMost(1f)
|
val oldNewBlend = weatherbox.weatherBlend.times(2f).coerceAtMost(1f)
|
||||||
val mornNoonBlend = (1f/4000f * (timeNow - 43200) + 0.5f).coerceIn(0f, 1f) // 0.0 at T41200; 0.5 at T43200; 1.0 at T45200;
|
val mornNoonBlend =
|
||||||
|
(1f / 4000f * (timeNow - 43200) + 0.5f).coerceIn(0f, 1f) // 0.0 at T41200; 0.5 at T43200; 1.0 at T45200;
|
||||||
|
|
||||||
turbidity0 = (world.weatherbox.oldWeather.json.getDouble("atmoTurbidity") + turbidityCoeff * 2.5).coerceIn(1.0, 10.0)
|
turbidity0 =
|
||||||
|
(world.weatherbox.oldWeather.json.getDouble("atmoTurbidity") + turbidityCoeff * 2.5).coerceIn(1.0, 10.0)
|
||||||
turbidity1 = (currentWeather.json.getDouble("atmoTurbidity") + turbidityCoeff * 2.5).coerceIn(1.0, 10.0)
|
turbidity1 = (currentWeather.json.getDouble("atmoTurbidity") + turbidityCoeff * 2.5).coerceIn(1.0, 10.0)
|
||||||
turbidity = FastMath.interpolateLinear(oldNewBlend.toDouble(), turbidity0, turbidity1)
|
turbidity = FastMath.interpolateLinear(oldNewBlend.toDouble(), turbidity0, turbidity1)
|
||||||
val oldTurbidity = forceTurbidity ?: turbidity0
|
val oldTurbidity = forceTurbidity ?: turbidity0
|
||||||
@@ -606,14 +644,25 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
|
|
||||||
cloudCol1.set(getGradientCloud(skyboxavr, solarElev, mornNoonBlend.toDouble(), turbidity, albedo))
|
cloudCol1.set(getGradientCloud(skyboxavr, solarElev, mornNoonBlend.toDouble(), turbidity, albedo))
|
||||||
cloudCol2.set(getGradientColour2(daylightClut, solarElev + CLOUD_SOLARDEG_OFFSET, timeNow) max globalLightByMoon)
|
cloudCol2.set(
|
||||||
cloudDrawColour.set(lerp(0.5, cloudCol1, cloudCol2))
|
getGradientColour2(
|
||||||
|
daylightClut,
|
||||||
|
solarElev + CLOUD_SOLARDEG_OFFSET,
|
||||||
|
timeNow
|
||||||
|
) max globalLightByMoon
|
||||||
|
)
|
||||||
|
cloudDrawColour.set(srgblerp(0.7, cloudCol1, cloudCol2))
|
||||||
|
|
||||||
|
|
||||||
val gradY = -(gH - App.scr.height) * ((parallax + 1f) / 2f)
|
val gradY = -(gH - App.scr.height) * ((parallax + 1f) / 2f)
|
||||||
|
|
||||||
val (tex, uvs, turbTihsBlend, albThisBlend, turbOldBlend, albOldBlend) = Skybox.getUV(solarElev, oldTurbidity, oldAlbedo, thisTurbidity, thisAlbedo)
|
val (tex, uvs, turbTihsBlend, albThisBlend, turbOldBlend, albOldBlend) = Skybox.getUV(
|
||||||
|
solarElev,
|
||||||
|
oldTurbidity,
|
||||||
|
oldAlbedo,
|
||||||
|
thisTurbidity,
|
||||||
|
thisAlbedo
|
||||||
|
)
|
||||||
|
|
||||||
starmapTex.texture.bind(1)
|
starmapTex.texture.bind(1)
|
||||||
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
|
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
|
||||||
@@ -636,7 +685,8 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
shaderAstrum.setUniformf("texBlend1", turbTihsBlend, albThisBlend, turbOldBlend, albOldBlend)
|
shaderAstrum.setUniformf("texBlend1", turbTihsBlend, albThisBlend, turbOldBlend, albOldBlend)
|
||||||
shaderAstrum.setUniformf("texBlend2", oldNewBlend, mornNoonBlend, 0f, 0f)
|
shaderAstrum.setUniformf("texBlend2", oldNewBlend, mornNoonBlend, 0f, 0f)
|
||||||
shaderAstrum.setUniformf("astrumScroll", astrumOffX + astrumX, astrumOffY + astrumY)
|
shaderAstrum.setUniformf("astrumScroll", astrumOffX + astrumX, astrumOffY + astrumY)
|
||||||
shaderAstrum.setUniformf("randomNumber",
|
shaderAstrum.setUniformf(
|
||||||
|
"randomNumber",
|
||||||
world.worldTime.TIME_T.div(+14.1f).plus(31L),
|
world.worldTime.TIME_T.div(+14.1f).plus(31L),
|
||||||
world.worldTime.TIME_T.div(-13.8f).plus(37L),
|
world.worldTime.TIME_T.div(-13.8f).plus(37L),
|
||||||
world.worldTime.TIME_T.div(+13.9f).plus(23L),
|
world.worldTime.TIME_T.div(+13.9f).plus(23L),
|
||||||
@@ -661,10 +711,10 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
fun colorMix(one: Color, two: Color, scale: Float): Color {
|
fun colorMix(one: Color, two: Color, scale: Float): Color {
|
||||||
return Color(
|
return Color(
|
||||||
FastMath.interpolateLinear(scale, one.r, two.r),
|
FastMath.interpolateLinear(scale, one.r, two.r),
|
||||||
FastMath.interpolateLinear(scale, one.g, two.g),
|
FastMath.interpolateLinear(scale, one.g, two.g),
|
||||||
FastMath.interpolateLinear(scale, one.b, two.b),
|
FastMath.interpolateLinear(scale, one.b, two.b),
|
||||||
FastMath.interpolateLinear(scale, one.a, two.a)
|
FastMath.interpolateLinear(scale, one.a, two.a)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,18 +758,29 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
val pStartRaw = pNowRaw.floorToInt()
|
val pStartRaw = pNowRaw.floorToInt()
|
||||||
val pNextRaw = pStartRaw + 1
|
val pNextRaw = pStartRaw + 1
|
||||||
|
|
||||||
val pSx: Int; val pSy: Int; val pNx: Int; val pNy: Int
|
val pSx: Int;
|
||||||
|
val pSy: Int;
|
||||||
|
val pNx: Int;
|
||||||
|
val pNy: Int
|
||||||
if (timeOfDay < HALF_DAY) {
|
if (timeOfDay < HALF_DAY) {
|
||||||
pSx = pStartRaw.coerceIn(0 until colorMap.width)
|
pSx = pStartRaw.coerceIn(0 until colorMap.width)
|
||||||
pSy = 0
|
pSy = 0
|
||||||
if (pSx == colorMap.width-1) { pNx = pSx; pNy = 1 }
|
if (pSx == colorMap.width - 1) {
|
||||||
else { pNx = pSx + 1; pNy = 0 }
|
pNx = pSx; pNy = 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pNx = pSx + 1; pNy = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pSx = (pStartRaw + 1).coerceIn(0 until colorMap.width)
|
pSx = (pStartRaw + 1).coerceIn(0 until colorMap.width)
|
||||||
pSy = 1
|
pSy = 1
|
||||||
if (pSx == 0) { pNx = 0; pNy = 0 }
|
if (pSx == 0) {
|
||||||
else { pNx = pSx - 1; pNy = 1 }
|
pNx = 0; pNy = 0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pNx = pSx - 1; pNy = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// interpolate R, G, B and A
|
// interpolate R, G, B and A
|
||||||
var scale = (pNowRaw - pStartRaw).toFloat()
|
var scale = (pNowRaw - pStartRaw).toFloat()
|
||||||
@@ -730,13 +791,21 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
val colourThisUV = colorMap.get(pSx, pSy + 2)
|
val colourThisUV = colorMap.get(pSx, pSy + 2)
|
||||||
val colourNextUV = colorMap.get(pNx, pNy + 2)
|
val colourNextUV = colorMap.get(pNx, pNy + 2)
|
||||||
|
|
||||||
val newColRGB = colourThisRGB.cpy().lerp(colourNextRGB, scale)//CIELuvUtil.getGradient(scale, colourThis, colourNext)
|
val newColRGB =
|
||||||
val newColUV = colourThisUV.cpy().lerp(colourNextUV, scale)//CIELuvUtil.getGradient(scale, colourThis, colourNext)
|
colourThisRGB.cpy().lerp(colourNextRGB, scale)//CIELuvUtil.getGradient(scale, colourThis, colourNext)
|
||||||
|
val newColUV =
|
||||||
|
colourThisUV.cpy().lerp(colourNextUV, scale)//CIELuvUtil.getGradient(scale, colourThis, colourNext)
|
||||||
|
|
||||||
return Cvec(newColRGB, newColUV.r)
|
return Cvec(newColRGB, newColUV.r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradientCloud(colorMap: GdxColorMap, solarAngleInDeg0: 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 solarAngleInDeg = solarAngleInDeg0 + CLOUD_SOLARDEG_OFFSET // add a small offset
|
||||||
val solarAngleInDegInt = solarAngleInDeg.floorToInt()
|
val solarAngleInDegInt = solarAngleInDeg.floorToInt()
|
||||||
|
|
||||||
@@ -745,12 +814,14 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
val angleX2 = (angleX1 + 1).coerceAtMost(150)
|
val angleX2 = (angleX1 + 1).coerceAtMost(150)
|
||||||
val ax = solarAngleInDeg - solarAngleInDegInt
|
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()
|
||||||
val turbY2 = (turbY1).coerceAtMost(Skybox.turbCnt - 1)
|
val turbY2 = (turbY1).coerceAtMost(Skybox.turbCnt - 1)
|
||||||
val tx = turbY - turbY1
|
val tx = turbY - turbY1
|
||||||
// coarse-grained
|
// coarse-grained
|
||||||
val albX = albedo.coerceIn(Skybox.albedos.first(), Skybox.albedos.last()).times(5.0) * Skybox.elevCnt // 0*151..5*151
|
val albX =
|
||||||
|
albedo.coerceIn(Skybox.albedos.first(), Skybox.albedos.last()).times(5.0) * Skybox.elevCnt // 0*151..5*151
|
||||||
val albX1 = albX.floorToInt()
|
val albX1 = albX.floorToInt()
|
||||||
val albX2 = (albX1 + 1).coerceAtMost(5 * Skybox.elevCnt)
|
val albX2 = (albX1 + 1).coerceAtMost(5 * Skybox.elevCnt)
|
||||||
val bx = albX - albX1
|
val bx = albX - albX1
|
||||||
@@ -772,6 +843,8 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
val a1t2b2B = colorMap.getCvec(albX2 * elevCnt + angleX1 + Skybox.albedoCnt * elevCnt, turbY2)
|
val a1t2b2B = colorMap.getCvec(albX2 * elevCnt + angleX1 + Skybox.albedoCnt * elevCnt, turbY2)
|
||||||
val a2t2b2B = colorMap.getCvec(albX2 * elevCnt + angleX2 + Skybox.albedoCnt * elevCnt, turbY2)
|
val a2t2b2B = colorMap.getCvec(albX2 * elevCnt + angleX2 + Skybox.albedoCnt * elevCnt, turbY2)
|
||||||
|
|
||||||
|
// no srgblerp here to match the skybox shader's behaviour
|
||||||
|
|
||||||
val t1b1A = lerp(ax, a1t1b1A, a2t1b1A)
|
val t1b1A = lerp(ax, a1t1b1A, a2t1b1A)
|
||||||
val t2b1A = lerp(ax, a1t2b1A, a2t2b1A)
|
val t2b1A = lerp(ax, a1t2b1A, a2t2b1A)
|
||||||
val t1b2A = lerp(ax, a1t1b2A, a2t1b2A)
|
val t1b2A = lerp(ax, a1t1b2A, a2t1b2A)
|
||||||
@@ -793,6 +866,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun lerp(x: Double, c1: Cvec, c2: Cvec): Cvec {
|
private fun lerp(x: Double, c1: Cvec, c2: Cvec): Cvec {
|
||||||
|
// yes I'm well aware that I must do gamma correction before lerping but it's just tooooo slowwww
|
||||||
val r = (((1.0 - x) * c1.r) + (x * c2.r)).toFloat()
|
val r = (((1.0 - x) * c1.r) + (x * c2.r)).toFloat()
|
||||||
val g = (((1.0 - x) * c1.g) + (x * c2.g)).toFloat()
|
val g = (((1.0 - x) * c1.g) + (x * c2.g)).toFloat()
|
||||||
val b = (((1.0 - x) * c1.b) + (x * c2.b)).toFloat()
|
val b = (((1.0 - x) * c1.b) + (x * c2.b)).toFloat()
|
||||||
@@ -800,6 +874,10 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
return Cvec(r, g, b, a)
|
return Cvec(r, g, b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun srgblerp(x: Double, c1: Cvec, c2: Cvec): Cvec {
|
||||||
|
return lerp(x, c1.linearise(), c2.linearise()).unlinearise()
|
||||||
|
}
|
||||||
|
|
||||||
fun getWeatherList(classification: String) = weatherDB[classification]!!
|
fun getWeatherList(classification: String) = weatherDB[classification]!!
|
||||||
fun getRandomWeather(classification: String) =
|
fun getRandomWeather(classification: String) =
|
||||||
getWeatherList(classification)[RNG.nextInt(getWeatherList(classification).size)]
|
getWeatherList(classification)[RNG.nextInt(getWeatherList(classification).size)]
|
||||||
@@ -870,6 +948,37 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
shaderAstrum.dispose()
|
shaderAstrum.dispose()
|
||||||
shaderClouds.dispose()
|
shaderClouds.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Cvec.linearise(): Cvec {
|
||||||
|
val newR = if (r > 0.04045f)
|
||||||
|
((r + 0.055f) / 1.055f).pow(2.4f)
|
||||||
|
else r / 12.92f
|
||||||
|
val newG = if (g > 0.04045f)
|
||||||
|
((g + 0.055f) / 1.055f).pow(2.4f)
|
||||||
|
else g / 12.92f
|
||||||
|
val newB = if (b > 0.04045f)
|
||||||
|
((b + 0.055f) / 1.055f).pow(2.4f)
|
||||||
|
else b / 12.92f
|
||||||
|
|
||||||
|
return Cvec(newR, newG, newB, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Cvec.unlinearise(): Cvec {
|
||||||
|
val newR = if (r > 0.0031308f)
|
||||||
|
1.055f * r.pow(1f / 2.4f) - 0.055f
|
||||||
|
else
|
||||||
|
r * 12.92f
|
||||||
|
val newG = if (g > 0.0031308f)
|
||||||
|
1.055f * g.pow(1f / 2.4f) - 0.055f
|
||||||
|
else
|
||||||
|
g * 12.92f
|
||||||
|
val newB = if (b > 0.0031308f)
|
||||||
|
1.055f * b.pow(1f / 2.4f) - 0.055f
|
||||||
|
else
|
||||||
|
b * 12.92f
|
||||||
|
|
||||||
|
return Cvec(newR, newG, newB, a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class GradientColourMode {
|
enum class GradientColourMode {
|
||||||
|
|||||||
Reference in New Issue
Block a user