Light Calculation using JDK Incubator Vector

This commit is contained in:
minjaesong
2022-04-21 14:33:37 +09:00
parent fd72b3d3ba
commit b47549d846
11 changed files with 181 additions and 441 deletions

View File

@@ -54,12 +54,12 @@ class BlockProp {
internal var baseLumColG = 0f // base value used to calculate dynamic luminosity
internal var baseLumColB = 0f // base value used to calculate dynamic luminosity
internal var baseLumColA = 0f // base value used to calculate dynamic luminosity
internal val baseLumCol = Cvec(0)
internal val baseLumCol = Cvec(0f)
//var lumColR = 0f // memoised value of dynamic luminosity
//var lumColG = 0f // memoised value of dynamic luminosity
//var lumColB = 0f // memoised value of dynamic luminosity
//var lumColA = 0f // memoised value of dynamic luminosity
internal val _lumCol = Cvec(0)
internal val _lumCol = Cvec(0f)
// X- and Y-value must be treated properly beforehand! (use GameWorld.coerceXY())
fun getLumCol(x: Int, y: Int) = if (dynamicLuminosityFunction == 0) {
baseLumCol

View File

@@ -137,11 +137,6 @@ object BlockPropUtil {
* @return processed colour
*/
private fun alterBrightnessUniform(data: Cvec, brighten: Float): Cvec {
return Cvec(
data.r + brighten,
data.g + brighten,
data.b + brighten,
data.a + brighten
)
return Cvec(data.vec.add(brighten))
}
}

View File

@@ -48,7 +48,7 @@ internal object WeatherMixer : RNGConsumer {
lateinit var mixedWeather: BaseModularWeather
val globalLightNow = Cvec(0)
val globalLightNow = Cvec(0f)
// Weather indices
const val WEATHER_GENERIC = "generic"

View File

@@ -3,6 +3,8 @@ package net.torvald.terrarum.worlddrawer
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import jdk.incubator.vector.FloatVector
import jdk.incubator.vector.FloatVector.SPECIES_128
import net.torvald.gdx.graphics.Cvec
import net.torvald.gdx.graphics.UnsafeCvecArray
import net.torvald.terrarum.*
@@ -365,10 +367,10 @@ object LightmapRenderer {
for (x in lightBoxX.div(TILE_SIZE).floorInt()
..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) {
val oldLight = lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: Cvec(0) // if two or more luminous actors share the same block, mix the light
val oldLight = lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: Cvec(0f) // if two or more luminous actors share the same block, mix the light
val actorLight = colour
lanternMap[LandUtil.getBlockAddr(world, x, y)] = oldLight.maxAndAssign(actorLight)
lanternMap[LandUtil.getBlockAddr(world, x, y)] = oldLight.max(actorLight)
}
}
}
@@ -384,10 +386,10 @@ object LightmapRenderer {
for (x in lightBoxX.div(TILE_SIZE).floorInt()
..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) {
val oldLight = shadowMap[LandUtil.getBlockAddr(world, x, y)] ?: Cvec(0) // if two or more luminous actors share the same block, mix the light
val oldLight = shadowMap[LandUtil.getBlockAddr(world, x, y)] ?: Cvec(0f) // if two or more luminous actors share the same block, mix the light
val actorLight = colour
shadowMap[LandUtil.getBlockAddr(world, x, y)] = oldLight.maxAndAssign(actorLight)
shadowMap[LandUtil.getBlockAddr(world, x, y)] = oldLight.max(actorLight)
}
}
}
@@ -433,20 +435,23 @@ object LightmapRenderer {
}*/
// local variables that are made static
private val sunLight = Cvec(0)
private val sunLight = Cvec(0f)
private var _thisTerrain = 0
private var _thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
private var _thisWall = 0
private val _ambientAccumulator = Cvec(0)
private val _reflectanceAccumulator = Cvec(0)
private val _thisTileOpacity = Cvec(0)
private val _thisTileOpacity2 = Cvec(0) // thisTileOpacity * sqrt(2)
private val _fluidAmountToCol = Cvec(0)
private val _thisTileLuminosity = Cvec(0)
private var _ambientAccumulator = Cvec(0f)
private var _reflectanceAccumulator = Cvec(0f)
private var _thisTileOpacity = Cvec(0f)
private var _thisTileOpacity2 = Cvec(0f) // thisTileOpacity * sqrt(2)
private var _fluidAmountToCol = Cvec(0f)
private var _thisTileLuminosity = Cvec(0f)
private var _thisTerrainProp: BlockProp = BlockProp()
private var _thisWallProp: BlockProp = BlockProp()
private var _thisFluidProp: BlockProp = BlockProp()
private val VECTOR_ZERO = Cvec(0f)
private val VECTOR_ONE = Cvec(1f)
private fun precalculate(rawx: Int, rawy: Int) {
val lx = rawx.convX(); val ly = rawy.convY()
val (worldX, worldY) = world.coerceXY(rawx, rawy)
@@ -491,9 +496,8 @@ object LightmapRenderer {
if (_thisFluid.type != Fluid.NULL) {
_fluidAmountToCol.set(_thisFluid.amount, _thisFluid.amount, _thisFluid.amount, _thisFluid.amount)
_thisTileLuminosity.set(_thisTerrainProp.getLumCol(worldX, worldY))
_thisTileLuminosity.maxAndAssign(_thisFluidProp.getLumCol(worldX, worldY).mul(_fluidAmountToCol))
_thisTileLuminosity.max(_thisFluidProp.getLumCol(worldX, worldY).cpy().mul(_fluidAmountToCol))
_mapThisTileOpacity.setVec(lx, ly, _thisTerrainProp.opacity)
_mapThisTileOpacity.max(lx, ly, _thisFluidProp.opacity.mul(_fluidAmountToCol))
}
@@ -505,10 +509,11 @@ object LightmapRenderer {
// blend shade
_mapThisTileOpacity.max(lx, ly, shadowMap[LandUtil.getBlockAddr(world, worldX, worldY)] ?: colourNull)
_mapThisTileOpacity2.setR(lx, ly, _mapThisTileOpacity.getR(lx, ly) * 1.41421356f)
_mapThisTileOpacity2.setG(lx, ly, _mapThisTileOpacity.getG(lx, ly) * 1.41421356f)
_mapThisTileOpacity2.setB(lx, ly, _mapThisTileOpacity.getB(lx, ly) * 1.41421356f)
_mapThisTileOpacity2.setA(lx, ly, _mapThisTileOpacity.getA(lx, ly) * 1.41421356f)
// _mapThisTileOpacity2.setR(lx, ly, _mapThisTileOpacity.getR(lx, ly) * 1.41421356f)
// _mapThisTileOpacity2.setG(lx, ly, _mapThisTileOpacity.getG(lx, ly) * 1.41421356f)
// _mapThisTileOpacity2.setB(lx, ly, _mapThisTileOpacity.getB(lx, ly) * 1.41421356f)
// _mapThisTileOpacity2.setA(lx, ly, _mapThisTileOpacity.getA(lx, ly) * 1.41421356f)
_mapThisTileOpacity2.setFromFloatVector(lx, ly, _mapThisTileOpacity.getFloatVector(lx, ly).mul(1.41421356f))
// open air || luminous tile backed by sunlight
@@ -518,7 +523,7 @@ object LightmapRenderer {
}
// blend lantern
_mapLightLevelThis.max(lx, ly, _thisTileLuminosity.maxAndAssign(
_mapLightLevelThis.max(lx, ly, _thisTileLuminosity.max(
lanternMap[LandUtil.getBlockAddr(world, worldX, worldY)] ?: colourNull
))
}
@@ -534,17 +539,16 @@ object LightmapRenderer {
// }
// blend nearby 4 lights to get intensity
_ambientAccumulator.set(0)
.maxAndAssign(lightmap.getVec(lx - 1, ly))
.maxAndAssign(lightmap.getVec(lx + 1, ly))
.maxAndAssign(lightmap.getVec(lx, ly - 1))
.maxAndAssign(lightmap.getVec(lx, ly + 1))
_ambientAccumulator.set(0f)
.max(lightmap.getVec(lx - 1, ly))
.max(lightmap.getVec(lx + 1, ly))
.max(lightmap.getVec(lx, ly - 1))
.max(lightmap.getVec(lx, ly + 1))
_thisTerrain = world.getTileFromTerrainRaw(worldX, worldY)
_thisTerrainProp = BlockCodex[world.tileNumberToNameMap[_thisTerrain.toLong()]]
_reflectanceAccumulator.set(App.tileMaker.terrainTileColourMap[_thisTerrainProp.id]!!)
_reflectanceAccumulator.a = 0f // temporarily disabled
_reflectanceAccumulator.mul(_thisTerrainProp.reflectance).mul(giScale)
_mapLightLevelThis.max(lx, ly, _reflectanceAccumulator)
@@ -557,26 +561,34 @@ object LightmapRenderer {
private fun _swipeTask(x: Int, y: Int, x2: Int, y2: Int, lightmap: UnsafeCvecArray) {
if (x2 < 0 || y2 < 0 || x2 >= LIGHTMAP_WIDTH || y2 >= LIGHTMAP_HEIGHT) return
_ambientAccumulator.r = _mapLightLevelThis.getR(x, y)
_ambientAccumulator.g = _mapLightLevelThis.getG(x, y)
_ambientAccumulator.b = _mapLightLevelThis.getB(x, y)
_ambientAccumulator.a = _mapLightLevelThis.getA(x, y)
// _ambientAccumulator.r = _mapLightLevelThis.getR(x, y)
// _ambientAccumulator.g = _mapLightLevelThis.getG(x, y)
// _ambientAccumulator.b = _mapLightLevelThis.getB(x, y)
// _ambientAccumulator.a = _mapLightLevelThis.getA(x, y)
_ambientAccumulator = _mapLightLevelThis.getVec(x, y)
if (!swipeDiag) {
_thisTileOpacity.r = _mapThisTileOpacity.getR(x, y)
_thisTileOpacity.g = _mapThisTileOpacity.getG(x, y)
_thisTileOpacity.b = _mapThisTileOpacity.getB(x, y)
_thisTileOpacity.a = _mapThisTileOpacity.getA(x, y)
_ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity, lightmap))
// _thisTileOpacity.r = _mapThisTileOpacity.getR(x, y)
// _thisTileOpacity.g = _mapThisTileOpacity.getG(x, y)
// _thisTileOpacity.b = _mapThisTileOpacity.getB(x, y)
// _thisTileOpacity.a = _mapThisTileOpacity.getA(x, y)
// _ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity, lightmap))
_thisTileOpacity = _mapThisTileOpacity.getVec(x, y)
_ambientAccumulator = _ambientAccumulator.max(darkenColoured(x2, y2, _thisTileOpacity, lightmap))
}
else {
_thisTileOpacity2.r = _mapThisTileOpacity2.getR(x, y)
_thisTileOpacity2.g = _mapThisTileOpacity2.getG(x, y)
_thisTileOpacity2.b = _mapThisTileOpacity2.getB(x, y)
_thisTileOpacity2.a = _mapThisTileOpacity2.getA(x, y)
_ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity2, lightmap))
// _thisTileOpacity2.r = _mapThisTileOpacity2.getR(x, y)
// _thisTileOpacity2.g = _mapThisTileOpacity2.getG(x, y)
// _thisTileOpacity2.b = _mapThisTileOpacity2.getB(x, y)
// _thisTileOpacity2.a = _mapThisTileOpacity2.getA(x, y)
// _ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity2, lightmap))
_thisTileOpacity2 = _mapThisTileOpacity2.getVec(x, y)
_ambientAccumulator = _ambientAccumulator.max(darkenColoured(x2, y2, _thisTileOpacity2, lightmap))
}
// _mapLightLevelThis.setVec(x, y, _ambientAccumulator)
// lightmap.setVec(x, y, _ambientAccumulator)
_mapLightLevelThis.setVec(x, y, _ambientAccumulator)
lightmap.setVec(x, y, _ambientAccumulator)
}
@@ -611,9 +623,9 @@ object LightmapRenderer {
var lightBuffer: Pixmap = Pixmap(64, 64, Pixmap.Format.RGBA8888) // must not be too small
private val colourNull = Cvec(0)
private val colourNull = Cvec(0f)
private val gdxColorNull = Color(0)
const val epsilon = 1f/1024f
val epsilon = FloatVector.broadcast(SPECIES_128, 1f / 1024f)
private var _lightBufferAsTex: Texture = Texture(64, 64, Pixmap.Format.RGBA8888) // must not be too small
@@ -647,10 +659,10 @@ object LightmapRenderer {
val arrayX = x.convX()
val arrayY = y.convY()
val red = lightmap.getR(arrayX, arrayY)
val grn = lightmap.getG(arrayX, arrayY)
val blu = lightmap.getB(arrayX, arrayY)
val uvl = lightmap.getA(arrayX, arrayY)
val red = lightmap.getR(arrayX, arrayY).let { if (it.isFinite()) it else 0f }
val grn = lightmap.getG(arrayX, arrayY).let { if (it.isFinite()) it else 0f }
val blu = lightmap.getB(arrayX, arrayY).let { if (it.isFinite()) it else 0f }
val uvl = lightmap.getA(arrayX, arrayY).let { if (it.isFinite()) it else 0f }
val redw = (red.sqrt() - 1f) * (7f / 24f)
val grnw = (grn.sqrt() - 1f)
val bluw = (blu.sqrt() - 1f) * (7f / 72f)
@@ -666,13 +678,21 @@ object LightmapRenderer {
0
)
else
lightBuffer.drawPixel(
/*lightBuffer.drawPixel(
x - this_x_start,
lightBuffer.height - 1 - y + this_y_start, // flip Y
(maxOf(red,grnw,bluw,uvlwr) * solidMultMagic).hdnorm().times(255f).roundToInt().shl(24) or
(maxOf(redw,grn,bluw,uvlwg) * solidMultMagic).hdnorm().times(255f).roundToInt().shl(16) or
(maxOf(redw,grnw,blu,uvlwb) * solidMultMagic).hdnorm().times(255f).roundToInt().shl(8) or
(maxOf(bluwv,uvl) * solidMultMagic).hdnorm().times(255f).roundToInt()
)*/
lightBuffer.drawPixel(
x - this_x_start,
lightBuffer.height - 1 - y + this_y_start, // flip Y
(red * solidMultMagic).hdnorm().times(255f).roundToInt().shl(24) or
(grn * solidMultMagic).hdnorm().times(255f).roundToInt().shl(16) or
(blu * solidMultMagic).hdnorm().times(255f).roundToInt().shl(8) or
(uvl * solidMultMagic).hdnorm().times(255f).roundToInt()
)
}
}
@@ -720,25 +740,15 @@ object LightmapRenderer {
if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull
return Cvec(
/*return Cvec(
lightmap.getR(x, y) * (1f - darken.r * lightScalingMagic),
lightmap.getG(x, y) * (1f - darken.g * lightScalingMagic),
lightmap.getB(x, y) * (1f - darken.b * lightScalingMagic),
lightmap.getA(x, y) * (1f - darken.a * lightScalingMagic)
)
}
/** infix is removed to clarify the association direction */
private fun Cvec.maxAndAssign(other: Cvec): Cvec {
// TODO investigate: if I use assignment instead of set(), it blackens like the vector branch. --Torvald, 2019-06-07
// that was because you forgot 'this.r/g/b/a = ' part, bitch. --Torvald, 2019-06-07
this.r = if (this.r > other.r) this.r else other.r
this.g = if (this.g > other.g) this.g else other.g
this.b = if (this.b > other.b) this.b else other.b
this.a = if (this.a > other.a) this.a else other.a
return this
)*/
return Cvec(lightmap.getFloatVector(x, y).mul(
VECTOR_ONE.vec.sub(darken.vec.mul(lightScalingMagic))
))
}
private fun Float.inv() = 1f / this
@@ -811,10 +821,7 @@ object LightmapRenderer {
inline fun Float.hdnorm() = hdr(this.coerceIn(0f, 1f))
private fun Cvec.nonZero() = this.r.abs() > epsilon ||
this.g.abs() > epsilon ||
this.b.abs() > epsilon ||
this.a.abs() > epsilon
private fun Cvec.nonZero() = epsilon.lt(this.vec.abs()).anyTrue()
val histogram: Histogram
get() {