randomised weather but i'm just faking it rn

This commit is contained in:
minjaesong
2023-08-23 18:12:32 +09:00
parent 8535b0ce13
commit bf87dc04cb
5 changed files with 168 additions and 61 deletions

View File

@@ -2,15 +2,16 @@
"skyboxGradColourMap": "generic_skybox.tga", "skyboxGradColourMap": "generic_skybox.tga",
"daylightClut": "clut_daylight.tga", "daylightClut": "clut_daylight.tga",
"classification": "generic", "classification": "generic",
"cloudChance": 133, "cloudChance": 500,
"cloudGamma": [0.48, 1.8], "cloudGamma": [0.48, 1.8],
"cloudGammaVariance": [0.1, 0.1], "cloudGammaVariance": [0.1, 0.1],
"windSpeed": 0.16, "windSpeed": 0.16,
"windSpeedVariance": 1.0,
"clouds": { "clouds": {
"cumulonimbus": { "cumulonimbus": {
"filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.25, "filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.2,
"baseScale": 1.0, "scaleVariance": 0.8, "baseScale": 2.0, "scaleVariance": 0.3333333,
"altLow": 80, "altHigh": 600 "altLow": 80, "altHigh": 120
}, },
"cumulus": { "cumulus": {
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 1.0, "filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 1.0,

View File

@@ -248,6 +248,10 @@ final public class FastMath {
return interpolateCatmullRom(u, 0.5f, p0, p1, p2, p3); return interpolateCatmullRom(u, 0.5f, p0, p1, p2, p3);
} }
public static float interpolateCatmullRom(float u, float[] ps) {
return interpolateCatmullRom(u, 0.5f, ps[0], ps[1], ps[2], ps[3]);
}
/**Interpolate a spline between at least 4 control points following the Catmull-Rom equation. /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
* here is the interpolation matrix * here is the interpolation matrix
* m = [ 0.0 1.0 0.0 0.0 ] * m = [ 0.0 1.0 0.0 0.0 ]
@@ -331,8 +335,7 @@ final public class FastMath {
return l; return l;
} }
/*public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3) {
public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3) {
// return interpolateHermite(scale, p0, p1, p2, p3, 0f, 0f); // return interpolateHermite(scale, p0, p1, p2, p3, 0f, 0f);
float mu2 = scale * scale; float mu2 = scale * scale;
float mu3 = mu2 * scale; float mu3 = mu2 * scale;
@@ -350,7 +353,7 @@ final public class FastMath {
float a3 = -2*mu3 + 3*mu2 + 0; float a3 = -2*mu3 + 3*mu2 + 0;
return a0*p1 + a1*m0 + a2*m1 + a3*p2; return a0*p1 + a1*m0 + a2*m1 + a3*p2;
} }*/
//public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3, float tension, float bias) {} //public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3, float tension, float bias) {}

View File

@@ -1,9 +1,12 @@
package net.torvald.terrarum.weather package net.torvald.terrarum.weather
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.math.Vector3
import com.badlogic.gdx.utils.JsonValue import com.badlogic.gdx.utils.JsonValue
import com.jme3.math.FastMath
import net.torvald.terrarum.GdxColorMap import net.torvald.terrarum.GdxColorMap
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import kotlin.math.absoluteValue
/** /**
* Note: Colour maps are likely to have sparse data points * Note: Colour maps are likely to have sparse data points
@@ -13,27 +16,45 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
* Created by minjaesong on 2016-07-11. * Created by minjaesong on 2016-07-11.
*/ */
data class BaseModularWeather( data class BaseModularWeather(
val json: JsonValue, val json: JsonValue,
var skyboxGradColourMap: GdxColorMap, // row 0: skybox grad top, row 1: skybox grad bottom, row 2: sunlight (RGBA) var skyboxGradColourMap: GdxColorMap, // row 0: skybox grad top, row 1: skybox grad bottom, row 2: sunlight (RGBA)
val daylightClut: GdxColorMap, val daylightClut: GdxColorMap,
val classification: String, val classification: String,
val cloudChance: Float, val cloudChance: Float,
val windSpeed: Float, val windSpeed: Float,
val cloudGamma: Vector2, val windSpeedVariance: Float,
val cloudGammaVariance: Vector2, val cloudGamma: Vector2,
var clouds: List<CloudProps>, // sorted by CloudProps.probability val cloudGammaVariance: Vector2,
var clouds: List<CloudProps>, // sorted by CloudProps.probability
val mixFrom: String? = null, val mixFrom: String? = null,
val mixPercentage: Double? = null val mixPercentage: Double? = null,
)
var forceWindVec: Vector3? = null
) {
/**
* @param rnd random number between -1 and +1
*/
fun getRandomWindSpeed(rnd: Float): Float {
val v = 1f + rnd.absoluteValue * windSpeedVariance
return if (rnd < 0) windSpeed / v else windSpeed * v
}
}
data class CloudProps( data class CloudProps(
val category: String, val category: String,
val spriteSheet: TextureRegionPack, val spriteSheet: TextureRegionPack,
val probability: Float, val probability: Float,
val baseScale: Float, val baseScale: Float,
val scaleVariance: Float, val scaleVariance: Float,
val altLow: Float, val altLow: Float,
val altHigh: Float, val altHigh: Float,
) { ) {
/**
* @param rnd random number between -1 and +1
*/
fun getCloudScaleVariance(rnd: Float): Float {
val v = 1f + rnd.absoluteValue * scaleVariance
return if (rnd < 0) baseScale / v else baseScale * v
}
} }

View File

@@ -19,6 +19,7 @@ import net.torvald.terrarum.gameworld.WorldTime
import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH
import net.torvald.terrarum.RNGConsumer import net.torvald.terrarum.RNGConsumer
import net.torvald.terrarum.clut.Skybox import net.torvald.terrarum.clut.Skybox
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
import net.torvald.terrarum.utils.JsonFetcher import net.torvald.terrarum.utils.JsonFetcher
import net.torvald.terrarum.utils.forEachSiblings import net.torvald.terrarum.utils.forEachSiblings
import net.torvald.terrarum.weather.WeatherObjectCloud.Companion.ALPHA_ROLLOFF_Z import net.torvald.terrarum.weather.WeatherObjectCloud.Companion.ALPHA_ROLLOFF_Z
@@ -31,9 +32,7 @@ import java.lang.Double.doubleToLongBits
import java.lang.Math.toDegrees import java.lang.Math.toDegrees
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.math.absoluteValue import kotlin.math.*
import kotlin.math.atan2
import kotlin.math.pow
/** /**
* Currently there is a debate whether this module must be part of the engine or the basegame * Currently there is a debate whether this module must be part of the engine or the basegame
@@ -92,7 +91,7 @@ internal object WeatherMixer : RNGConsumer {
private val clouds = SortedArrayList<WeatherObjectCloud>() private val clouds = SortedArrayList<WeatherObjectCloud>()
var cloudsSpawned = 0; private set var cloudsSpawned = 0; private set
private var cloudDriftVector = Vector3(-1f, 0f, 0.1f) // this is a direction vector private var windVector = Vector3(-1f, 0f, 0.1f) // this is a direction vector
val cloudSpawnMax: Int val cloudSpawnMax: Int
get() = 256 shl (App.getConfigInt("maxparticles") / 256) get() = 256 shl (App.getConfigInt("maxparticles") / 256)
@@ -116,8 +115,10 @@ internal object WeatherMixer : RNGConsumer {
clouds.clear() clouds.clear()
cloudsSpawned = 0 cloudsSpawned = 0
cloudDriftVector = Vector3(-0.98f, 0f, 0.21f) windVector = Vector3(-0.98f, 0f, 0.21f)
// cloudDriftVector = Vector3(-1f, 0f, -1f)
windDirWindow = null
windSpeedWindow = null
oldCamPos.set(WorldCamera.camVector) oldCamPos.set(WorldCamera.camVector)
} }
@@ -165,6 +166,7 @@ internal object WeatherMixer : RNGConsumer {
"default", "default",
0f, 0f,
0f, 0f,
0f,
Vector2(1f, 1f), Vector2(1f, 1f),
Vector2(0f, 0f), Vector2(0f, 0f),
listOf() listOf()
@@ -183,6 +185,7 @@ internal object WeatherMixer : RNGConsumer {
// currentWeather = weatherList[WEATHER_GENERIC]!![0] // force set weather // currentWeather = weatherList[WEATHER_GENERIC]!![0] // force set weather
updateWind(delta, world)
updateClouds(delta, world) updateClouds(delta, world)
@@ -192,6 +195,81 @@ internal object WeatherMixer : RNGConsumer {
} }
private fun FloatArray.shiftAndPut(f: Float) {
for (k in 1 until this.size) {
this[k-1] = this[k]
}
this[this.lastIndex] = f
}
private val PI = 3.1415927f
private val TWO_PI = 6.2831855f
private val THREE_PI = 9.424778f
private var windDirWindow: FloatArray? = null
private var windSpeedWindow: FloatArray? = null
private val WIND_DIR_TIME_UNIT = 14400 // every 4hr
private val WIND_SPEED_TIME_UNIT = 3600 // every 1hr
private var windDirAkku = 0 // only needed if timeDelta is not divisible by WIND_TIME_UNIT
private var windSpeedAkku = 0
// see: https://stackoverflow.com/questions/2708476/rotation-interpolation/14498790#14498790
private fun getShortestAngle(start: Float, end: Float) =
(((((end - if (start < 0f) TWO_PI + start else start) % TWO_PI) + THREE_PI) % TWO_PI) - PI).let {
if (it > PI) it - TWO_PI else it
}
private fun updateWind(delta: Float, world: GameWorld) {
if (windDirWindow == null) {
windDirWindow = FloatArray(4) { takeUniformRand(-PI..PI) } // completely random regardless of the seed
}
if (windSpeedWindow == null) {
windSpeedWindow = FloatArray(4) { currentWeather.getRandomWindSpeed(takeTriangularRand(-1f..1f)) } // completely random regardless of the seed
}
val windDirStep = windDirAkku / WIND_DIR_TIME_UNIT.toFloat()
val windSpeedStep = windSpeedAkku / WIND_SPEED_TIME_UNIT.toFloat()
// val angle0 = windDirWindow[0]
// val angle1 = getShortestAngle(angle0, windDirWindow[1])
// val angle2 = getShortestAngle(angle1, windDirWindow[2])
// val angle3 = getShortestAngle(angle2, windDirWindow[3])
// val fixedAngles = floatArrayOf(angle0, angle1, angle2, angle3)
val currentWindDir = FastMath.interpolateCatmullRom(windDirStep, windDirWindow)
val currentWindSpeed = FastMath.interpolateCatmullRom(windSpeedStep, windSpeedWindow)
printdbg(this,
"dir ${Math.toDegrees(currentWindDir.toDouble()).roundToInt()}\t" +
"spd ${currentWindSpeed.times(10f).roundToInt().div(10f)}\t " +
"dirs ${windDirWindow!!.map { Math.toDegrees(it.toDouble()).roundToInt() }} ${windDirStep.times(100).roundToInt()}\t" +
"spds ${windSpeedWindow!!.map { it.times(10f).roundToInt().div(10f) }} ${windSpeedStep.times(100).roundToInt()}"
)
if (currentWeather.forceWindVec != null) {
windVector.set(currentWeather.forceWindVec)
}
else {
windVector.set(
cos(currentWindDir) * currentWindSpeed,
0f,
sin(currentWindDir) * currentWindSpeed
)
}
while (windDirAkku >= WIND_DIR_TIME_UNIT) {
windDirAkku -= WIND_DIR_TIME_UNIT
windDirWindow!!.shiftAndPut(takeUniformRand(-PI..PI))
}
while (windSpeedAkku >= WIND_SPEED_TIME_UNIT) {
windSpeedAkku -= WIND_SPEED_TIME_UNIT
windSpeedWindow!!.shiftAndPut(currentWeather.getRandomWindSpeed(takeTriangularRand(-1f..1f)))
}
windDirAkku += world.worldTime.timeDelta
windSpeedAkku += world.worldTime.timeDelta
}
private val cloudParallaxMultY = -0.035f private val cloudParallaxMultY = -0.035f
private val cloudParallaxMultX = -0.035f private val cloudParallaxMultX = -0.035f
private var cloudUpdateAkku = 0f private var cloudUpdateAkku = 0f
@@ -234,7 +312,7 @@ internal object WeatherMixer : RNGConsumer {
it.posY += camDelta.y * cloudParallaxMultY it.posY += camDelta.y * cloudParallaxMultY
it.update(cloudDriftVector, currentWeather.windSpeed) it.update(windVector)
if (it.life == 0) immDespawnCount += 1 if (it.life == 0) immDespawnCount += 1
} }
@@ -266,13 +344,6 @@ internal object WeatherMixer : RNGConsumer {
private val scrHscaler = App.scr.height / 720f private val scrHscaler = App.scr.height / 720f
private val cloudSizeMult = App.scr.wf / TerrarumScreenSize.defaultW private val cloudSizeMult = App.scr.wf / TerrarumScreenSize.defaultW
/**
* @param range: range of the randomised number
* @param random: random number in the range of `[-1, 1]`
*/
private fun randomPosWithin(range: ClosedFloatingPointRange<Float>, random: Float) =
((range.start + range.endInclusive) / 2f) + random * (range.endInclusive - range.start) / 2f
private fun takeUniformRand(range: ClosedFloatingPointRange<Float>) = private fun takeUniformRand(range: ClosedFloatingPointRange<Float>) =
FastMath.interpolateLinear(Math.random().toFloat(), range.start, range.endInclusive) FastMath.interpolateLinear(Math.random().toFloat(), range.start, range.endInclusive)
private fun takeTriangularRand(range: ClosedFloatingPointRange<Float>) = private fun takeTriangularRand(range: ClosedFloatingPointRange<Float>) =
@@ -284,7 +355,8 @@ internal object WeatherMixer : RNGConsumer {
* 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
*/ */
private fun getCloudSpawningPosition(cloud: CloudProps, halfCloudSize: Float, windVector: Vector3): Vector3 { private fun getCloudSpawningPosition(cloud: CloudProps, halfCloudSize: Float, windVector: Vector3): Vector3 {
val y = randomPosWithin(-cloud.altHigh..-cloud.altLow, takeUniformRand(-1f..1f)) * scrHscaler val Z_LIM = ALPHA_ROLLOFF_Z/2f
val y = takeUniformRand(-cloud.altHigh..-cloud.altLow) * scrHscaler
var windVectorDir = toDegrees(atan2(windVector.z.toDouble(), windVector.x.toDouble())).toFloat() + 180f var windVectorDir = toDegrees(atan2(windVector.z.toDouble(), windVector.x.toDouble())).toFloat() + 180f
if (windVectorDir < 0f) windVectorDir += 360f if (windVectorDir < 0f) windVectorDir += 360f
@@ -293,33 +365,40 @@ internal object WeatherMixer : RNGConsumer {
// an "edge" is a line of length 1 drawn into the edge of the square of size 1 (its total edge length will be 4) // an "edge" is a line of length 1 drawn into the edge of the square of size 1 (its total edge length will be 4)
// when the windVectorDir is not an integer, the "edge" will take the shape similar to this: ¬ // when the windVectorDir is not an integer, the "edge" will take the shape similar to this: ¬
// 'rr' is a point on the "edge", where 0.5 is a middle point in its length // 'rr' is a point on the "edge", where 0.5 is a middle point in its length
val rl = (windVectorDir % 1f).let { if (it < 0.5f) -it else it - 1f } // val rl = (windVectorDir % 1f).let { if (it < 0.5f) -it else it - 1f }.toInt()
val rh = 1f + (windVectorDir % 1f).let { if (it < 0.5f) it else 1f - it } // val rh = 1 + (windVectorDir % 1f).let { if (it < 0.5f) it else 1f - it }.toInt()
val rr = windVectorDir + takeUniformRand(rl..rh)
// printdbg(this, "${windVectorDir + rl}..${windVectorDir + rh} / $rr") // choose between rl and rh using (windVectorDir % 1f) as a pivot
val Z_LIM = ALPHA_ROLLOFF_Z/2f // if pivot = 0.3, rL is 70%, and rR is 30% likely
return when (rr.toInt()) { // plug the vote result into the when()
val selectedQuadrant = takeUniformRand((windVectorDir % 1f)..(windVectorDir % 1f) + 1f)
// printdbg(this, "Dir: $windVectorDir, Rand(${windVectorDir % 1f}..${(windVectorDir % 1f) + 1f}) = $selectedQuadrant")
val rr = takeUniformRand(0f..1f)
return when (selectedQuadrant.toInt()) {
0, 4 -> { // right side of the screen 0, 4 -> { // right side of the screen
val z = FastMath.interpolateLinear(rr % 1f, 1f, ALPHA_ROLLOFF_Z).pow(1.5f) // clouds are more likely to spawn with low Z-value val z = FastMath.interpolateLinear(rr, 1f, ALPHA_ROLLOFF_Z).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)
} }
1, 5 -> { // z = inf 1, 5 -> { // z = inf
val z = ALPHA_ROLLOFF_Z val z = ALPHA_ROLLOFF_Z
val posXscr = FastMath.interpolateLinear(rr % 1f, App.scr.width + halfCloudSize, -halfCloudSize) val posXscr = FastMath.interpolateLinear(rr, App.scr.width + halfCloudSize, -halfCloudSize)
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM) val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM)
Vector3(x, y, z) Vector3(x, y, z)
} }
2, 6 -> { // left side of the screen 2, 6 -> { // left side of the screen
val z = FastMath.interpolateLinear(rr % 1f, ALPHA_ROLLOFF_Z, 1f).pow(1.5f) // clouds are more likely to spawn with low Z-value val z = FastMath.interpolateLinear(rr, ALPHA_ROLLOFF_Z, 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)
} }
3, 7 -> { // z = 0 3, 7 -> { // z = 0
val z = 0.1f val z = 0.1f
val posXscr = FastMath.interpolateLinear(rr % 1f, -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)
} }
@@ -352,8 +431,7 @@ internal object WeatherMixer : RNGConsumer {
} }
cloudsToSpawn?.let { cloud -> cloudsToSpawn?.let { cloud ->
val scaleVariance = 1f + rT1.absoluteValue * cloud.scaleVariance val cloudScale = cloud.getCloudScaleVariance(rT1)
val cloudScale = cloud.baseScale * (if (rT1 < 0) 1f / scaleVariance else scaleVariance)
val hCloudSize = (cloud.spriteSheet.tileW * cloudScale) / 2f + 1f val hCloudSize = (cloud.spriteSheet.tileW * cloudScale) / 2f + 1f
// val posXscr = initX ?: if (cloudDriftVector.x < 0) (App.scr.width + hCloudSize) else -hCloudSize // val posXscr = initX ?: if (cloudDriftVector.x < 0) (App.scr.width + hCloudSize) else -hCloudSize
@@ -365,11 +443,11 @@ internal object WeatherMixer : RNGConsumer {
WeatherObjectCloud(cloud.spriteSheet.get(sheetX, sheetY), flip).also { WeatherObjectCloud(cloud.spriteSheet.get(sheetX, sheetY), flip).also {
it.scale = cloudScale * cloudSizeMult it.scale = cloudScale * cloudSizeMult
it.pos.set(precalculatedPos ?: getCloudSpawningPosition(cloud, hCloudSize, cloudDriftVector)) it.pos.set(precalculatedPos ?: getCloudSpawningPosition(cloud, hCloudSize, windVector))
// further set the random altitude if required // further set the random altitude if required
if (precalculatedPos != null) { if (precalculatedPos != null) {
it.pos.y = randomPosWithin(-cloud.altHigh..-cloud.altLow, takeUniformRand(-1f..1f)) * scrHscaler it.pos.y = takeUniformRand(-cloud.altHigh..-cloud.altLow) * scrHscaler
} }
clouds.add(it) clouds.add(it)
@@ -385,10 +463,12 @@ internal object WeatherMixer : RNGConsumer {
private fun initClouds() { private fun initClouds() {
val hCloudSize = 1024f val hCloudSize = 1024f
repeat((currentWeather.cloudChance * 3.3f).ceilToInt()) { // multiplier is an empirical value that depends on the 'rZ' // multiplier is an empirical value that depends on the 'rZ'
// it does converge at ~6, but having it as an initial state does not make it stay converged
repeat((currentWeather.cloudChance * 1.333f).ceilToInt()) {
val posXscr = FastMath.interpolateLinear(takeUniformRand(0f..1f), -hCloudSize, App.scr.width + hCloudSize) val posXscr = FastMath.interpolateLinear(takeUniformRand(0f..1f), -hCloudSize, App.scr.width + hCloudSize)
val z = takeUniformRand(1f..ALPHA_ROLLOFF_Z/4f).pow(1.5f) // clouds are more likely to spawn with low Z-value val z = takeUniformRand(0.1f..ALPHA_ROLLOFF_Z - 0.1f).pow(1.5f) // clouds are more likely to spawn with low Z-value
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z) val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z)
tryToSpawnCloud(currentWeather, Vector3(x, 0f, z)) tryToSpawnCloud(currentWeather, Vector3(x, 0f, z))
@@ -397,6 +477,7 @@ internal object WeatherMixer : RNGConsumer {
internal fun titleScreenInitWeather() { internal fun titleScreenInitWeather() {
currentWeather = weatherList["titlescreen"]!![0] currentWeather = weatherList["titlescreen"]!![0]
currentWeather.forceWindVec = Vector3(-0.98f, 0f, 0.21f)
initClouds() initClouds()
} }
@@ -687,6 +768,7 @@ internal object WeatherMixer : RNGConsumer {
classification = classification, classification = classification,
cloudChance = JSON.getFloat("cloudChance"), cloudChance = JSON.getFloat("cloudChance"),
windSpeed = JSON.getFloat("windSpeed"), windSpeed = JSON.getFloat("windSpeed"),
windSpeedVariance = JSON.getFloat("windSpeedVariance"),
cloudGamma = JSON["cloudGamma"].asFloatArray().let { Vector2(it[0], it[1]) }, cloudGamma = JSON["cloudGamma"].asFloatArray().let { Vector2(it[0], it[1]) },
cloudGammaVariance = JSON["cloudGammaVariance"].asFloatArray().let { Vector2(it[0], it[1]) }, cloudGammaVariance = JSON["cloudGammaVariance"].asFloatArray().let { Vector2(it[0], it[1]) },
clouds = cloudsMap, clouds = cloudsMap,

View File

@@ -27,14 +27,14 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW:
* FlowVector: In which direction the cloud flows. Vec3(dX, dY, dScale) * FlowVector: In which direction the cloud flows. Vec3(dX, dY, dScale)
* Resulting vector: (x + dX, y + dY, scale * dScale) * Resulting vector: (x + dX, y + dY, scale * dScale)
*/ */
fun update(flowVector: Vector3, gait: Float) { fun update(flowVector: Vector3) {
pos.add( pos.add(
flowVector.cpy(). 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(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(gait) scl(vecMult)
) )
alpha = if (posZ < 1f) posZ.pow(0.5f) else -(posZ / ALPHA_ROLLOFF_Z) + 1f alpha = if (posZ < 1f) posZ.pow(0.5f) else -((posZ - 1f) / ALPHA_ROLLOFF_Z) + 1f
val lrCoord = screenCoordBottomLRforDespawnCalculation val lrCoord = screenCoordBottomLRforDespawnCalculation
if (lrCoord.x > WeatherMixer.oobMarginR || lrCoord.z < WeatherMixer.oobMarginL || posZ !in 0.0001f..ALPHA_ROLLOFF_Z + 1f || alpha < 0f) { if (lrCoord.x > WeatherMixer.oobMarginR || lrCoord.z < WeatherMixer.oobMarginL || posZ !in 0.0001f..ALPHA_ROLLOFF_Z + 1f || alpha < 0f) {
@@ -47,7 +47,7 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW:
private val w = App.scr.halfwf private val w = App.scr.halfwf
private val h = App.scr.hf * 0.5f private val h = App.scr.hf * 0.5f
private val vecMult = Vector3(1f, 1f, 1f / (2f * h)) private val vecMult = Vector3(1f, 1f, 1f / (4f * h))
/** /**
* X/Y position is a bottom-centre point of the image * X/Y position is a bottom-centre point of the image