Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to apply fog from a point in a three.js scene that is independent of the camera?

For example, given a terrain with an avatar on it with a camera far away overhead: is it possible to render the fog so that the avatar remains perfectly unfogged while the terrain around the avatar fades into the fog?

like image 574
shino Avatar asked Oct 06 '22 20:10

shino


1 Answers

Sure, though as far as I know, you'll have to make your own shader rather than using the ones provided with three.js. There may be a way to customize them in this way, but if there is, I'm not familiar with it.

Check out this answer on doing fog as distance from the camera. The idea, as explained there, is to pass the camera position in as a uniform to the shader, then in the vertex shader on all your objects, you find the distance from the camera position to the vertex you're transforming. You then pass that distance along as a varying to the fragment shader, and you can figure out the distance per pixel, which you use to mix between a fogged color and the object's regular color. You can see that in this example from the OpenGL ES 2.0 Programming guide.

To change it to be based on distance from the character is simple: you just pass in the character position as the uniform that you're calculating distance from instead of the camera position (in that sample code, you would replace u_eyePos with something like u_characterPos and maybe change the varying from v_eyeDist to v_characterDist). Except for any name changes, the fragment shader can be exactly the same.

So, something like this (WARNING: NOT TESTED. you're going to have to fix this up to have three.js happy with using it. There are a ton of example of that, though, like this one):

vertex shader:

uniform mat4 matViewProjection;
uniform mat4 matView;
uniform vec4 u_characterPos;

attribute vec4 rm_Vertex;
attribute vec2 rm_TexCoord0;

varying vec2 v_texCoord;
varying float v_characterDist;

void main() {
  // Transform vertex to view-space
  vec4 vViewPos = matView * rm_Vertex;

  // Compute the distance to character
  v_characterDist = length(vViewPos - u_characterPos);                  

  gl_Position = matViewProjection * rm_Vertex;
  v_texCoord    = rm_TexCoord0.xy;
}

fragment shader:

precision mediump float;

uniform vec4 u_fogColor;
uniform float u_fogMaxDist;
uniform float u_fogMinDist;
uniform sampler2D baseMap;

varying vec2 v_texCoord;
varying float v_characterDist;

float computeLinearFogFactor() {
  float factor;

  // Compute linear fog equation
  factor = (u_fogMaxDist - v_characterDist) /
        (u_fogMaxDist - u_fogMinDist );

  // Clamp in the [0,1] range
  factor = clamp(factor, 0.0, 1.0);

  return factor;            
}

void main() {
  float fogFactor = computeLinearFogFactor();
  vec4 fogColor = fogFactor * u_fogColor;
  vec4 baseColor = texture2D(baseMap, v_texCoord);

  // Compute final color as a lerp with fog factor
  gl_FragColor = baseColor * fogFactor +
               fogColor * (1.0 - fogFactor); 
}
like image 129
Brendan Kenny Avatar answered Oct 10 '22 01:10

Brendan Kenny