Skip to content

Commit

Permalink
volume scatter emission
Browse files Browse the repository at this point in the history
  • Loading branch information
harry7557558 committed Feb 12, 2024
1 parent dff0bf2 commit be3ac83
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 70 deletions.
128 changes: 88 additions & 40 deletions implicit3-rt/frag-render.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -540,18 +540,25 @@ vec3 sampleHenyeyGreenstein(vec3 wi, float g) {
uniform float rOpacity;
uniform float rIor;
uniform float rRoughness1;
uniform float rRoughness2;
uniform float rEmission1;
uniform float rEmission2;
uniform float rAbsorb1;
uniform float rAbsorb2;
uniform float rVEmission1;
uniform float rScatter1;
uniform float rScatter2;
uniform float rVDecayAbs;
uniform float rVDecaySca;
uniform float rScatterAniso1;

uniform float rRoughness2;
uniform float rEmission2;
uniform float rAbsorb2;
uniform float rVAbsorbHue;
uniform float rVAbsorbChr;
uniform float rVAbsorbBri;
uniform float rVDecayAbs;
uniform float rVEmission2;
// uniform float rVEmissionTint2;
#define rVEmissionTint2 1.0
uniform float rScatter2;
uniform float rScatterAniso2;
uniform float rVDecaySca;
uniform float rVSharpSca;

uniform float rLightIntensity;
uniform float rLightSky;
Expand Down Expand Up @@ -580,7 +587,8 @@ vec3 mainRender(vec3 ro, vec3 rd) {

bool is_inside = false;

for (float iter = ZERO; iter < 32.; iter++) {
float maxLightPathDepth = float({%LIGHT_PATH_DEPTH%});
for (float iter = ZERO; iter < maxLightPathDepth; iter++) {
if (iter != 0.) ro += 1e-4*length(ro) * rd;
vec3 n, min_n = vec3(0);
float t, min_t = 1e6;
Expand Down Expand Up @@ -616,6 +624,7 @@ vec3 mainRender(vec3 ro, vec3 rd) {
if (is_inside) {
float A_abs = rAbsorb1/(1.0-rAbsorb1);
float A_sca = pow(rScatter1, 0.5); A_sca = 0.5*A_sca/(1.0-A_sca);
float A_emi = 4.0 * pow(rVEmission1, 2.2);
// scattering
float r = randf();
float tsc = -log(r) / A_sca;
Expand All @@ -627,45 +636,82 @@ vec3 mainRender(vec3 ro, vec3 rd) {
col = prev_col;
material = MAT_SCATTER;
}
// absorption
float absorb = A_abs*min(min_t,clip_t1);
m_col *= pow(clamp(colmid, 0.0, 1.0), vec3(absorb));
// absorption, emission
float t = min(min_t,clip_t1);
vec3 emit = vec3(A_emi) * colmid;
vec3 a = pow(clamp(colmid, 0.00001, 0.99999), vec3(A_abs));
vec3 w = pow(a, vec3(t));
t_col += m_col * emit * (A_abs==0.0 ? vec3(t) : (w-1.0)/log(a));
m_col *= w;
}
else {
float z0 = -uClipBox.z;
// scattering
float k0_sca = pow(rVDecaySca, 1.0);
k0_sca = 1.0 / (k0_sca/(1.0-k0_sca)); // reciprocal layer thickness
float A0_sca = 1.0-pow(1.0-rScatter2,2.0);
A0_sca = 0.01*A0_sca/(1.0-A0_sca) / (0.1*k0_sca); // scattering intensity
if (randf() < rVSharpSca) {
// scattering p(t) = exp( -A/k (1-exp(-kt)) ),
// from 1 to exp(-A/k)
// https://www.desmos.com/calculator/vjguq3x7wm
vec2 tb = vec2((z0-ro.z)/rd.z, (z0+1.0/k0_sca-ro.z)/rd.z);
tb = max(rd.z<0.0 ? tb.yx : tb, 0.0);
if (tb.y > 0.0) {
float A_sca = A0_sca;
float k_sca = k0_sca / (tb.y-tb.x);
float r = randf();
float rth = exp(-A_sca/k_sca);
if ((r > rth || k_sca < 0.0) && uOutput == OUTPUT_RADIANCE) {
float tsc = tb.x - log(mix(rth, 1.0, r)) / A_sca;
if (tsc < min_t) {
min_t = tsc, min_n = vec3(0);
min_ro = ro+rd*tsc, min_rd = rd;
col = prev_col;
material = MAT_SCATTER;
}
}
}
}
else {
// scattering p(t) = exp( -A/k (1-exp(-kt)) ),
// from 1 to exp(-A/k)
// floating point bad here - large scattering with small decay
// https://www.desmos.com/calculator/wo63zpczge
// if this is fixed we can increase k0_sca for "thin snow" effect
float A_sca = A0_sca * exp(-k0_sca*(ro.z-z0));
float k_sca = k0_sca * rd.z;
float r = randf();
if ((r > exp(-A_sca/k_sca) || k_sca < 0.0)
&& uOutput == OUTPUT_RADIANCE) {
float tsc = -log(1.0+k_sca/A_sca*log(r))/k_sca;
if (tsc < min_t) {
min_t = tsc, min_n = vec3(0);
min_ro = ro+rd*tsc, min_rd = rd;
col = prev_col;
material = MAT_SCATTER;
}
}
}
// absorption
// density A0 exp(-k0 z)
// = A0 exp(-k0 (ro.z + rd.z t))
// = (A0 exp(-k0 ro.z)) exp(-k0 rd.z t)
// = A exp(-k t)
// total absorption density A/k (1-exp(-kt))
// scattering p(t) = exp( -A/k (1-exp(-kt)) ),
// from 1 to exp(-A/k)
float k0_abs = pow(rVDecayAbs, 0.8); k0_abs = 0.2 / (k0_abs/(1.0-k0_abs));
float k0_sca = pow(rVDecaySca, 1.0); k0_sca = 1.0 / (k0_sca/(1.0-k0_sca));
float k0_abs = pow(rVDecayAbs, 0.8);
k0_abs = 0.2 / (k0_abs/(1.0-k0_abs));
float A0_abs = rAbsorb2/(1.0-rAbsorb2);
float A0_sca = 1.0-pow(1.0-rScatter2,2.0); A0_sca = 0.01*A0_sca/(1.0-A0_sca) / (0.1*k0_sca);
float z0 = -uClipBox.z;
vec3 c_abs = getAbsorbColor();
vec3 c_emi = 0.5 * pow(rVEmission2, 2.2) * mix(vec3(1), c_abs, rVEmissionTint2);
float A_abs = A0_abs * exp(-k0_abs*(ro.z-z0));
float A_sca = A0_sca * exp(-k0_sca*(ro.z-z0));
float k_abs = k0_abs * rd.z;
float k_sca = k0_sca * rd.z;
// scattering
// floating point bad here - large scattering with small decay
// https://www.desmos.com/calculator/wo63zpczge
// if this is fixed we can increase k0_sca for "thin snow" effect
float r = randf();
if ((r > exp(-A_sca/k_sca) || k_sca < 0.0)
&& uOutput == OUTPUT_RADIANCE) {
float tsc = -log(1.0+k_sca/A_sca*log(r))/k_sca;
if (tsc < min_t) {
min_t = tsc, min_n = vec3(0);
min_ro = ro+rd*tsc, min_rd = rd;
col = prev_col;
material = MAT_SCATTER;
}
}
// absorption
float absorb = A_abs / k_abs * (1.0-exp(-k_abs*min_t));
m_col *= pow(getAbsorbColor(), vec3(absorb));
vec3 c = pow(clamp(c_abs, 0.00001, 0.99999), vec3(A_abs));
vec3 A = -log(c);
vec3 w = exp(k_abs == 0.0 ? -vec3(min_t) : A/k_abs*(exp(-k_abs*min_t)-1.0));
if (A0_abs != 0.0)
t_col += m_col * c_emi * (1.0-w) / A;
m_col *= w;
}

// buffer
Expand Down Expand Up @@ -700,12 +746,14 @@ vec3 mainRender(vec3 ro, vec3 rd) {
ro = min_ro, rd = min_rd;
min_n = dot(rd,min_n) < 0. ? min_n : -min_n;
if (material == MAT_SCATTER) {
// isotropic scattering
rd = sampleUniformSphere();
// rd = sampleUniformSphere();
float aniso = is_inside ? rScatterAniso1 : rScatterAniso2;
aniso = 1.5*aniso - 0.5*pow(aniso,3.0);
rd = sampleHenyeyGreenstein(rd, aniso);
}
else if (material == MAT_PLANE) {
// rd -= 2.0*dot(rd, min_n) * min_n, m_col *= col;
t_col += rEmission2 * m_col * col;
t_col += 2.0*rEmission2 * m_col * col;
rd = sampleBrdf(-rd, min_n, pow(rRoughness2,2.0), 1.0, col, m_col);
}
else if (material == MAT_OBJECT) {
Expand Down
75 changes: 53 additions & 22 deletions implicit3-rt/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<option value="0.004">high</option>
<option value="0.001">ultra high</option>
</select>precision</span>&ensp;
<br />
<span><select id="select-spp" title="Maximum samples per pixel">
<option value="1">2⁰</option>
<option value="4"></option>
Expand All @@ -66,7 +67,17 @@
<option value="1024">2¹⁰</option>
<option value="4096">2¹²</option>
<option value="16384">2¹⁴</option>
</select>spp</span>
</select>spp</span>&ensp;
<span><select id="select-light-path-depth" title="Maximum light path depth">
<option value="8">8</option>
<option value="16">16</option>
<option value="32">32</option>
<option value="64" selected>64</option>
<option value="128">128</option>
<option value="256">256</option>
<option value="512">512</option>
<option value="1024">1024</option>
</select>path depth</span>
<br />
<span title="Shape clipping boundary"><select id="select-clip">
<option value="1" selected>box</option>
Expand Down Expand Up @@ -107,7 +118,7 @@
<br />
</div>
<hr />
<div class="foldable" id='folder-appearance' folded="true">
<div class="foldable" id='folder-object' folded="true">
<span class="foldable-name"></span>
<span title="Surface color mode"><select id="select-color">
<option value="0">default</option>
Expand All @@ -123,29 +134,49 @@
<span title="object index of refraction"><span>ior</span>&nbsp;<input type="range" id="slider-ior" style="width:80px" /></span>
<br />
<span>roughness</span>
<span title="object roughness"><input type="range" id="slider-roughness1" style="width:80px" /></span>
<span title="plane roughness"><input type="range" id="slider-roughness2" style="width:80px" /></span>
<br />
<span>emission</span>
<span title="object surface emission"><input type="range" id="slider-emission1" style="width:80px" /></span>
<span title="plane emission"><input type="range" id="slider-emission2" style="width:80px" /></span>
<span title="object roughness"><input type="range" id="slider-roughness1" style="width:70px" /></span>
<span>emit</span>
<span title="object surface emission intensity"><input type="range" id="slider-emission1" style="width:60px" /></span>
<br />
<span>absorption</span>
<span title="object volume absorption"><input type="range" id="slider-absorb1" style="width:80px" /></span>
<span title="atmospheric absorption"><input type="range" id="slider-absorb2" style="width:80px" /></span>
<span>absorb</span>
<span title="object volume absorption intensity"><input type="range" id="slider-absorb1" style="width:60px" /></span>
<span>emit[v]</span>
<span title="object volume emission intensity"><input type="range" id="slider-vemission1" style="width:60px" /></span>
<br />
<span>scattering</span>
<span title="object volume scattering"><input type="range" id="slider-scatter1" style="width:80px" /></span>
<span title="atmospheric scattering"><input type="range" id="slider-scatter2" style="width:80px" /></span>
<span>scatter</span>
<span title="object volume scattering intensity"><input type="range" id="slider-scatter1" style="width:80px" /></span>
<span>aniso</span>
<span title="object volume scattering anisotropy"><input type="range" id="slider-scatter-aniso1" style="width:60px" /></span>
<br />
<span>decay:</span>
<span title="near-ground absorption layer thickness">a&nbsp;<input type="range" id="slider-vdecay-abs" style="width:80px" /></span>
<span title="near-ground scattering layer thickness">s&nbsp;<input type="range" id="slider-vdecay-sca" style="width:80px" /></span>
<br />
<span>absorb:</span>
<span title="atmospheric absorption hue">h&nbsp;<input type="range" id="slider-vabsorb-hue" style="width:100px" /></span>
<span title="atmospheric absorption chroma">c&nbsp;<input type="range" id="slider-vabsorb-chr" style="width:60px" /></span>
<span style="display:none">l&nbsp;<input type="range" id="slider-vabsorb-bri" style="width:35px" /></span>
</div>
<hr />
<div class="foldable" id='folder-background' folded="true">
<span class="foldable-name"></span>
<span>roughness</span>
<span title="plane roughness"><input type="range" id="slider-roughness2" style="width:70px" /></span>
<span>emit</span>
<span title="plane emission intensity"><input type="range" id="slider-emission2" style="width:60px" /></span>
<br />
<span>absorb</span>
<span title="atmospheric absorption intensity"><input type="range" id="slider-absorb2" style="width:80px" /></span>
<span title="near-ground absorption layer thickness">depth&nbsp;<input type="range" id="slider-vdecay-abs" style="width:60px" /></span>
<br />
&emsp;
<span title="atmospheric absorption hue">hue&nbsp;<input type="range" id="slider-vabsorb-hue" style="width:90px" /></span>
<span title="atmospheric absorption chroma">chroma&nbsp;<input type="range" id="slider-vabsorb-chr" style="width:50px" /></span>
<br />
&emsp;
<span title="atmospheric emission intensity">emit[v]&nbsp;<input type="range" id="slider-vemit" style="width:80px" /></span>
<!-- <span title="atmospheric emission color tint">tint&nbsp;<input type="range" id="slider-vemit-tint" style="width:60px" /></span> -->
<br />
<span>scatter</span>
<span title="atmospheric scattering intensity"><input type="range" id="slider-scatter2" style="width:80px" /></span>
<span>aniso</span>
<span title="atmospheric scattering anisotropy"><input type="range" id="slider-scatter-aniso2" style="width:60px" /></span>
<br />
&emsp;
<span title="near-ground scattering layer thickness">depth&nbsp;<input type="range" id="slider-vdecay-sca" style="width:70px" /></span>
<span title="near-ground scattering layer boundary sharpness">sharp&nbsp;<input type="range" id="slider-vsharp-sca" style="width:70px" /></span>
<br />
</div>
<hr />
Expand Down
24 changes: 16 additions & 8 deletions implicit3-rt/script.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions scripts/render-rt.js
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ function updateShaderFunction(funCode, funGradCode, params) {
shaderSource = shaderSource.replaceAll("{%FUNGRAD%}", funGradCode);
shaderSource = shaderSource.replaceAll("{%HZ%}", params.sHz);
shaderSource = shaderSource.replaceAll("{%CLIP%}", Number(params.sClip));
shaderSource = shaderSource.replaceAll("{%LIGHT_PATH_DEPTH%}", Number(params.sLightPathDepth));
shaderSource = shaderSource.replaceAll("{%CLOSED%}", Number(params.cClosed));
shaderSource = shaderSource.replaceAll("{%FIELD%}", params.sField);
shaderSource = shaderSource.replaceAll("{%STEP_SIZE%}", params.sStep);
Expand Down

0 comments on commit be3ac83

Please sign in to comment.