81 lines
2.4 KiB
Haxe
81 lines
2.4 KiB
Haxe
package armory.renderpath;
|
|
|
|
import kha.FastFloat;
|
|
import kha.graphics4.TextureFormat;
|
|
import kha.graphics4.Usage;
|
|
|
|
import iron.data.WorldData;
|
|
|
|
import armory.math.Helper;
|
|
|
|
class Nishita {
|
|
|
|
public static var data: NishitaData = null;
|
|
|
|
public static function recompute(world: WorldData) {
|
|
if (world == null || world.raw.sun_direction == null) return;
|
|
if (data == null) data = new NishitaData();
|
|
|
|
// TODO
|
|
data.recompute(1.0, 1.0, 1.0);
|
|
}
|
|
}
|
|
|
|
class NishitaData {
|
|
static inline var LUT_WIDTH = 16;
|
|
|
|
/** Maximum ray height as defined by Cycles **/
|
|
static inline var MAX_HEIGHT = 60000;
|
|
|
|
static inline var RAYLEIGH_SCALE = 8e3;
|
|
static inline var MIE_SCALE = 1.2e3;
|
|
|
|
public var optDepthLUT: kha.Image;
|
|
|
|
public function new() {}
|
|
|
|
function getOzoneDensity(height: FastFloat): FastFloat {
|
|
if (height < 10000.0 || height >= 40000.0) {
|
|
return 0.0;
|
|
}
|
|
if (height < 25000.0) {
|
|
return (height - 10000.0) / 15000.0;
|
|
}
|
|
return -((height - 40000.0) / 15000.0);
|
|
}
|
|
|
|
/**
|
|
The RGBA texture layout looks as follows:
|
|
R = Rayleigh optical depth at height \in [0, 60000]
|
|
G = Mie optical depth at height \in [0, 60000]
|
|
B = Ozone optical depth at height \in [0, 60000]
|
|
A = Unused
|
|
**/
|
|
public function recompute(densityFacAir: FastFloat, densityFacDust: FastFloat, densityFacOzone: FastFloat) {
|
|
optDepthLUT = kha.Image.create(LUT_WIDTH, 1, TextureFormat.RGBA32, Usage.StaticUsage);
|
|
|
|
var textureData = optDepthLUT.lock();
|
|
for (i in 0...LUT_WIDTH) {
|
|
// Get the height for each LUT pixel i (in [-1, 1] range)
|
|
var height = (i / LUT_WIDTH) * 2 - 1;
|
|
|
|
// Use quadratic height for better horizon precision
|
|
// See https://sebh.github.io/publications/egsr2020.pdf (5.3)
|
|
height = 0.5 + 0.5 * Helper.sign(height) * Math.sqrt(Math.abs(height));
|
|
height *= MAX_HEIGHT; // Denormalize
|
|
|
|
// Make sure we use 32 bit floats
|
|
var optDepthRayleigh: FastFloat = Math.exp(-height / RAYLEIGH_SCALE) * densityFacAir;
|
|
var optDepthMie: FastFloat = Math.exp(-height / MIE_SCALE) * densityFacDust;
|
|
var optDepthOzone: FastFloat = getOzoneDensity(height) * densityFacOzone;
|
|
|
|
// 10 is the maximum density, so we divide by it to be able to use normalized values
|
|
textureData.set(i * 4 + 0, Std.int(optDepthRayleigh * 255 / 10));
|
|
textureData.set(i * 4 + 1, Std.int(optDepthMie * 255 / 10));
|
|
textureData.set(i * 4 + 2, Std.int(optDepthOzone * 255 / 10));
|
|
textureData.set(i * 4 + 3, 255); // Unused
|
|
}
|
|
optDepthLUT.unlock();
|
|
}
|
|
}
|