more testing on skydome / font change

This commit is contained in:
minjaesong
2020-04-29 08:48:06 +09:00
parent 826a13ff57
commit 226c8342cb
19 changed files with 468 additions and 424 deletions

View File

@@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.3.10' ext.kotlin_version = '1.3.72'
repositories { repositories {
mavenCentral() mavenCentral()
@@ -27,6 +27,7 @@ repositories {
} }
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlinx-coroutines-core"
compile "org.jetbrains.kotlin:kotlin-stdlib" compile "org.jetbrains.kotlin:kotlin-stdlib"
compile fileTree(dir: 'lib', include: ['*.jar']) compile fileTree(dir: 'lib', include: ['*.jar'])
implementation 'org.junit:junit-bom:5.2.0' implementation 'org.junit:junit-bom:5.2.0'

Binary file not shown.

View File

@@ -2,12 +2,6 @@ package net.torvald.colourutil
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.jme3.math.FastMath import com.jme3.math.FastMath
import net.torvald.colourutil.CIELChabUtil.toLCh
import net.torvald.colourutil.CIELChabUtil.toLab
import net.torvald.colourutil.CIELabUtil.toLab
import net.torvald.colourutil.CIEXYZUtil.toXYZ
import net.torvald.colourutil.CIEXYZUtil.toColor
import net.torvald.colourutil.CIELabUtil.toXYZ
/** /**
* Cylindrical modification of CIELab colour space * Cylindrical modification of CIELab colour space
* *
@@ -16,10 +10,9 @@ import net.torvald.colourutil.CIELabUtil.toXYZ
* Created by minjaesong on 2016-09-01. * Created by minjaesong on 2016-09-01.
*/ */
object CIELChabUtil {
/** Sweet LCh_ab linear gradient */ /** Sweet LCh_ab linear gradient */
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color { fun cielch_getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
val from = fromCol.toLCh() val from = fromCol.toLCh()
val to = toCol.toLCh() val to = toCol.toLCh()
val newL = FastMath.interpolateLinear(scale, from.L, to.L) val newL = FastMath.interpolateLinear(scale, from.L, to.L)
@@ -28,35 +21,35 @@ object CIELChabUtil {
val newH: Float val newH: Float
if ((from.h - to.h).abs() == FastMath.PI) // exact opposite colour if ((from.h - to.h).abs() == FastMath.PI) // exact opposite colour
return CIELabUtil.getGradient(scale, fromCol, toCol) return cielab_getGradient(scale, fromCol, toCol)
else if ((from.h - to.h).abs() > FastMath.PI) // reflex angle else if ((from.h - to.h).abs() > FastMath.PI) // reflex angle
newH = FastMath.interpolateLinear(scale, from.h, to.h + FastMath.TWO_PI) newH = FastMath.interpolateLinear(scale, from.h, to.h + FastMath.TWO_PI)
else else
newH = FastMath.interpolateLinear(scale, from.h, to.h) newH = FastMath.interpolateLinear(scale, from.h, to.h)
return CIELCh(newL, newC, newH, newAlpha).toColor() return CIELCh(newL, newC, newH, newAlpha).toColor()
} }
fun CIELab.toLCh(): CIELCh { fun CIELab.toLCh(): CIELCh {
val c = (a.sqr() + b.sqr()).sqrt() val c = (a.sqr() + b.sqr()).sqrt()
val h = FastMath.atan2(b, a) val h = FastMath.atan2(b, a)
return CIELCh(L, c, h, alpha) return CIELCh(L, c, h, alpha)
} }
fun CIELCh.toLab(): CIELab { fun CIELCh.toLab(): CIELab {
val a = C * FastMath.cos(h) val a = C * FastMath.cos(h)
val b = C * FastMath.sin(h) val b = C * FastMath.sin(h)
return CIELab(L, a, b, alpha) return CIELab(L, a, b, alpha)
}
private fun Float.sqr() = this * this
private fun Float.sqrt() = Math.sqrt(this.toDouble()).toFloat()
private fun Float.abs() = FastMath.abs(this)
} }
private fun Float.sqr() = this * this
private fun Float.sqrt() = Math.sqrt(this.toDouble()).toFloat()
private fun Float.abs() = FastMath.abs(this)
fun Color.toLCh() = this.toXYZ().toLab().toLCh() fun Color.toLCh() = this.toXYZ().toLab().toLCh()
fun CIELCh.toColor() = this.toLab().toXYZ().toColor() fun CIELCh.toColor() = this.toLab().toXYZ().toColor()

View File

@@ -2,11 +2,6 @@ package net.torvald.colourutil
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.jme3.math.FastMath import com.jme3.math.FastMath
import net.torvald.colourutil.CIELabUtil.toLab
import net.torvald.colourutil.CIEXYZUtil.toColor
import net.torvald.colourutil.CIEXYZUtil.toRGB
import net.torvald.colourutil.CIEXYZUtil.toXYZ
import net.torvald.colourutil.CIELabUtil.toXYZ
/** /**
* A modification of CIEXYZ that is useful for surface colours * A modification of CIEXYZ that is useful for surface colours
@@ -23,25 +18,24 @@ import net.torvald.colourutil.CIELabUtil.toXYZ
* *
* Created by minjaesong on 2016-09-01. * Created by minjaesong on 2016-09-01.
*/ */
object CIELabUtil { fun Color.brighterLab(scale: Float): Color {
fun Color.brighterLab(scale: Float): Color {
val brighten = scale + 1f val brighten = scale + 1f
val lab = this.toLab() val lab = this.toLab()
lab.L *= brighten lab.L *= brighten
return lab.toColor() return lab.toColor()
} }
fun Color.darkerLab(scale: Float): Color { fun Color.darkerLab(scale: Float): Color {
val darken = 1f - scale val darken = 1f - scale
val lab = this.toLab() val lab = this.toLab()
lab.L *= darken lab.L *= darken
return lab.toColor() return lab.toColor()
} }
/** Tend to have more natural (or less saturated) colour */ /** Tend to have more natural (or less saturated) colour */
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color { fun cielab_getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
val from = fromCol.toLab() val from = fromCol.toLab()
val to = toCol.toLab() val to = toCol.toLab()
val newL = FastMath.interpolateLinear(scale, from.L, to.L) val newL = FastMath.interpolateLinear(scale, from.L, to.L)
@@ -50,9 +44,9 @@ object CIELabUtil {
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha) val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
return CIELab(newL, newA, newB, newAlpha).toColor() return CIELab(newL, newA, newB, newAlpha).toColor()
} }
fun CIEXYZ.toLab(): CIELab { fun CIEXYZ.toLab(): CIELab {
val x = pivotXYZ(X / D65.X) val x = pivotXYZ(X / D65.X)
val y = pivotXYZ(Y / D65.Y) val y = pivotXYZ(Y / D65.Y)
val z = pivotXYZ(Z / D65.Z) val z = pivotXYZ(Z / D65.Z)
@@ -62,9 +56,9 @@ object CIELabUtil {
val b = 200 * (y - z) val b = 200 * (y - z)
return CIELab(L, a, b, alpha) return CIELab(L, a, b, alpha)
} }
fun CIELab.toXYZ(): CIEXYZ { fun CIELab.toXYZ(): CIEXYZ {
val y = L.plus(16).div(116f) val y = L.plus(16).div(116f)
val x = a / 500f + y val x = a / 500f + y
val z = y - b / 200f val z = y - b / 200f
@@ -78,15 +72,15 @@ object CIELabUtil {
D65.Z * if (z3 > epsilon) z3 else (z - 16f / 116f) / 7.787f, D65.Z * if (z3 > epsilon) z3 else (z - 16f / 116f) / 7.787f,
alpha alpha
) )
}
private fun pivotXYZ(n: Float) = if (n > epsilon) n.cbrt() else (kappa * n + 16f) / 116f
private fun Float.cbrt() = FastMath.pow(this, 1f / 3f)
private fun Float.cube() = this * this * this
private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp)
} }
private fun pivotXYZ(n: Float) = if (n > epsilon) n.cbrt() else (kappa * n + 16f) / 116f
private fun Float.cbrt() = FastMath.pow(this, 1f / 3f)
private fun Float.cube() = this * this * this
private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp)
fun Color.toLab() = this.toXYZ().toLab() fun Color.toLab() = this.toXYZ().toLab()
fun RGB.toLab() = this.toXYZ().toLab() fun RGB.toLab() = this.toXYZ().toLab()
fun CIELab.toColor() = this.toXYZ().toColor() fun CIELab.toColor() = this.toXYZ().toColor()

