mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
each cloud now carry its own gamma value
This commit is contained in:
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<WeatherObjectCloud> {
|
||||
class WeatherObjectCloud(
|
||||
private val texture: TextureRegion,
|
||||
private val flipW: Boolean,
|
||||
private val rgbGamma: Float,
|
||||
private val aGamma: Float
|
||||
) : WeatherObject(), Comparable<WeatherObjectCloud> {
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user