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

View file

@ -11,14 +11,14 @@ class Uniforms {
public static function register() { public static function register() {
iron.object.Uniforms.externalTextureLinks = [textureLink]; iron.object.Uniforms.externalTextureLinks = [textureLink];
iron.object.Uniforms.externalVec2Links = []; iron.object.Uniforms.externalVec2Links = [vec2Link];
iron.object.Uniforms.externalVec3Links = [vec3Link]; iron.object.Uniforms.externalVec3Links = [vec3Link];
iron.object.Uniforms.externalVec4Links = []; iron.object.Uniforms.externalVec4Links = [];
iron.object.Uniforms.externalFloatLinks = [floatLink]; iron.object.Uniforms.externalFloatLinks = [floatLink];
iron.object.Uniforms.externalIntLinks = []; 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) { switch (link) {
case "_nishitaLUT": { case "_nishitaLUT": {
if (armory.renderpath.Nishita.data == null) armory.renderpath.Nishita.recompute(Scene.active.world); 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; 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; var v: Vec4 = null;
switch (link) { switch (link) {
#if arm_hosek #if arm_hosek
@ -173,6 +173,23 @@ class Uniforms {
return v; 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> { public static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
switch (link) { switch (link) {
#if rp_dynres #if rp_dynres

View file

@ -1,6 +1,7 @@
package armory.renderpath; package armory.renderpath;
import kha.FastFloat; import kha.FastFloat;
import kha.arrays.Float32Array;
import kha.graphics4.TextureFormat; import kha.graphics4.TextureFormat;
import kha.graphics4.Usage; import kha.graphics4.Usage;
@ -18,15 +19,28 @@ class Nishita {
public static var data: NishitaData = null; public static var data: NishitaData = null;
/** /**
Recompute the nishita lookup table. Call this function after updating Recomputes the nishita lookup table after the density settings changed.
the sky density settings. Do not call this method on every frame (it's slow)!
**/ **/
public static function recompute(world: WorldData) { 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(); if (data == null) data = new NishitaData();
// TODO var density = world.raw.nishita_density;
data.computeLUT(new Vec3(1.0, 1.0, 1.0)); 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['sun_direction'] = list(world.arm_envtex_sun_direction)
out_world['turbidity'] = world.arm_envtex_turbidity out_world['turbidity'] = world.arm_envtex_turbidity
out_world['ground_albedo'] = world.arm_envtex_ground_albedo 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') 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('vec3 sunDir', link='_sunDirection')
curshader.add_uniform('sampler2D nishitaLUT', link='_nishitaLUT', included=True, curshader.add_uniform('sampler2D nishitaLUT', link='_nishitaLUT', included=True,
tex_addr_u='clamp', tex_addr_v='clamp') 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 planet_radius = 6360e3 # Earth radius used in Blender
ray_origin_z = planet_radius + node.altitude 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 = '' sun = ''
if node.sun_disc: if node.sun_disc:
@ -399,7 +400,7 @@ def parse_sky_nishita(node: bpy.types.ShaderNodeTexSky, state: ParserState) -> v
size = math.cos(theta) size = math.cos(theta)
sun = f'* sun_disk(n, sunDir, {size}, {node.sun_intensity})' 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: 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_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_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_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_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_receive_shadow = BoolProperty(name="Receive Shadow", description="Requires forward render path", default=True)
bpy.types.Material.arm_overlay = BoolProperty(name="Overlay", default=False) bpy.types.Material.arm_overlay = BoolProperty(name="Overlay", default=False)