View File

@@ -2,11 +2,6 @@ package net.torvald.colourutil
import com.jme3.math.FastMath import com.jme3.math.FastMath
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import net.torvald.colourutil.CIEXYZUtil.toColor
import net.torvald.colourutil.CIEXYZUtil.toRGB
import net.torvald.colourutil.CIEXYZUtil.toXYZ
import net.torvald.colourutil.CIELuvUtil.toLuv
import net.torvald.colourutil.CIELuvUtil.toXYZ
/** /**
* A modification of CIEXYZ that is useful for additive mixtures of lights. * A modification of CIEXYZ that is useful for additive mixtures of lights.
@@ -18,26 +13,25 @@ import net.torvald.colourutil.CIELuvUtil.toXYZ
* *
* Created by minjaesong on 2016-09-06. * Created by minjaesong on 2016-09-06.
*/ */
object CIELuvUtil {
fun Color.brighterLuv(scale: Float): Color { fun Color.brighterLuv(scale: Float): Color {
val brighten = scale + 1f val brighten = scale + 1f
val luv = this.toLuv() val luv = this.toLuv()
luv.L *= brighten luv.L *= brighten
return luv.toColor() return luv.toColor()
} }
fun Color.darkerLuv(scale: Float): Color { fun Color.darkerLuv(scale: Float): Color {
val darken = 1f - scale val darken = 1f - scale
val luv = this.toLuv() val luv = this.toLuv()
luv.L *= darken luv.L *= darken
return luv.toColor() return luv.toColor()
} }
/** Tend to have more vivid (or saturated) colour */ /** Tend to have more vivid (or saturated) colour */
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color { fun cieluv_getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
val from = fromCol.toLuv() val from = fromCol.toLuv()
val to = toCol.toLuv() val to = toCol.toLuv()
val newL = FastMath.interpolateLinear(scale, from.L, to.L) val newL = FastMath.interpolateLinear(scale, from.L, to.L)
@@ -46,20 +40,20 @@ object CIELuvUtil {
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha) val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
return CIELab(newL, newU, newV, newAlpha).toColor() return CIELab(newL, newU, newV, newAlpha).toColor()
} }
/** /**
* Alpha value will be overwritten to 1.0 * Alpha value will be overwritten to 1.0
*/ */
infix fun Color.additiveLuv(other: Color): Color { infix fun Color.additiveLuv(other: Color): Color {
val rgb = RGB(r, g, b) additiveLuv RGB(other.r, other.g, other.b) val rgb = RGB(r, g, b) additiveLuv RGB(other.r, other.g, other.b)
return Color(rgb.r, rgb.g, rgb.b, a) return Color(rgb.r, rgb.g, rgb.b, a)
} }
/** /**
* Alpha value will be overwritten to 1.0 * Alpha value will be overwritten to 1.0
*/ */
infix fun RGB.additiveLuv(other: RGB): RGB { infix fun RGB.additiveLuv(other: RGB): RGB {
val thisLuv = this.toXYZ().toLuv() val thisLuv = this.toXYZ().toLuv()
val otherLuv = other.toXYZ().toLuv() val otherLuv = other.toXYZ().toLuv()
@@ -68,9 +62,9 @@ object CIELuvUtil {
val newV = thisLuv.v.times(otherLuv.L / newL) + otherLuv.v.times(otherLuv.L).times(1f - thisLuv.L).div(newL) val newV = thisLuv.v.times(otherLuv.L / newL) + otherLuv.v.times(otherLuv.L).times(1f - thisLuv.L).div(newL)
return CIELuv(newL, newU, newV).toRGB() return CIELuv(newL, newU, newV).toRGB()
} }
fun CIEXYZ.toLuv(): CIELuv { fun CIEXYZ.toLuv(): CIELuv {
val yRef = Y / D65.Y val yRef = Y / D65.Y
val uPrime = 4f * X / (X + 15f * Y + 3f * Z) val uPrime = 4f * X / (X + 15f * Y + 3f * Z)
val vPrime = 9f * Y / (X + 15f * Y + 3f * Z) val vPrime = 9f * Y / (X + 15f * Y + 3f * Z)
@@ -86,9 +80,9 @@ object CIELuvUtil {
val v = 13f * L * (vPrime - vRefPrime) val v = 13f * L * (vPrime - vRefPrime)
return CIELuv(L, u, v, alpha) return CIELuv(L, u, v, alpha)
} }
fun CIELuv.toXYZ(): CIEXYZ { fun CIELuv.toXYZ(): CIEXYZ {
val Y = if (L > kappa * epsilon) val Y = if (L > kappa * epsilon)
L.plus(16f).div(116f).cube() L.plus(16f).div(116f).cube()
else else
@@ -103,12 +97,12 @@ object CIELuvUtil {
val Z = X * a + b val Z = X * a + b
return CIEXYZ(X, Y, Z, alpha) return CIEXYZ(X, Y, Z, alpha)
}
private fun Float.cbrt() = FastMath.pow(this, 1f / 3f)
private fun Float.cube() = this * this * this
} }
private fun Float.cbrt() = FastMath.pow(this, 1f / 3f)
private fun Float.cube() = this * this * this
fun Color.toLuv() = this.toXYZ().toLuv() fun Color.toLuv() = this.toXYZ().toLuv()
fun CIELuv.toRGB() = this.toXYZ().toRGB() fun CIELuv.toRGB() = this.toXYZ().toRGB()
fun CIELuv.toColor() = this.toXYZ().toColor() fun CIELuv.toColor() = this.toXYZ().toColor()

View File

@@ -2,59 +2,56 @@ package net.torvald.colourutil
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.jme3.math.FastMath import com.jme3.math.FastMath
import net.torvald.gdx.graphics.Cvec
/** /**
* Created by minjaesong on 2017-01-12. * Created by minjaesong on 2017-01-12.
*/ */
object CIEXYZUtil {
/** /**
* 0..255 -> 0.0..1.0 * 0..255 -> 0.0..1.0
*/ */
private val rgbLinLUT = FloatArray(256) { private val rgbLinLUT = FloatArray(256) {
val step = it / 255f val step = it / 255f
if (step > 0.04045f) if (step > 0.04045f)
((step + 0.055f) / 1.055f).powerOf(2.4f) ((step + 0.055f) / 1.055f).powerOf(2.4f)
else step / 12.92f else step / 12.92f
} }
/** /**
* 0..255 -> 0.0..1.0 * 0..255 -> 0.0..1.0
*/ */
private val rgbUnLinLUT = FloatArray(256) { private val rgbUnLinLUT = FloatArray(256) {
val step = it / 255f val step = it / 255f
if (step > 0.0031308f) if (step > 0.0031308f)
1.055f * step.powerOf(1f / 2.4f) - 0.055f 1.055f * step.powerOf(1f / 2.4f) - 0.055f
else else
step * 12.92f step * 12.92f
} }
private val rgbToXyzLut_XR = FloatArray(256) { 0.4124564f * (it / 255f) } private val rgbToXyzLut_XR = FloatArray(256) { 0.4124564f * (it / 255f) }
fun Color.brighterXYZ(scale: Float): Color {
fun Color.brighterXYZ(scale: Float): Color {
val xyz = this.toXYZ() val xyz = this.toXYZ()
xyz.X = xyz.X.times(1f + scale).clampOne() xyz.X = xyz.X.times(1f + scale).clampOne()
xyz.Y = xyz.Y.times(1f + scale).clampOne() xyz.Y = xyz.Y.times(1f + scale).clampOne()
xyz.Z = xyz.Z.times(1f + scale).clampOne() xyz.Z = xyz.Z.times(1f + scale).clampOne()
return xyz.toColor() return xyz.toColor()
} }
fun Color.darkerXYZ(scale: Float): Color { fun Color.darkerXYZ(scale: Float): Color {
val xyz = this.toXYZ() val xyz = this.toXYZ()
xyz.X = xyz.X.times(1f - scale).clampOne() xyz.X = xyz.X.times(1f - scale).clampOne()
xyz.Y = xyz.Y.times(1f - scale).clampOne() xyz.Y = xyz.Y.times(1f - scale).clampOne()
xyz.Z = xyz.Z.times(1f - scale).clampOne() xyz.Z = xyz.Z.times(1f - scale).clampOne()
return xyz.toColor() return xyz.toColor()
} }
/*@Deprecated("Use one in CIELAB or CIELUV; CIEXYZ is not perceptually uniform") /*@Deprecated("Use one in CIELAB or CIELUV; CIEXYZ is not perceptually uniform")
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color { fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
val from = fromCol.toXYZ() val from = fromCol.toXYZ()
val to = toCol.toXYZ() val to = toCol.toXYZ()
val newX = FastMath.interpolateLinear(scale, from.X, to.X) val newX = FastMath.interpolateLinear(scale, from.X, to.X)
@@ -63,17 +60,17 @@ object CIEXYZUtil {
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha) val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
return CIEXYZ(newX, newY, newZ, newAlpha).toColor() return CIEXYZ(newX, newY, newZ, newAlpha).toColor()
}*/ }*/
fun Color.toXYZ(): CIEXYZ = RGB(this).toXYZ() fun Color.toXYZ(): CIEXYZ = RGB(this).toXYZ()
/** /**
* "Linearise" the sRGB triads. This use lookup table to speed up calculation. * "Linearise" the sRGB triads. This use lookup table to speed up calculation.
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are * Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference, * linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
* but may not optimal for rigorous maths. * but may not optimal for rigorous maths.
*/ */
fun RGB.linearise(): RGB { /*fun RGB.linearise(): RGB {
val out = floatArrayOf(0f, 0f, 0f) val out = floatArrayOf(0f, 0f, 0f)
for (i in 0..2) { for (i in 0..2) {
val value = when (i) { val value = when (i) {
@@ -91,10 +88,10 @@ object CIEXYZUtil {
return RGB(out[0], out[1], out[2], alpha) return RGB(out[0], out[1], out[2], alpha)
} }*/
/** Suitable for rigorous maths but slower */ /** Suitable for rigorous maths but slower */
fun RGB.lineariseSuper(): RGB { fun RGB.linearise(): RGB {
val newR = if (r > 0.04045f) val newR = if (r > 0.04045f)
((r + 0.055f) / 1.055f).powerOf(2.4f) ((r + 0.055f) / 1.055f).powerOf(2.4f)
else r / 12.92f else r / 12.92f
@@ -107,15 +104,15 @@ object CIEXYZUtil {
return RGB(newR, newG, newB, alpha) return RGB(newR, newG, newB, alpha)
} }
/** /**
* "Un-linearise" the RGB triads. That is, codes the linear RGB into sRGB. This use lookup table to speed up calculation. * "Un-linearise" the RGB triads. That is, codes the linear RGB into sRGB. This use lookup table to speed up calculation.
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are * Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference, * linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
* but may not optimal for rigorous maths. * but may not optimal for rigorous maths.
*/ */
fun RGB.unLinearise(): RGB { /*fun RGB.unLinearise(): RGB {
val out = floatArrayOf(0f, 0f, 0f) val out = floatArrayOf(0f, 0f, 0f)
for (i in 0..2) { for (i in 0..2) {
val value = when (i) { val value = when (i) {
@@ -133,10 +130,10 @@ object CIEXYZUtil {
return RGB(out[0], out[1], out[2], alpha) return RGB(out[0], out[1], out[2], alpha)
} }*/
/** Suitable for rigorous maths but slower */ /** Suitable for rigorous maths but slower */
fun RGB.unLineariseSuper(): RGB { fun RGB.unLinearise(): RGB {
val newR = if (r > 0.0031308f) val newR = if (r > 0.0031308f)
1.055f * r.powerOf(1f / 2.4f) - 0.055f 1.055f * r.powerOf(1f / 2.4f) - 0.055f
else else
@@ -152,9 +149,9 @@ object CIEXYZUtil {
return RGB(newR, newG, newB, alpha) return RGB(newR, newG, newB, alpha)
} }
fun RGB.toXYZ(): CIEXYZ { fun RGB.toXYZ(): CIEXYZ {
val new = this.linearise() val new = this.linearise()
val x = 0.4124564f * new.r + 0.3575761f * new.g + 0.1804375f * new.b val x = 0.4124564f * new.r + 0.3575761f * new.g + 0.1804375f * new.b
@@ -162,39 +159,44 @@ object CIEXYZUtil {
val z = 0.0193339f * new.r + 0.1191920f * new.g + 0.9503041f * new.b val z = 0.0193339f * new.r + 0.1191920f * new.g + 0.9503041f * new.b
return CIEXYZ(x, y, z, alpha) return CIEXYZ(x, y, z, alpha)
} }
fun CIEXYZ.toRGB(): RGB { fun RGB.toColor() = Color(r, g, b, alpha)
fun RGB.toCvec() = Cvec(r, g, b, alpha)
fun CIEXYZ.toRGB(): RGB {
val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z
val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z
val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z
return RGB(r, g, b, alpha).unLinearise() return RGB(r, g, b, alpha).unLinearise()
} }
fun CIEXYZ.toRGBRaw(): RGB { fun CIEXYZ.toRGBRaw(): RGB {
val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z
val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z
val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z
return RGB(r, g, b, alpha) return RGB(r, g, b, alpha)
} }
fun CIEXYZ.toColor(): Color { fun CIEXYZ.toColor(): Color {
val rgb = this.toRGB() val rgb = this.toRGB()
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha) return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
} }
fun CIEXYZ.toColorRaw(): Color { fun CIEXYZ.mul(scalar: Float) = CIEXYZ(this.X * scalar, this.Y * scalar, this.Z * scalar, this.alpha)
fun CIEXYZ.toColorRaw(): Color {
val rgb = this.toRGBRaw() val rgb = this.toRGBRaw()
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha) return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
} }
fun CIEYXY.toXYZ(): CIEXYZ { fun CIEYXY.toXYZ(): CIEXYZ {
return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y) return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y)
} }
fun colourTempToXYZ(temp: Float, Y: Float): CIEXYZ { fun colourTempToXYZ(temp: Float, Y: Float): CIEXYZ {
val x = if (temp < 7000) val x = if (temp < 7000)
-4607000000f / FastMath.pow(temp, 3f) + 2967800f / FastMath.pow(temp, 2f) + 99.11f / temp + 0.244063f -4607000000f / FastMath.pow(temp, 3f) + 2967800f / FastMath.pow(temp, 2f) + 99.11f / temp + 0.244063f
else else
@@ -203,12 +205,12 @@ object CIEXYZUtil {
val y = -3f * FastMath.pow(x, 2f) + 2.870f * x - 0.275f val y = -3f * FastMath.pow(x, 2f) + 2.870f * x - 0.275f
return CIEXYZ(x * Y / y, Y, (1 - x - y) * Y / y) return CIEXYZ(x * Y / y, Y, (1 - x - y) * Y / y)
} }
private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp) private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp)
private fun Float.clampOne() = if (this > 1f) 1f else if (this < 0f) 0f else this private fun Float.clampOne() = if (this > 1f) 1f else if (this < 0f) 0f else this
private fun interpolateLinear(scale: Float, startValue: Float, endValue: Float): Float { private fun interpolateLinear(scale: Float, startValue: Float, endValue: Float): Float {
if (startValue == endValue) { if (startValue == endValue) {
return startValue return startValue
} }
@@ -219,7 +221,6 @@ object CIEXYZUtil {
endValue endValue
} }
else (1f - scale) * startValue + scale * endValue else (1f - scale) * startValue + scale * endValue
}
} }

