Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fog plus height and noise #1313

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"concat": "^1.0.3",
"eslint": "^6.8.0",
"fs-extra": "^8.1.0",
"jsdoc": "3.6.3",
"jsdoc": "^3.6.11",
"terser": "^4.3.8",
"zip-lib": "^0.2.1"
}
Expand Down
5 changes: 5 additions & 0 deletions src/SSAO.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ x3dom.SSAO.blur = function ( stateManager, gl, scene, ssaoTexture, depthTexture,

stateManager.useProgram( sp );

// shader always requires fog uniforms
var fog = scene.getFog();
sp.fogRange = fog._vf.visibilityRange;
sp.fogType = ( fog._vf.fogType == "LINEAR" ) ? 0.0 : 1.0;

sp.SSAOTexture = 0;
sp.depthTexture = 1;

Expand Down
17 changes: 7 additions & 10 deletions src/gfx_webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2298,11 +2298,14 @@ x3dom.gfx_webgl = ( function ()
var fog = scene.getFog();

// THINKABOUTME: changed flag only works as long as lights and fog are global
if ( fog && changed )
if ( fog._vf.visibilityRange && changed )
{
sp.fogColor = fog._vf.color.toGL();
sp.fogRange = fog._vf.visibilityRange;
sp.fogType = ( fog._vf.fogType == "LINEAR" ) ? 0.0 : 1.0;

sp.fogHeight = fog._vf.fogHeight;
sp.fogNoise = fog._vf.fogNoise / 100.0;
}

// Set Material
Expand Down Expand Up @@ -5117,22 +5120,16 @@ x3dom.gfx_webgl = ( function ()
}
}

if ( properties.FOG ) { sp.fogType = 999.0; } // draw without fog first

gl.drawArrays( gl.TRIANGLES, 0, 6 ); //shadows

// Set fog
// Mask shadows w/ fog, no need for fogColor, fogHeight, fogNoise.
if ( properties.FOG )
{
var fog = scene.getFog();
this.stateManager.blendColor( fog._vf.color.r, fog._vf.color.g, fog._vf.color.b, 1.0 );
this.stateManager.blendFunc( gl.CONSTANT_COLOR, gl.ONE_MINUS_SRC_COLOR );
sp.fogColor = fog._vf.color.toGL();
sp.fogRange = fog._vf.visibilityRange;
sp.fogType = ( fog._vf.fogType == "LINEAR" ) ? 0.0 : 1.0;
gl.drawArrays( gl.TRIANGLES, 0, 6 ); // fog
}

gl.drawArrays( gl.TRIANGLES, 0, 6 );

// cleanup
var nk = shadowIndex + 1;
for ( k = 0; k < nk; k++ )
Expand Down
24 changes: 24 additions & 0 deletions src/nodes/EnvironmentalEffects/X3DFogNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,30 @@ x3dom.registerNodeType(
* @instance
*/
this.addField_SFFloat( ctx, "visibilityRange", 0 );

/**
* FogHeight is in world scale like visibilityRange.
andreasplesch marked this conversation as resolved.
Show resolved Hide resolved
* @var {x3dom.fields.SFFloat} fogHeight
* @memberof x3dom.nodeTypes.X3DFogNode
* @initvalue 0
* @range [0, -inf]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[0, inf]

* @field x3dom
* @instance
* Hint: Start with a low visibilityRange (very dense fog) to adjust fogHeight.
*/
this.addField_SFFloat( ctx, "fogHeight", 1000000.0 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the default value be 0 ?


/**
* fogNoise is 3d noise which create "clouds" within the fog.
* @var {x3dom.fields.SFFloat} fogNoise
* @memberof x3dom.nodeTypes.X3DFogNode
* @initvalue 0
* @range [0, -inf]
* @field x3dom
* @instance
* Hint: Useful range is 0.0-3.0, larger values create more "clouds".
*/
this.addField_SFFloat( ctx, "fogNoise", 0.0 );
},
{
}
Expand Down
24 changes: 13 additions & 11 deletions src/shader/ShaderDynamic.js
Original file line number Diff line number Diff line change
Expand Up @@ -742,17 +742,14 @@ x3dom.shader.DynamicShader.prototype.generateFragmentShader = function ( gl, pro
}
}

//Fog
if ( properties.FOG )
{
shader += x3dom.shader.fog();
}
if ( properties.FOG ) { shader += x3dom.shader.fog(); }

if ( properties.LIGHTS || properties.CLIPPLANES )
// same as vertex shader but with fragPositionWS for fogNoise (w/ or w/out lights)
if ( properties.LIGHTS || properties.FOG || properties.CLIPPLANES )
{
shader += "varying vec4 fragPosition;\n";
shader += "varying vec4 fragPositionWS;\n";
shader += "uniform float isOrthoView;\n";
shader += "varying vec4 fragPositionWS;\n";
}

//Lights
Expand Down Expand Up @@ -1350,11 +1347,16 @@ x3dom.shader.DynamicShader.prototype.generateFragmentShader = function ( gl, pro

shader += "color = " + x3dom.shader.encodeGamma( properties, "color" ) + ";\n";

//Fog
if ( properties.FOG && !properties.SHADOW )
if ( properties.FOG )
{
shader += "float f0 = calcFog(fragEyePosition);\n";
shader += "color.rgb = fogColor * (1.0-f0) + f0 * (color.rgb);\n";
shader += " float f0 = calcFog(fragEyePosition);\n" +
//" color.rgb = fogColor * (1.0-f0) + f0 * (color.rgb);\n";
// use original fog above, or optional Noise and Height below
" if (fogNoise > 0.0) f0 += mix( 0.0, 0.1, noise3d(fragPositionWS.xyz * fogNoise) );\n" +
" vec3 fcol = fogColor * (1.0-f0) + f0 * (color.rgb);\n" +
" float fogH = clamp( (fragPositionWS.y - fogHeight) / fogRange, 0.0, 1.0);\n" +
" float fogD = clamp( (f0 - fogRange), 0.0, 1.0);\n" +
" color.rgb = mix( fcol, color.rgb, max(fogH,fogD) ) ;\n";
}

shader += "gl_FragColor = color;\n";
Expand Down
46 changes: 27 additions & 19 deletions src/shader/ShaderParts.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,33 @@ x3dom.shader.twoSidedMaterial = function ()
********************************************************************************/
x3dom.shader.fog = function ()
{
var shaderPart = "uniform vec3 fogColor;\n" +
"uniform float fogType;\n" +
"uniform float fogRange;\n" +
"varying vec3 fragEyePosition;\n" +
"float calcFog(in vec3 eye) {\n" +
" float f0 = 0.0;\n" +
" if(fogType == 0.0) {\n" +
" if(length(eye) < fogRange){\n" +
" f0 = (fogRange-length(eye)) / fogRange;\n" +
" }\n" +
" }else{\n" +
" if(length(eye) < fogRange){\n" +
" f0 = exp(-length(eye) / (fogRange-length(eye) ) );\n" +
" }\n" +
" }\n" +
" f0 = clamp(f0, 0.0, 1.0);\n" +
" return f0;\n" +
"}\n";

var shaderPart = "uniform vec3 fogColor;\n" +
"uniform float fogType;\n" +
"uniform float fogRange;\n" +
"varying vec3 fragEyePosition;\n" +

"uniform float fogHeight;\n" +
"uniform float fogNoise;\n" +
// simple 3d noise: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83
"float mod289(float x){return x - floor(x * (1.0 / 289.0)) * 289.0;}\n\n" +
"vec4 mod289(vec4 x){return x - floor(x * (1.0 / 289.0)) * 289.0;}\n\n" +
"vec4 perm(vec4 x){return mod289(((x * 34.0) + 1.0) * x);}\n\n" +
"float noise3d(vec3 p){vec3 a = floor(p);vec3 d = p - a;d = d * d * (3.0 - 2.0 * d);vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);vec4 k1 = perm(b.xyxy);vec4 k2 = perm(k1.xyxy + b.zzww);vec4 c = k2 + a.zzzz;vec4 k3 = perm(c);vec4 k4 = perm(c + 1.0);vec4 o1 = fract(k3 * (1.0 / 41.0));vec4 o2 = fract(k4 * (1.0 / 41.0));vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);return o4.y * d.y + o4.x * (1.0 - d.y);}\n\n" +

"float calcFog(in vec3 eye) {\n" +
" float f0 = 0.0;\n" +
" if(fogType == 0.0) {\n" +
" if(length(eye) < fogRange){\n" +
" f0 = (fogRange-length(eye)) / fogRange;\n" +
" }\n" +
" }else{\n" +
" if(length(eye) < fogRange){\n" +
" f0 = exp(-length(eye) / (fogRange-length(eye) ) );\n" +
" }\n" +
" }\n" +
" f0 = clamp(f0, 0.0, 1.0);\n" +
" return f0;\n" +
"}\n";
return shaderPart;
};

Expand Down
19 changes: 16 additions & 3 deletions src/shader/ShaderSSAOBlur.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ x3dom.shader.SSAOBlurShader.prototype.generateFragmentShader = function ( gl )
shader += " precision mediump float;\n";
shader += "#endif\n\n";

shader += "uniform sampler2D SSAOTexture;\n" +
shader += "uniform sampler2D SSAOTexture;\n" +
"uniform sampler2D depthTexture;\n" +
"uniform float nearPlane;\n" +
"uniform float farPlane;\n" +
Expand All @@ -66,6 +66,9 @@ x3dom.shader.SSAOBlurShader.prototype.generateFragmentShader = function ( gl )

shader += x3dom.shader.SSAOShader.depthReconsructionFunctionCode();

// always use fog uniforms, even if no fog
shader += x3dom.shader.fog();

shader += "void main(void) {\n" +
" float sum = 0.0;\n" +
" float numSamples = 0.0;\n" +
Expand All @@ -78,8 +81,18 @@ x3dom.shader.SSAOBlurShader.prototype.generateFragmentShader = function ( gl )
" numSamples++;\n" +
" }}}\n" +
" float intensity = mix(1.0,sum/numSamples,amount);\n" +
" gl_FragColor = vec4(intensity,intensity,intensity,1.0);\n" +
"}\n";

//" gl_FragColor = vec4(intensity,intensity,intensity,1.0);\n" +
" vec4 color = vec4(intensity,intensity,intensity,1.0);\n" +

" if (fogRange > 0.0) {\n" +
" vec3 eye = vec3(0.0, 0.0, referenceDepth);\n" +
" float f0 = calcFog(eye);\n" +
" color.rgb = vec3(1.0, 1.0, 1.0) * (1.0 - f0) + f0 * color.rgb;\n" +
" }\n" +

" gl_FragColor = color;\n" +
"}\n";

var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
gl.shaderSource( fragmentShader, shader );
Expand Down
25 changes: 12 additions & 13 deletions src/shader/ShaderShadowRendering.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,7 @@ x3dom.shader.ShadowRenderingShader.prototype.generateFragmentShader = function (
" projCoords = projCoords / projCoords.w;\n" +
" projCoords.xy = vPosition;\n" +
" vec4 eyeCoords = inverseProj*projCoords;\n";
if ( properties.FOG )
{
shader +=
" if (fogType < 2.0) {\n" +
" vec3 eye = eyeCoords.xyz / eyeCoords.w;\n" +
" float f0 = calcFog( eye );\n" +
" color = vec4( 1.0 - f0, 1.0 - f0, 1.0 - f0, 1.0 );\n" +
" }\n" +
" else {\n";
}

shader +=
" float shadowValue = 1.0;\n" +
//reconstruct world and view coordinates from scene map
Expand Down Expand Up @@ -172,15 +163,23 @@ x3dom.shader.ShadowRenderingShader.prototype.generateFragmentShader = function (
shader += " }\n";
}

shader += " color = " + x3dom.shader.encodeGamma( {}, "vec4(shadowValue, shadowValue, shadowValue, 1.0)" ) + " ;\n";
if ( properties.FOG ) { shader += " }\n"; }
// In principle we should fix the place where this is multplied in instead
// of overcompensating for the subsequent error from here. This way of doing
// gamma correction explots the rule that (a*b)^x = a^x * b^x (x being the
// gamma coefficient), i.e. the umbra is corrected for now, the penumbra
// is incorrect and full light is zero here so unaffected as well.
shader += " color = " + x3dom.shader.encodeGamma( {}, "vec4(shadowValue, shadowValue, shadowValue, 1.0)" ) + " ;\n";

if ( properties.FOG )
{
shader += " vec3 fragEyePosition = eyeCoords.xyz / eyeCoords.w;\n" +
" float f0 = calcFog(fragEyePosition);\n" +
" color.rgb = vec3(1.0, 1.0, 1.0) * (1.0 - f0) + f0 * color.rgb;\n";
}

shader += " gl_FragColor = color;\n" +
"}\n";
"}\n";

var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
gl.shaderSource( fragmentShader, shader );
gl.compileShader( fragmentShader );
Expand Down