Add API to set Nishita density parameters

This commit is contained in:
Moritz Brückner 2021-03-26 20:59:26 +01:00
parent 845d2aff93
commit 420033c86d
6 changed files with 48 additions and 14 deletions

View file

@ -21,6 +21,7 @@
#define _SKY_GLSL_
uniform sampler2D nishitaLUT;
uniform vec2 nishitaDensity;
#ifndef PI
#define PI 3.141592
@ -91,9 +92,8 @@ vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
* r0: ray origin
* pSun: normalized sun direction
* rPlanet: planet radius
* density: (air density, dust density, ozone density)
*/
vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet, const vec3 density) {
vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet) {
// Calculate the step size of the primary ray.
vec2 p = nishita_rsi(r0, r, nishita_atmo_radius);
if (p.x > p.y) return vec3(0,0,0);
@ -127,8 +127,8 @@ vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const floa
float iHeight = length(iPos) - rPlanet;
// Calculate the optical depth of the Rayleigh and Mie scattering for this step
float odStepRlh = exp(-iHeight / nishita_rayleigh_scale) * density.x * iStepSize;
float odStepMie = exp(-iHeight / nishita_mie_scale) * density.y * iStepSize;
float odStepRlh = exp(-iHeight / nishita_rayleigh_scale) * nishitaDensity.x * iStepSize;
float odStepMie = exp(-iHeight / nishita_mie_scale) * nishitaDensity.y * iStepSize;
// Accumulate optical depth.
iOdRlh += odStepRlh;

View file

@ -11,14 +11,14 @@ class Uniforms {
public static function register() {
iron.object.Uniforms.externalTextureLinks = [textureLink];
iron.object.Uniforms.externalVec2Links = [];
iron.object.Uniforms.externalVec2Links = [vec2Link];
iron.object.Uniforms.externalVec3Links = [vec3Link];
iron.object.Uniforms.externalVec4Links = [];
iron.object.Uniforms.externalFloatLinks = [floatLink];
iron.object.Uniforms.externalIntLinks = [];
}
public static function textureLink(object: Object, mat: MaterialData, link: String): kha.Image {
public static function textureLink(object: Object, mat: MaterialData, link: String): Null<kha.Image> {
switch (link) {
case "_nishitaLUT": {
if (armory.renderpath.Nishita.data == null) armory.renderpath.Nishita.recompute(Scene.active.world);
@ -40,7 +40,7 @@ class Uniforms {
return target != null ? target.image : null;
}
public static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
public static function vec3Link(object: Object, mat: MaterialData, link: String): Null<iron.math.Vec4> {
var v: Vec4 = null;
switch (link) {
#if arm_hosek
@ -173,6 +173,23 @@ class Uniforms {
return v;
}
public static function vec2Link(object: Object, mat: MaterialData, link: String): Null<iron.math.Vec4> {
var v: Vec4 = null;
switch (link) {
case "_nishitaDensity": {
v = iron.object.Uniforms.helpVec;
var w = Scene.active.world;
if (w != null) {
// We only need Rayleigh and Mie density in the sky shader -> Vec2
v.x = w.raw.nishita_density[0];
v.y = w.raw.nishita_density[1];
}
}
}
return v;
}
public static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
switch (link) {
#if rp_dynres

View file

@ -1,6 +1,7 @@
package armory.renderpath;
import kha.FastFloat;
import kha.arrays.Float32Array;
import kha.graphics4.TextureFormat;
import kha.graphics4.Usage;
@ -18,15 +19,28 @@ class Nishita {
public static var data: NishitaData = null;
/**
Recompute the nishita lookup table. Call this function after updating
the sky density settings.
Recomputes the nishita lookup table after the density settings changed.
Do not call this method on every frame (it's slow)!
**/
public static function recompute(world: WorldData) {
if (world == null || world.raw.sun_direction == null) return;
if (world == null || world.raw.nishita_density == null) return;
if (data == null) data = new NishitaData();
// TODO
data.computeLUT(new Vec3(1.0, 1.0, 1.0));
var density = world.raw.nishita_density;
data.computeLUT(new Vec3(density[0], density[1], density[2]));
}
/** Sets the sky's density parameters and calls `recompute()` afterwards. **/
public static function setDensity(world: WorldData, densityAir: FastFloat, densityDust: FastFloat, densityOzone: FastFloat) {
if (world == null) return;
if (world.raw.nishita_density == null) world.raw.nishita_density = new Float32Array(3);
var density = world.raw.nishita_density;
density[0] = Helper.clamp(densityAir, 0, 10);
density[1] = Helper.clamp(densityDust, 0, 10);
density[2] = Helper.clamp(densityOzone, 0, 10);
recompute(world);
}
}

View file

@ -2843,6 +2843,7 @@ class ArmoryExporter:
out_world['sun_direction'] = list(world.arm_envtex_sun_direction)
out_world['turbidity'] = world.arm_envtex_turbidity
out_world['ground_albedo'] = world.arm_envtex_ground_albedo
out_world['nishita_density'] = list(world.arm_nishita_density)
disable_hdr = world.arm_envtex_name.endswith('.jpg')

View file

@ -375,11 +375,12 @@ def parse_sky_nishita(node: bpy.types.ShaderNodeTexSky, state: ParserState) -> v
curshader.add_uniform('vec3 sunDir', link='_sunDirection')
curshader.add_uniform('sampler2D nishitaLUT', link='_nishitaLUT', included=True,
tex_addr_u='clamp', tex_addr_v='clamp')
curshader.add_uniform('vec2 nishitaDensity', link='_nishitaDensity', included=True)
planet_radius = 6360e3 # Earth radius used in Blender
ray_origin_z = planet_radius + node.altitude
density = c.to_vec3((node.air_density, node.dust_density, node.ozone_density))
state.world.arm_nishita_density = [node.air_density, node.dust_density, node.ozone_density]
sun = ''
if node.sun_disc:
@ -399,7 +400,7 @@ def parse_sky_nishita(node: bpy.types.ShaderNodeTexSky, state: ParserState) -> v
size = math.cos(theta)
sun = f'* sun_disk(n, sunDir, {size}, {node.sun_intensity})'
return f'nishita_atmosphere(n, vec3(0, 0, {ray_origin_z}), sunDir, {planet_radius}, {density}){sun}'
return f'nishita_atmosphere(n, vec3(0, 0, {ray_origin_z}), sunDir, {planet_radius}){sun}'
def parse_tex_environment(node: bpy.types.ShaderNodeTexEnvironment, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:

View file

@ -326,6 +326,7 @@ def init_properties():
bpy.types.World.arm_envtex_sun_direction = FloatVectorProperty(name="Sun Direction", size=3, default=[0,0,0])
bpy.types.World.arm_envtex_turbidity = FloatProperty(name="Turbidity", default=1.0)
bpy.types.World.arm_envtex_ground_albedo = FloatProperty(name="Ground Albedo", default=0.0)
bpy.types.World.arm_nishita_density = FloatVectorProperty(name="Nishita Density", size=3, default=[1, 1, 1])
bpy.types.Material.arm_cast_shadow = BoolProperty(name="Cast Shadow", default=True)
bpy.types.Material.arm_receive_shadow = BoolProperty(name="Receive Shadow", description="Requires forward render path", default=True)
bpy.types.Material.arm_overlay = BoolProperty(name="Overlay", default=False)