-
-
Notifications
You must be signed in to change notification settings - Fork 36.1k
Description
Description
Hello, I am trying to replicate the WebGL clipping-cap example and draw the clipping cap using WebGPU (with forceWebGL = true). However, just like in the provided example, the clipped object itself cannot be rendered — only the clipping cap is drawn. When I set the clipped object's renderOrder to the minimum value, or when I comment out the clipping cap’s onAfterRender callback, the clipped object can be rendered. I don’t know what is causing this issue.
When I use the Spector frame-capture tool, unfortunately, the captured frames do render the clipped object, which makes it even harder for me to investigate the root cause. Additionally, I found that when I set forceWebGL to false, the clipped object can be rendered, but the clipping cap is drawn incorrectly.
Reproduction steps
1.Running the code
2. Set the clipped object's renderOrder to the minimum value Or Comment out the clipping cap’s onAfterRender callback
3.Set forceWebGL to false
Code
import * as THREE from 'three/webgpu';
import { Inspector } from 'three/addons/inspector/Inspector.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
let camera, scene, renderer, startTime, object;
init();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.25, 16 );
camera.position.set( 5, 1.3, 3 );
scene = new THREE.Scene();
// Lights
scene.add( new THREE.AmbientLight( 0xcccccc ) );
const spotLight = new THREE.SpotLight( 0xffffff, 60 );
spotLight.angle = Math.PI / 5;
spotLight.penumbra = 0.2;
spotLight.position.set( 2, 3, 3 );
spotLight.castShadow = true;
spotLight.shadow.camera.near = 3;
spotLight.shadow.camera.far = 10;
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
spotLight.shadow.bias = - 0.002;
spotLight.shadow.radius = 4;
scene.add( spotLight );
const dirLight = new THREE.DirectionalLight( 0x55505a, 3 );
dirLight.position.set( 0, 3, 0 );
dirLight.castShadow = true;
dirLight.shadow.camera.near = 1;
dirLight.shadow.camera.far = 10;
dirLight.shadow.camera.right = 1;
dirLight.shadow.camera.left = - 1;
dirLight.shadow.camera.top = 1;
dirLight.shadow.camera.bottom = - 1;
dirLight.shadow.mapSize.width = 1024;
dirLight.shadow.mapSize.height = 1024;
scene.add( dirLight );
// Clipping planes
const localPlane1 = new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), 0 );
// Clipping Groups
const knotClippingGroup = new THREE.ClippingGroup();
knotClippingGroup.clippingPlanes = [ localPlane1, ];
scene.add( knotClippingGroup );
// Geometry
const material = new THREE.MeshPhongNodeMaterial( {
color: 0x80ee10,
shininess: 0,
side: THREE.DoubleSide,
// ***** Clipping setup (material): *****
alphaToCoverage: true
} );
const geometry = new THREE.CylinderGeometry( 2, 2 ,2, 32);
object = new THREE.Mesh( geometry, material );
object.castShadow = true;
object.renderOrder = 5;
knotClippingGroup.add( object );
createPlaneStencilGroup( geometry,1, knotClippingGroup);
const planeGeom = new THREE.PlaneGeometry( 4, 4 );
const planematerial = new THREE.MeshStandardMaterial( {
color: 0xE91E63,
metalness: 0.1,
roughness: 0.75,
stencilWrite: true,
stencilRef: 0,
stencilFunc: THREE.NotEqualStencilFunc,
stencilFail: THREE.ReplaceStencilOp,
stencilZFail: THREE.ReplaceStencilOp,
stencilZPass: THREE.ReplaceStencilOp,
} );
const po = new THREE.Mesh(planeGeom,planematerial);
po.renderOrder = 2.5;
po.onAfterRender = function ( renderer ) {
renderer.clearStencil();
};
// Renderer
localPlane1.coplanarPoint( po.position );
po.lookAt(
po.position.x - localPlane1.normal.x,
po.position.y - localPlane1.normal.y,
po.position.z - localPlane1.normal.z,
);
let group = new THREE.ClippingGroup();
scene.add(group);
group.add(po);
renderer = new THREE.WebGPURenderer( { antialias: true,forceWebGL:true,stencil:true } );
renderer.shadowMap.enabled = true;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
renderer.inspector = new Inspector();
window.addEventListener( 'resize', onWindowResize );
document.body.appendChild( renderer.domElement );
// Controls
const controls = new OrbitControls( camera, renderer.domElement );
controls.target.set( 0, 1, 0 );
controls.update();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
renderer.render( scene, camera );
}
function createPlaneStencilGroup( geometry,renderOrder, group) {
const baseMat = new THREE.MeshBasicNodeMaterial();
baseMat.depthWrite = false;
baseMat.depthTest = false;
baseMat.colorWrite = false;
baseMat.stencilWrite = true;
baseMat.stencilFunc = THREE.AlwaysStencilFunc;
// back faces
const mat0 = baseMat.clone();
mat0.side = THREE.BackSide;
mat0.stencilFail = THREE.IncrementWrapStencilOp;
mat0.stencilZFail = THREE.IncrementWrapStencilOp;
mat0.stencilZPass = THREE.IncrementWrapStencilOp;
const mesh0 = new THREE.Mesh( geometry, mat0 );
mesh0.renderOrder = renderOrder;
group.add( mesh0 );
// front faces
const mat1 = baseMat.clone();
mat1.side = THREE.FrontSide;
mat1.stencilFail = THREE.DecrementWrapStencilOp;
mat1.stencilZFail = THREE.DecrementWrapStencilOp;
mat1.stencilZPass = THREE.DecrementWrapStencilOp;
const mesh1 = new THREE.Mesh( geometry, mat1 );
mesh1.renderOrder = renderOrder;
group.add( mesh1 );
return group;
}Live example
https://jsfiddle.net/ewd9nsqa/
Screenshots
Version
r181
Device
Desktop
Browser
Chrome
OS
Windows