Skip to content

WebGPURenderer: Fog applied twice in all materials #31462

@davidhckh

Description

@davidhckh

Description

When using WebGPURenderer, Fog is applied twice, no matter the material. This results in a noticeably harsher color transition between the fog’s near and far values.

I realized it by setting outputNode = output in MeshBasicNodeMaterial. The color transition is smoother when doing so.
Not sure about the expected behavior in that case. Output should either be the final color with fog or the final color without fog.

Looking at the compiled shader confirms the duplication. The fog blending appears twice:

Output = vec4( mix( Output.xyz, f_nodeUniform20, smoothstep( f_nodeUniform21, f_nodeUniform22, ( - v_positionView.z ) ) ), Output.w );
    
    // result
    
    fragColor = vec4( mix( Output.xyz, f_nodeUniform20, smoothstep( f_nodeUniform21, f_nodeUniform22, ( - v_positionView.z ) ) ), Output.w );

Reproduction steps

  1. Create a scene using WebGPURenderer
  2. Setup Fog
  3. Create a MeshBasicMaterial and MeshBasicNodeMaterial
  4. Set outputNode = output on the MeshBasicNodeMaterial
    The fog looks different than on the MeshBasicMaterial

Code

const width = window.innerWidth;
const height = window.innerHeight;
const aspect = width / height;
const frustumSize = 20;

const camera = new OrthographicCamera(
  (-frustumSize * aspect) / 2,
  (frustumSize * aspect) / 2,
  frustumSize / 2,
  -frustumSize / 2,
  0.01,
  100
);
camera.position.z = 15;

const controls = new OrbitControls(camera, canvas);

const scene = new Scene();

const geometry = new TorusKnotGeometry(2, 0.6, 100, 16);

const material1 = new MeshBasicNodeMaterial({
  color: "red",
});

const material2 = new MeshBasicNodeMaterial({
  color: "red",
  outputNode: output,
});

const material3 = new MeshBasicMaterial({
  color: "red",
});

const mesh1 = new Mesh(geometry, material1);
const mesh2 = new Mesh(geometry, material2);
const mesh3 = new Mesh(geometry, material3);

mesh1.position.x = -8;
mesh2.position.x = 0;
mesh3.position.x = 8;

scene.add(mesh1);
scene.add(mesh2);
scene.add(mesh3);

const renderer = new WebGPURenderer({
  canvas,
  forceWebGL: true,
  alpha: false,
});

renderer.setSize(width, height);

scene.fog = new Fog("blue", 14, 15);

const tick = () => {
  renderer.render(scene, camera);

  controls.update();

  window.requestAnimationFrame(tick);
};

tick();

Live example

Screenshots

In this video, I’m toggling outputNode = output to demonstrate the visual difference in fog behavior:

2025-07-20.19-48-17.mp4

Version

0.178.0

Device

Desktop

Browser

Chrome

OS

MacOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions