Skip to content

WebGPURenderer: alphaTest not respected for shadow maps (WebGLRenderer OK) #31802

@novogrammer

Description

@novogrammer

Description

With WebGPURenderer, a mesh using MeshStandardMaterial with an alpha texture and alphaTest casts a solid quad shadow, as if the cutout were ignored. This occurs both with WebGPURenderer and with WebGPURenderer({ forceWebGL: true }). Using WebGLRenderer directly produces the expected cut-out shadow.

Reproduction steps

  1. Enable renderer.shadowMap and add a ground plane (receiveShadow = true).
  2. Create a CanvasTexture with a transparent background and a tall opaque rectangle.
  3. Use MeshStandardMaterial({ map, alphaTest: 0.5, side: DoubleSide }).
  4. Put the material on a plane (castShadow = true).
  5. Add a shadow-casting DirectionalLight.
  6. Render with WebGPURenderer → shadow is a full quad; switch to WebGLRenderer → shadow is cut out.

Code

// Toggle to compare:
// import * as THREE from "three";               // OK: WebGLRenderer
// const renderer = new THREE.WebGLRenderer({ antialias: true });
import * as THREE from "three/webgpu";           // FAIL: WebGPURenderer
const renderer = new THREE.WebGPURenderer({
  antialias: true,
  // forceWebGL: true, // also reproduces
});

renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

const camera = new THREE.PerspectiveCamera(40, innerWidth/innerHeight, 1, 3000);
camera.position.set(0, 1.5, 5);

const scene = new THREE.Scene();

// ground
const ground = new THREE.Mesh(
  new THREE.PlaneGeometry(10,10),
  new THREE.MeshStandardMaterial({ color: 0xffffff })
);
ground.rotation.x = -Math.PI/2;
ground.receiveShadow = true;
scene.add(ground);

// alpha texture: tall opaque rectangle on transparent background
function makeAlphaTexture() {
  const c = document.createElement("canvas");
  c.width = c.height = 512;
  const ctx = c.getContext("2d");
  ctx.clearRect(0,0,512,512);
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, 128, 512);
  const tex = new THREE.CanvasTexture(c);
  tex.colorSpace = THREE.SRGBColorSpace;
  return tex;
}

const plane = new THREE.Mesh(
  new THREE.PlaneGeometry(3,3),
  new THREE.MeshStandardMaterial({
    map: makeAlphaTexture(),
    alphaTest: 0.5,
    side: THREE.DoubleSide,
    // transparent: false, // default
  })
);
plane.position.set(0, 1.5, 0);
plane.castShadow = true;
scene.add(plane);

// light
const dir = new THREE.DirectionalLight(0xffffff, 5);
dir.position.set(10,10,10);
dir.castShadow = true;
scene.add(dir);

// render
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
renderer.setAnimationLoop(() => renderer.render(scene, camera));

Live example

Screenshots

Image

Version

r179

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