skybox: two different setup for AM/PN

This commit is contained in:
minjaesong
2023-08-06 15:50:04 +09:00
parent 52ad8f0c46
commit 30fb57eca3
7 changed files with 115 additions and 64 deletions

Binary file not shown.

View File

@@ -0,0 +1,31 @@
{
"GAME_ITEM_CALENDAR": "Calendar",
"MENU_CALENDAR_CALENDAR": "Calendar",
"MENU_CALENDAR_EVENTS": "Events",
"MENU_CALENDAR_ADD_NEW_EVENT": "Add New Event…",
"CONTEXT_CALENDAR_SEASON_SPRING": "Spring",
"CONTEXT_CALENDAR_SEASON_SUMMER": "Summer",
"CONTEXT_CALENDAR_SEASON_AUTUMN": "Autumn",
"CONTEXT_CALENDAR_SEASON_WINTER": "Winter",
"CONTEXT_CALENDAR_SEASON_SPRI": "Spri",
"CONTEXT_CALENDAR_SEASON_SUMM": "Summ",
"CONTEXT_CALENDAR_SEASON_AUTM": "Autm",
"CONTEXT_CALENDAR_SEASON_WINT": "Wint",
"CONTEXT_CALENDAR_DAY_MONDAG_DNT": "Mondag",
"CONTEXT_CALENDAR_DAY_TYSDAG_DNT": "Tysdag",
"CONTEXT_CALENDAR_DAY_MIDTVEKE_DNT": "Midtveke",
"CONTEXT_CALENDAR_DAY_TORSDAG_DNT": "Torsdag",
"CONTEXT_CALENDAR_DAY_FREDAG_DNT": "Fredag",
"CONTEXT_CALENDAR_DAY_LAURDAG_DNT": "Laurdag",
"CONTEXT_CALENDAR_DAY_SUNDAG_DNT": "Sundag",
"CONTEXT_CALENDAR_DAY_VERDDAG_DNT": "Verddag",
"CONTEXT_CALENDAR_DAY_MON_DNT": "Mon",
"CONTEXT_CALENDAR_DAY_TYS_DNT": "Tys",
"CONTEXT_CALENDAR_DAY_MID_DNT": "Mid",
"CONTEXT_CALENDAR_DAY_TOR_DNT": "Tor",
"CONTEXT_CALENDAR_DAY_FRE_DNT": "Fre",
"CONTEXT_CALENDAR_DAY_LAU_DNT": "Lau",
"CONTEXT_CALENDAR_DAY_SUN_DNT": "Sun",
"CONTEXT_CALENDAR_DAY_VER_DNT": "Ver"
}

View File

@@ -0,0 +1,14 @@
{
"GAME_ITEM_CALENDAR": "달력",
"MENU_CALENDAR_CALENDAR": "달력",
"MENU_CALENDAR_EVENTS": "일정",
"MENU_CALENDAR_ADD_NEW_EVENT": "새 일정 추가…",
"CONTEXT_CALENDAR_SEASON_SPRING": "봄",
"CONTEXT_CALENDAR_SEASON_SUMMER": "여름",
"CONTEXT_CALENDAR_SEASON_AUTUMN": "가을",
"CONTEXT_CALENDAR_SEASON_WINTER": "겨울",
"CONTEXT_CALENDAR_SEASON_SPRI": "봄",
"CONTEXT_CALENDAR_SEASON_SUMM": "여름",
"CONTEXT_CALENDAR_SEASON_AUTM": "가을",
"CONTEXT_CALENDAR_SEASON_WINT": "겨울"
}

View File

