each cloud now carry its own gamma value

This commit is contained in:
minjaesong
2023-09-02 02:40:27 +09:00
parent 721a24d9dc
commit 78075d779b
9 changed files with 157 additions and 35 deletions

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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(

View File

@@ -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)
}
}
}

View File

@@ -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
)
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;
}