This commit is contained in:
Moritz Brückner 2021-03-31 20:33:52 +02:00
parent ffcc5fcceb
commit c5be90d0b0
3 changed files with 17 additions and 31 deletions

View file

@ -66,25 +66,15 @@ vec3 nishita_lookupLUT(const float height, const float sunTheta) {
return textureLod(nishitaLUT, coords, 0.0).rgb; return textureLod(nishitaLUT, coords, 0.0).rgb;
} }
/* Approximates the density of ozone for a given sample height. Values taken from Cycles code. */ /* See raySphereIntersection() in armory/Sources/renderpath/Nishita.hx */
float nishita_density_ozone(const float height) {
return (height < 10000.0 || height >= 40000.0) ? 0.0 : (height < 25000.0 ? (height - 10000.0) / 15000.0 : -((height - 40000.0) / 15000.0));
}
/* ray-sphere intersection that assumes
* the sphere is centered at the origin.
* No intersection when result.x > result.y */
vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) { vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
float a = dot(rd, rd); float a = dot(rd, rd);
float b = 2.0 * dot(rd, r0); float b = 2.0 * dot(rd, r0);
float c = dot(r0, r0) - (sr * sr); float c = dot(r0, r0) - (sr * sr);
float d = (b*b) - 4.0*a*c; float d = (b*b) - 4.0*a*c;
if (d < 0.0) return vec2(1e5,-1e5); // If d < 0.0 the ray does not intersect the sphere
return vec2( return (d < 0.0) ? vec2(1e5,-1e5) : vec2((-b - sqrt(d))/(2.0*a), (-b + sqrt(d))/(2.0*a));
(-b - sqrt(d))/(2.0*a),
(-b + sqrt(d))/(2.0*a)
);
} }
/* /*
@ -94,43 +84,41 @@ vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
* rPlanet: planet radius * rPlanet: planet radius
*/ */
vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet) { 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);
p.y = min(p.y, nishita_rsi(r0, r, rPlanet).x); p.y = min(p.y, nishita_rsi(r0, r, rPlanet).x);
float iStepSize = (p.y - p.x) / float(nishita_iSteps); float iStepSize = (p.y - p.x) / float(nishita_iSteps);
// Initialize the primary ray time. // Primary ray time
float iTime = 0.0; float iTime = 0.0;
// Initialize accumulators for Rayleigh and Mie scattering. // Accumulators for Rayleigh and Mie scattering.
vec3 totalRlh = vec3(0,0,0); vec3 totalRlh = vec3(0,0,0);
vec3 totalMie = vec3(0,0,0); vec3 totalMie = vec3(0,0,0);
// Initialize optical depth accumulators for the primary ray. // Optical depth accumulators for the primary ray
float iOdRlh = 0.0; float iOdRlh = 0.0;
float iOdMie = 0.0; float iOdMie = 0.0;
// Calculate the Rayleigh and Mie phases. // Calculate the Rayleigh and Mie phases
float mu = dot(r, pSun); float mu = dot(r, pSun);
float mumu = mu * mu; float mumu = mu * mu;
float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu); float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu);
float pMie = 3.0 / (8.0 * PI) * ((1.0 - nishita_mie_dir_sq) * (mumu + 1.0)) / (pow(1.0 + nishita_mie_dir_sq - 2.0 * mu * nishita_mie_dir, 1.5) * (2.0 + nishita_mie_dir_sq)); float pMie = 3.0 / (8.0 * PI) * ((1.0 - nishita_mie_dir_sq) * (mumu + 1.0)) / (pow(1.0 + nishita_mie_dir_sq - 2.0 * mu * nishita_mie_dir, 1.5) * (2.0 + nishita_mie_dir_sq));
// Sample the primary ray. // Sample the primary ray
for (int i = 0; i < nishita_iSteps; i++) { for (int i = 0; i < nishita_iSteps; i++) {
// Calculate the primary ray sample position. // Calculate the primary ray sample position and height
vec3 iPos = r0 + r * (iTime + iStepSize * 0.5); vec3 iPos = r0 + r * (iTime + iStepSize * 0.5);
// Calculate the height of the sample.
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) * nishitaDensity.x * iStepSize; float odStepRlh = exp(-iHeight / nishita_rayleigh_scale) * nishitaDensity.x * iStepSize;
float odStepMie = exp(-iHeight / nishita_mie_scale) * nishitaDensity.y * iStepSize; float odStepMie = exp(-iHeight / nishita_mie_scale) * nishitaDensity.y * iStepSize;
// Accumulate optical depth. // Accumulate optical depth
iOdRlh += odStepRlh; iOdRlh += odStepRlh;
iOdMie += odStepMie; iOdMie += odStepMie;
@ -142,22 +130,20 @@ vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const floa
// Apply dithering to reduce visible banding // Apply dithering to reduce visible banding
jODepth += mix(-1000, 1000, random(r.xy)); jODepth += mix(-1000, 1000, random(r.xy));
// Calculate attenuation. // Calculate attenuation
vec3 attn = exp(-( vec3 attn = exp(-(
nishita_mie_coeff * (iOdMie + jODepth.y) nishita_mie_coeff * (iOdMie + jODepth.y)
+ (nishita_rayleigh_coeff) * (iOdRlh + jODepth.x) + (nishita_rayleigh_coeff) * (iOdRlh + jODepth.x)
+ nishita_ozone_coeff * jODepth.z + nishita_ozone_coeff * jODepth.z
)); ));
// Accumulate scattering. // Accumulate scattering
totalRlh += odStepRlh * attn; totalRlh += odStepRlh * attn;
totalMie += odStepMie * attn; totalMie += odStepMie * attn;
// Increment the primary ray time.
iTime += iStepSize; iTime += iStepSize;
} }
// Calculate and return the final color.
return nishita_sun_intensity * (pRlh * nishita_rayleigh_coeff * totalRlh + pMie * nishita_mie_coeff * totalMie); return nishita_sun_intensity * (pRlh * nishita_rayleigh_coeff * totalRlh + pMie * nishita_mie_coeff * totalMie);
} }
@ -166,7 +152,7 @@ vec3 sun_disk(const vec3 n, const vec3 light_dir, const float disk_size, const f
float dist = distance(n, light_dir) / disk_size; float dist = distance(n, light_dir) / disk_size;
// Darken the edges of the sun // Darken the edges of the sun
// [Hill: 28, 60] (code from [Nec96]) // [Hill: 28, 60] (according to [Nec96])
float invDist = 1.0 - dist; float invDist = 1.0 - dist;
float mu = sqrt(invDist * invDist); float mu = sqrt(invDist * invDist);
vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col)); vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col));