@@ -19,7 +19,7 @@ fun main() {
// y: increasing turbidity (1.0 .. 10.0, in steps of 0.333)
// x: elevations (-75 .. 75 in steps of 1, then albedo of [0.1, 0.3, 0.5, 0.7, 0.9])
val texh = Skybox.gradSize * Skybox.turbCnt
val texw = Skybox.elevCnt * Skybox.albedoCnt
val texw = Skybox.elevCnt * Skybox.albedoCnt * 2
val TGA_HEADER_SIZE = 18
val bytes = ByteArray(TGA_HEADER_SIZE + texw * texh * 4 + 26)
@@ -44,47 +44,50 @@ fun main() {
println("Generating texture atlas ($texw x $texh)...")
// write pixels
for (albedo0 in 0 until Skybox.albedoCnt) {
val albedo = Skybox.albedos[albedo0]
println("Albedo=$albedo")
for (turb0 in 0 until Skybox.turbCnt) {
val turbidity = Skybox.turbiditiesD[turb0]
println("....... Turbidity=$turbidity")
for (elev0 in 0 until Skybox.elevCnt) {
val elevationDeg = Skybox.elevationsD[elev0]
val elevationRad = Math.toRadians(elevationDeg)
for (gammaPair in 0..1) {
for (albedo0 in 0 until Skybox.albedoCnt) {
val albedo = Skybox.albedos[albedo0]
println("Albedo=$albedo")
for (turb0 in 0 until Skybox.turbCnt) {
val turbidity = Skybox.turbiditiesD[turb0]
println("....... Turbidity=$turbidity")
for (elev0 in 0 until Skybox.elevCnt) {
val elevationDeg = Skybox.elevationsD[elev0]
val elevationRad = Math.toRadians(elevationDeg)
// println("... Elevation: $elevationDeg")
val state = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
val state =
ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
for (yp in 0 until Skybox.gradSize) {
val yi = yp - 3
val xf = -elevationDeg / 90.0
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
for (yp in 0 until Skybox.gradSize) {
val yi = yp - 3
val xf = -elevationDeg / 90.0
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
// if (elevationDeg < 0) yf *= 1.0 - pow(xf, 0.333)
// if (elevationDeg < 0) yf *= -2.0 * asin(xf - 1.0) / PI
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
val theta = yf * HALF_PI
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
val theta = yf * HALF_PI
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
// println("$yp\t$theta")
val xyz = CIEXYZ(
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, HALF_PI, 0).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, HALF_PI, 1).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, HALF_PI, 2).toFloat()
)
val xyz2 = xyz.scaleToFit(elevationDeg)
val rgb = xyz2.toRGB().toColor()
val colour = rgb.toIntBits().toLittle()
val xyz = CIEXYZ(
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 0).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 1).toFloat(),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 2).toFloat()
)
val xyz2 = xyz.scaleToFit(elevationDeg)
val rgb = xyz2.toRGB().toColor()
val colour = rgb.toIntBits().toLittle()
val imgOffX = (albedo0 * Skybox.elevCnt + elev0)
val imgOffY = texh - 1 - (Skybox.gradSize * turb0 + yp)
val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX)
for (i in 0..3) {
bytes[fileOffset + i] = colour[bytesLut[i]]
val imgOffX = albedo0 * Skybox.elevCnt + elev0 + Skybox.elevCnt * Skybox.albedoCnt * gammaPair
val imgOffY = texh - 1 - (Skybox.gradSize * turb0 + yp)
val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX)
for (i in 0..3) {
bytes[fileOffset + i] = colour[bytesLut[i]]
}
}
}
}

View File

@@ -13,6 +13,7 @@ import net.torvald.parametricsky.ArHosekSkyModel
import net.torvald.terrarum.App
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.abs
import net.torvald.terrarum.toInt
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import kotlin.math.*
@@ -50,28 +51,24 @@ object Skybox : Disposable {
}*/
// use external LUT
operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double): TextureRegion {
val elev = elevationDeg.coerceIn(-elevMax, elevMax).roundToInt().plus(elevMax).roundToInt()
val turb = turbidity.coerceIn(1.0, 10.0).minus(1.0).times(turbDivisor).roundToInt()
val alb = albedo.coerceIn(0.1, 0.9).minus(0.1).times(turbDivisor).roundToInt()
//printdbg(this, "elev $elevationDeg->$elev; turb $turbidity->$turb; alb $albedo->$alb")
return texRegions.get(alb * elevCnt + elev, turb)
operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double, isAfternoon: Boolean): TextureRegion {
TODO()
}
fun getUV(elevationDeg: Double, turbidity: Double, albedo: Double): Pair<Texture, FloatArray> {
val turb = turbidity.coerceIn(1.0, 10.0).minus(1.0).times(turbDivisor).roundToInt()
val alb = albedo.coerceIn(0.1, 0.9).minus(0.1).times(turbDivisor).roundToInt()
val region = texStripRegions.get(alb, turb)
val alb = albedo.coerceIn(0.0, 1.0).times(turbDivisor).roundToInt()
val region1 = texStripRegions.get(alb + albedoCnt * 0, turb) // left half of the sheet
val region2 = texStripRegions.get(alb + albedoCnt * 1, turb) // right half of the sheet
val elev = elevationDeg.coerceIn(-elevMax, elevMax).plus(elevMax).div(elevations.last.toDouble()).div(albedoCnt).times((elevCnt - 1.0) / elevCnt)
val elev = elevationDeg.coerceIn(-elevMax, elevMax).plus(elevMax).div(elevations.last.toDouble()).div(albedoCnt * 2).times((elevCnt - 1.0) / elevCnt)
val u = region.u + (0.5f / tex.width) + elev.toFloat() // because of the nature of bilinear interpolation, half pixels from the edges must be discarded
val uA = region1.u + (0.5f / tex.width) + elev.toFloat() // because of the nature of bilinear interpolation, half pixels from the edges must be discarded
val uB = region2.u + (0.5f / tex.width) + elev.toFloat() // because of the nature of bilinear interpolation, half pixels from the edges must be discarded
return tex to floatArrayOf(
u,
region.v,
u,
region.v2
uA, region1.v, uA, region1.v2,
uB, region2.v, uB, region2.v2,
)
}
@@ -113,7 +110,7 @@ object Skybox : Disposable {
val turbidities = (0..45) // 1, 1.2, 1.4, 1.6, ..., 10.0
val turbDivisor = 5.0
val turbiditiesD = turbidities.map { 1.0 + it / turbDivisor }
val albedos = arrayOf(0.1, 0.3, 0.5, 0.7, 0.9)
val albedos = arrayOf(0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0)
val elevCnt = elevations.count()
val turbCnt = turbidities.count()
val albedoCnt = albedos.size

View File

@@ -208,8 +208,10 @@ internal object WeatherMixer : RNGConsumer {
// TODO trilinear with (deg, turb, alb)
val gradY = -(gH - App.scr.height) * ((parallax + 1f) / 2f)
val (tex, uvs) = Skybox.getUV(solarElev, thisTurbidity, 0.3)
val texBlend = (1f/4000f * (timeNow - 43200) + 0.5f).coerceIn(0f, 1f) // 0.0 at T41200; 0.5 at T43200; 1.0 at T45200;
starmapTex.texture.bind(1)
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
@@ -220,20 +222,20 @@ internal object WeatherMixer : RNGConsumer {
batch.inUse {
batch.shader = shaderBlendMax
shaderBlendMax.setUniformi("tex1", 1)
shaderBlendMax.setUniformf("drawOffset", 0f, gradY)
shaderBlendMax.setUniformf("drawOffsetSize", App.scr.wf, gH)
shaderBlendMax.setUniform2fv("skyboxUV1", uvs, 0, 2)
shaderBlendMax.setUniform2fv("skyboxUV2", uvs, 2, 2)
shaderBlendMax.setUniformf("drawOffsetSize", 0f, gradY, App.scr.wf, gH)
shaderBlendMax.setUniform4fv("skyboxUV1", uvs, 0, 4)
shaderBlendMax.setUniform4fv("skyboxUV2", uvs, 4, 4)
shaderBlendMax.setUniformf("texBlend", texBlend)
shaderBlendMax.setUniformf("astrumScroll", astrumOffX + astrumX, astrumOffY + astrumY)
shaderBlendMax.setUniformf("randomNumber",
// (world.worldTime.TIME_T.plus(31L) xor 1453L + 31L).and(1023).toFloat(),
// (world.worldTime.TIME_T.plus(37L) xor 862L + 31L).and(1023).toFloat(),
// (world.worldTime.TIME_T.plus(23L) xor 1639L + 29L).and(1023).toFloat(),
// (world.worldTime.TIME_T.plus(29L) xor 2971L + 41L).and(1023).toFloat(),
world.worldTime.TIME_T.div(+12.1f).plus(31L),
world.worldTime.TIME_T.div(-11.8f).plus(37L),
world.worldTime.TIME_T.div(+11.9f).plus(23L),
world.worldTime.TIME_T.div(-12.3f).plus(29L),
world.worldTime.TIME_T.div(+14.1f).plus(31L),
world.worldTime.TIME_T.div(-13.8f).plus(37L),
world.worldTime.TIME_T.div(+13.9f).plus(23L),
world.worldTime.TIME_T.div(-14.3f).plus(29L),
)
batch.color = Color.WHITE

View File

@@ -13,10 +13,10 @@ out vec4 fragColor;
const vec2 boolean = vec2(0.0, 1.0);
uniform vec2 drawOffset; // value of the 'gradY'
uniform vec2 drawOffsetSize; // value of the 'gradH'
uniform vec2 skyboxUV1; // (u, v) for the skybox drawing
uniform vec2 skyboxUV2; // (u2, v2) for the skybox drawing
uniform vec4 drawOffsetSize; // (gradX, gradY, gradW, gradH)
uniform vec4 skyboxUV1; // (u, v, u2, v2) for the skybox drawing (morning)
uniform vec4 skyboxUV2; // (u, v, u2, v2) for the skybox drawing (afternoon)
uniform float texBlend;
uniform vec2 tex1Size = vec2(4096.0);
uniform vec2 astrumScroll = vec2(0.0);
uniform vec4 randomNumber = vec4(1.0, -2.0, 3.0, -4.0);
@@ -112,13 +112,17 @@ vec4 random(vec2 p) {
// draw call to this function must use UV coord of (0,0,1,1)!
void main(void) {
vec2 skyboxTexCoord = mix(skyboxUV1, skyboxUV2, v_texCoords);
vec2 astrumTexCoord = (v_texCoords * drawOffsetSize + drawOffset + astrumScroll) / tex1Size;
vec2 skyboxTexCoordMorning = mix(skyboxUV1.xy, skyboxUV1.zw, v_texCoords);
vec2 skyboxTexCoordAfternoon = mix(skyboxUV2.xy, skyboxUV2.zw, v_texCoords);
vec2 astrumTexCoord = (v_texCoords * drawOffsetSize.zw + drawOffsetSize.xy + astrumScroll) / tex1Size;
vec4 randomness = snoise4((gl_FragCoord.xy - astrumScroll) * 0.16) * 2.0; // multiply by 2 so that the "density" of the stars would be same as the non-random version
vec4 colorTex0 = texture(u_texture, skyboxTexCoord);
vec4 colorTex0Morining = texture(u_texture, skyboxTexCoordMorning);
vec4 colorTex0Afternoon = texture(u_texture, skyboxTexCoordAfternoon);
vec4 colorTex0 = mix(colorTex0Morining, colorTex0Afternoon, texBlend);
vec4 colorTex1 = texture(tex1, astrumTexCoord) * randomness;