Illuminating a basic geometry with a volumetric material

I’m trying to apply light effects to the volumetric cloud shader example. (three.js webgl2 - volume - cloud)
(three.js/webgl2_volume_cloud.html at 580ca9046b6544c2accb54118c970e23b7eae8a5 · mrdoob/three.js · GitHub)

I’ve been able to do it with one pointLight by passing manually the pointLight position in world space, and calculating the distance between it and the fragment. The longest the distance, the smaller the light intensity is. This works alright for the lightning effect I’m triying to apply.

vec3 add_light(vec3 color){
  vec3 light_value = pointLights[0].color;
  float intensity = 1.0 / (abs(distance(vecPos.xyz, uFlashPosition.xyz)) / uLightDistDivider);
  light_value *= intensity;
  return vec3(color * light_value);
}

The thing is, I would like to be able to do this with the Three light uniforms, but in those the position of the point lights aren’t passed. My guess is that the color of the light passed through these uniforms is calculated accounting the geometry and light position, so there is no need for it.

So I tried to do it using the pointLight uniforms, following this [guide/demo](Custom shaders with Three.JS: Uniforms, textures and lighting – Algorithmic Pensieve](Custom shaders with Three.JS: Uniforms, textures and lighting – Algorithmic Pensieve). But the lightning is all messed up. It works correctly for a basic color shader, but doesn’t work for a volumetric one.

Vertex

struct PointLight {
  vec3 color;
  vec3 position;
  float distance;
  float decay;
};

uniform vec3 cameraPos;
uniform PointLight pointLights[NUM_POINT_LIGHTS];

varying vec2 vUv;
varying vec3 vecPos;

out vec3 vOrigin;
out vec3 vDirection;

varying vec3 vNormal;
varying vec3 vSurfaceToLight;

void main() {
  vUv = uv;

  vecPos = (modelViewMatrix * vec4(position, 1.0)).xyz;

  vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz;
  vDirection = position - vOrigin;  
  vNormal = (modelViewMatrix * vec4(normal, 0.0)).xyz;

  gl_Position = projectionMatrix * vec4(vecPos, 1.);
}

Fragment

vec3 add_light(vec3 color){
  if(NUM_POINT_LIGHTS <= 0){
    return color;
  }

  vec4 addedLights = vec4(0.0, 0.0, 0.0, 1.0);

  for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
      vec3 lightDirection = normalize(vecPos
                            - pointLights[l].position);
      addedLights.rgb += clamp(dot(-lightDirection,
                               vNormal), 0.0, 1.0)
                         * pointLights[l].color
                         * 1.0;
  }

  return color * addedLights.rbg;
}

Material

new THREE.ShaderMaterial( {
    glslVersion: THREE.GLSL3,
    uniforms: THREE.UniformsUtils.merge( [
        THREE.UniformsLib[ "lights" ],
        {
            base: { value: new THREE.Color( 0x798aa0 ) },
            map: { value: this.texture },
            cameraPos: { value: new THREE.Vector3() },
            threshold: { value: 0.25 },
            opacity: { value: 0.25 },
            range: { value: 0.1 },
            steps: { value: 100 },
            frame: { value: 0 },
            // These aren't used in this solution
            uLightIntensity: { value: 1.0 },
            uLightColor: { value: new THREE.Color( 0xFFFFFF ) },
            uLightDistDivider: { value: 1.0 },
            uFlashPosition: { value: new THREE.Vector3() },
        },
    ]),
    vertexShader,
    fragmentShader,
    side: THREE.FrontSide,
    transparent: true,
    lights: true,
    depthWrite: false,
} );

This is the result

What I would like to archive is this kind of effect where the light not only illuminates whats facing it, but it also passes through and illuminates the inside, losing intensity.

Are there any documentations, guides, tutorials, or anything that could help me understand how to apply this kind of effects?

openvdb/VolumeToFog.js at 013ccad46093da36ef33a1c24ab3e94abc579723 · mjurczyk/openvdb · GitHub - may help, but please keep in mind this is heavily work-in-progress :face_with_peeking_eye:

2 Likes

Simondev just released a youtube video about this subject; How Big Budget AAA Games Render Clouds - YouTube

The code will (eventually) show up on his github :smile:

2 Likes

Yes! I’ve just found out about his channel after posting this and left a message in that video and he just replyed. The code is already up, and was built in threejs. I’ll be studying it in the following days.

1 Like

Thank you so much! I’ll check it out as soon as I can