View file

@ -177,9 +177,9 @@ class Uniforms {
var v: Vec4 = null; var v: Vec4 = null;
switch (link) { switch (link) {
case "_nishitaDensity": { case "_nishitaDensity": {
v = iron.object.Uniforms.helpVec;
var w = Scene.active.world; var w = Scene.active.world;
if (w != null) { if (w != null) {
v = iron.object.Uniforms.helpVec;
// We only need Rayleigh and Mie density in the sky shader -> Vec2 // We only need Rayleigh and Mie density in the sky shader -> Vec2
v.x = w.raw.nishita_density[0]; v.x = w.raw.nishita_density[0];
v.y = w.raw.nishita_density[1]; v.y = w.raw.nishita_density[1];

View file

@ -296,7 +296,7 @@ def parse_tex_sky(node: bpy.types.ShaderNodeTexSky, out_socket: bpy.types.NodeSo
if node.sky_type == 'PREETHAM' or node.sky_type == 'HOSEK_WILKIE': if node.sky_type == 'PREETHAM' or node.sky_type == 'HOSEK_WILKIE':
if node.sky_type == 'PREETHAM': if node.sky_type == 'PREETHAM':
log.warn('Preetham sky model is not supported, using Hosek Wilkie sky model instead') log.info('Info: Preetham sky model is not supported, using Hosek Wilkie sky model instead')
return parse_sky_hosekwilkie(node, state) return parse_sky_hosekwilkie(node, state)