View File

@@ -1,7 +1,6 @@
package net.torvald.colourutil package net.torvald.colourutil
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import net.torvald.colourutil.CIEXYZUtil.toColor
import net.torvald.terrarum.GdxColorMap import net.torvald.terrarum.GdxColorMap
import net.torvald.terrarum.ModMgr import net.torvald.terrarum.ModMgr
@@ -24,5 +23,5 @@ object ColourTemp {
/** returns CIExyY-based colour converted to slick.color /** returns CIExyY-based colour converted to slick.color
* @param CIE_Y 0.0 - 1.0+ */ * @param CIE_Y 0.0 - 1.0+ */
operator fun invoke(temp: Float, CIE_Y: Float): Color = operator fun invoke(temp: Float, CIE_Y: Float): Color =
CIEXYZUtil.colourTempToXYZ(temp, CIE_Y).toColor() colourTempToXYZ(temp, CIE_Y).toColor()
} }

View File

@@ -2,7 +2,6 @@ package net.torvald.colourutil
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.jme3.math.FastMath import com.jme3.math.FastMath
import net.torvald.colourutil.CIEXYZUtil.linearise
/** /**
* Created by minjaesong on 2016-07-26. * Created by minjaesong on 2016-07-26.

View File

@@ -5,16 +5,22 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Screen import com.badlogic.gdx.Screen
import com.badlogic.gdx.backends.lwjgl.LwjglApplication import com.badlogic.gdx.backends.lwjgl.LwjglApplication
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.EMDASH import net.torvald.EMDASH
import net.torvald.colourutil.*
import net.torvald.parametricsky.datasets.DatasetCIEXYZ import net.torvald.parametricsky.datasets.DatasetCIEXYZ
import net.torvald.parametricsky.datasets.DatasetRGB import net.torvald.parametricsky.datasets.DatasetRGB
import net.torvald.parametricsky.datasets.DatasetSpectral import net.torvald.parametricsky.datasets.DatasetSpectral
import net.torvald.terrarum.inUse import net.torvald.terrarum.inUse
import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
import java.awt.Dimension import java.awt.Dimension
import javax.swing.* import javax.swing.*
import kotlin.math.PI
import kotlin.math.pow
const val WIDTH = 1200 const val WIDTH = 1200
@@ -50,8 +56,9 @@ class Application : Game() {
private lateinit var testTex: Texture private lateinit var testTex: Texture
var turbidity = 5.0 var turbidity = 5.0
var albedo = 0.0 var albedo = 0.1
var elevation = 0.0 var elevation = 0.0
var scalefactor = 1f
override fun getScreen(): Screen { override fun getScreen(): Screen {
return super.getScreen() return super.getScreen()
@@ -64,12 +71,14 @@ class Application : Game() {
override fun render() { override fun render() {
Gdx.graphics.setTitle("Daylight Model $EMDASH F: ${Gdx.graphics.framesPerSecond}") Gdx.graphics.setTitle("Daylight Model $EMDASH F: ${Gdx.graphics.framesPerSecond}")
if (turbidity <= 0) throw IllegalStateException()
// we need to use different modelstate to accomodate different albedo for each spectral band but oh well...
genTexLoop(ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation)) genTexLoop(ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation))
val tex = Texture(oneScreen) val tex = Texture(oneScreen)
tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear) tex.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
batch.inUse { batch.inUse {
batch.draw(tex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat()) batch.draw(tex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
@@ -94,8 +103,8 @@ class Application : Game() {
oneScreen.dispose() oneScreen.dispose()
} }
val outTexWidth = 32 val outTexWidth = 256
val outTexHeight = 16 val outTexHeight = 256
/** /**
* Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west; * Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west;
@@ -112,6 +121,28 @@ class Application : Game() {
} }
for (y in 0 until oneScreen.height) {
for (x in 0 until oneScreen.width) {
val gamma = (x / oneScreen.width.toDouble()) * TWO_PI // 0deg..360deg
val theta = (1.0 - (y / oneScreen.height.toDouble())) * HALF_PI // 90deg..0deg
val xyz = CIEXYZ(
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat().times(scalefactor / 10f),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat().times(scalefactor / 10f),
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat().times(scalefactor / 10f)
)
val rgb = xyz.toRGB().toColor()
rgb.a = 1f
oneScreen.setColor(rgb)
oneScreen.drawPixel(x, y)
//println("x: ${xyz.X}, y: ${xyz.Y}, z: ${xyz.Z}")
}
}
//System.exit(0)
} }
/** /**
@@ -190,14 +221,21 @@ class Application : Game() {
val mainPanel = JPanel() val mainPanel = JPanel()
val turbidityControl = JSpinner(SpinnerNumberModel(5, 1, 10, 1)) val turbidityControl = JSpinner(SpinnerNumberModel(5.0, 1.0, 10.0, 0.1))
val albedoControl = JSpinner(SpinnerNumberModel(0.3, 0.0, 1.0, 0.05)) val albedoControl = JSpinner(SpinnerNumberModel(0.1, 0.0, 1.0, 0.05))
val elevationControl = JSpinner(SpinnerNumberModel(45, 0, 90, 5)) val elevationControl = JSpinner(SpinnerNumberModel(0.0, 0.0, 90.0, 0.5))
val scalefactorControl = JSpinner(SpinnerNumberModel(1.0, 0.0, 2.0, 0.01))
init { init {
val turbidityPanel = JPanel() val turbidityPanel = JPanel()
val albedoPanel = JPanel() val albedoPanel = JPanel()
val elevationPanel = JPanel() val elevationPanel = JPanel()
val scalefactorPanel = JPanel()
turbidityControl.preferredSize = Dimension(45, 18)
albedoControl.preferredSize = Dimension(45, 18)
elevationControl.preferredSize = Dimension(45, 18)
scalefactorControl.preferredSize = Dimension(45, 18)
turbidityPanel.add(JLabel("Turbidity")) turbidityPanel.add(JLabel("Turbidity"))
turbidityPanel.add(turbidityControl) turbidityPanel.add(turbidityControl)
@@ -208,9 +246,13 @@ class Application : Game() {
elevationPanel.add(JLabel("Elevation")) elevationPanel.add(JLabel("Elevation"))
elevationPanel.add(elevationControl) elevationPanel.add(elevationControl)
scalefactorPanel.add(JLabel("Scaling Factor"))
scalefactorPanel.add(scalefactorControl)
mainPanel.add(turbidityPanel) mainPanel.add(turbidityPanel)
mainPanel.add(albedoPanel) mainPanel.add(albedoPanel)
mainPanel.add(elevationPanel) mainPanel.add(elevationPanel)
mainPanel.add(scalefactorPanel)
this.isVisible = true this.isVisible = true
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
@@ -228,7 +270,11 @@ class Application : Game() {
} }
elevationControl.addChangeListener { elevationControl.addChangeListener {
app.elevation = Math.toRadians((elevationControl.value as Int).toDouble()) app.elevation = Math.toRadians(elevationControl.value as Double)
}
scalefactorControl.addChangeListener {
app.scalefactor = (scalefactorControl.value as Double).toFloat()
} }
} }

View File

@@ -160,8 +160,10 @@ object ArHosekSkyModel {
// internal definitions // internal definitions
private class DoubleArrayPtr(val arr: DoubleArray, var ptrOffset: Int) { private class DoubleArrayPtr(val arr: DoubleArray, var ptrOffset: Int) {
init {
if (ptrOffset < 0) throw IllegalArgumentException("Negative ptrOffset: $ptrOffset")
}
operator fun get(i: Int) = arr[ptrOffset + i] operator fun get(i: Int) = arr[ptrOffset + i]
} }
private class DoubleArrayArrayPtr(var arr: Array<DoubleArray>, var ptrOffset: Int) { private class DoubleArrayArrayPtr(var arr: Array<DoubleArray>, var ptrOffset: Int) {
@@ -185,6 +187,8 @@ object ArHosekSkyModel {
albedo: Double, albedo: Double,
solar_elevation: Double solar_elevation: Double
) { ) {
if (turbidity < 1) throw IllegalArgumentException("Turbidity must be equal to or greater than 1 (got $turbidity)")
var elev_matrix: DoubleArrayPtr var elev_matrix: DoubleArrayPtr
val int_turbidity = turbidity.toInt() val int_turbidity = turbidity.toInt()
@@ -193,7 +197,6 @@ object ArHosekSkyModel {
val solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0)) val solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0))
// alb 0 low turb // alb 0 low turb
elev_matrix = DoubleArrayPtr(dataset, 9 * 6 * (int_turbidity - 1)) elev_matrix = DoubleArrayPtr(dataset, 9 * 6 * (int_turbidity - 1))
@@ -672,13 +675,13 @@ object ArHosekSkyModel {
state.configs[channel], state.configs[channel],
theta, theta,
gamma gamma
) * state.radiances[channel]; ) * state.radiances[channel]
} }
private const val pieces = 45 private const val pieces = 45
private const val order = 4 private const val order = 4
fun arhosekskymodel_sr_internal( private fun arhosekskymodel_sr_internal(
state: ArHosekSkyModelState, state: ArHosekSkyModelState,
turbidity: Int, turbidity: Int,
wl: Int, wl: Int,
@@ -686,7 +689,7 @@ object ArHosekSkyModel {
): Double { ): Double {
var pos = (pow(2.0 * elevation / MATH_PI, 1.0 / 3.0) * pieces).toInt() // floor var pos = (pow(2.0 * elevation / MATH_PI, 1.0 / 3.0) * pieces).toInt() // floor
if (pos > 44) pos = 44; if (pos > 44) pos = 44
val break_x = pow((pos.toDouble() / pieces.toDouble()), 3.0) * (MATH_PI * 0.5) val break_x = pow((pos.toDouble() / pieces.toDouble()), 3.0) * (MATH_PI * 0.5)
@@ -773,7 +776,7 @@ object ArHosekSkyModel {
val singamma = sin(gamma) val singamma = sin(gamma)
var sc2 = 1.0 - ar2 * singamma * singamma var sc2 = 1.0 - ar2 * singamma * singamma
if (sc2 < 0.0) sc2 = 0.0 if (sc2 < 0.0) sc2 = 0.0
var sampleCosine = sqrt (sc2); var sampleCosine = sqrt(sc2)
// The following will be improved in future versions of the model: // The following will be improved in future versions of the model:
// here, we directly use fitted 5th order polynomials provided by the // here, we directly use fitted 5th order polynomials provided by the
@@ -791,9 +794,9 @@ object ArHosekSkyModel {
ldCoefficient[4] * pow(sampleCosine, 4.0) + ldCoefficient[4] * pow(sampleCosine, 4.0) +
ldCoefficient[5] * pow(sampleCosine, 5.0) ldCoefficient[5] * pow(sampleCosine, 5.0)
direct_radiance *= darkeningFactor; direct_radiance *= darkeningFactor
return direct_radiance; return direct_radiance
} }
fun arhosekskymodel_solar_radiance( fun arhosekskymodel_solar_radiance(
@@ -816,7 +819,7 @@ object ArHosekSkyModel {
wavelength wavelength
) )
return direct_radiance + inscattered_radiance; return direct_radiance + inscattered_radiance
} }
} }

View File

@@ -194,6 +194,8 @@ object DatasetSpectral {
solarDataset720 solarDataset720
) )
val waves = floatArrayOf(320f, 360f, 400f, 440f, 480f, 520f, 560f, 600f, 640f, 680f, 720f)
val limbDarkeningDataset320 = doubleArrayOf(0.087657, 0.767174, 0.658123, -1.02953, 0.703297, -0.186735) val limbDarkeningDataset320 = doubleArrayOf(0.087657, 0.767174, 0.658123, -1.02953, 0.703297, -0.186735)
val limbDarkeningDataset360 = doubleArrayOf(0.122953, 1.01278, 0.238687, -1.12208, 1.17087, -0.424947) val limbDarkeningDataset360 = doubleArrayOf(0.122953, 1.01278, 0.238687, -1.12208, 1.17087, -0.424947)

View File

@@ -4,7 +4,7 @@ import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath import com.jme3.math.FastMath
import net.torvald.colourutil.CIELabUtil.darkerLab import net.torvald.colourutil.darkerLab
import net.torvald.terrarum.AppLoader import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.Second import net.torvald.terrarum.Second
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid

View File

@@ -87,3 +87,4 @@ infix fun Long.shake(other: Long): Long {
} }
val TWO_PI = Math.PI * 2.0 val TWO_PI = Math.PI * 2.0
val HALF_PI = Math.PI / 2.0

View File

@@ -1,2 +1,20 @@
package net.torvald.terrarum.tests package net.torvald.terrarum.tests
import net.torvald.colourutil.CIEXYZ
import net.torvald.colourutil.getXYZUsingIntegral
import net.torvald.colourutil.toRGB
import net.torvald.colourutil.toRGBRaw
fun main() {
val waves = floatArrayOf(485f,495f,505f,515f,525f,535f,545f,555f,565f)
val samples = floatArrayOf( 0f,0.2f,0.5f,1f, 1f, 1f,0.5f,0.2f,0f)
val xyz = getXYZUsingIntegral(waves, samples)
val srgb = xyz.toRGB()
println(xyz)
println(srgb)
println(CIEXYZ(100f/3f, 100f/3f, 100f/3f).toRGB())
}

View File

@@ -1,10 +1,10 @@
package net.torvald.terrarum.tests package net.torvald.terrarum.tests
import net.torvald.colourutil.CIEXYZUtil.linearise
import net.torvald.colourutil.CIEXYZUtil.unLinearise
import net.torvald.colourutil.ColourUtil.getLuminosity import net.torvald.colourutil.ColourUtil.getLuminosity
import net.torvald.colourutil.ColourUtil.getLuminosityQuick import net.torvald.colourutil.ColourUtil.getLuminosityQuick
import net.torvald.colourutil.RGB import net.torvald.colourutil.RGB
import net.torvald.colourutil.linearise
import net.torvald.colourutil.unLinearise
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import kotlin.system.measureNanoTime import kotlin.system.measureNanoTime

View File

@@ -1,15 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4"> <module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JVM 12" allPlatforms="JVM [12]">
<compilerSettings />
<compilerArguments>
<option name="jvmTarget" value="12" />
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">

Binary file not shown.

BIN
work_files/skylight/XYZJCGT.pdf LFS Normal file

Binary file not shown.