mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
101.83k stars 35.31k forks source link

Weird r164 WebGL renderer regression with GLB model #28420

Closed AndyGura closed 4 months ago

AndyGura commented 4 months ago

Description

After upgrading three.js from 0.163.0 to 0.164.0 or 0.164.1 one particular GLB model from my library breaks the renderer when camera looks at it, it leaves the "trail" on the screen, where only the background image visible. I'm not sure how to describe it in a more informative way TBH, see the screenshot and attached codepen

Reproduction steps

  1. open this CodePen example
  2. move camera to the left and see that lambo car can be seen without issues
  3. replace three@0.163.0 with three@0.164.1 in HTML
  4. move camera to the left again and see the issue

OR

  1. add this glb to scene
  2. add some mesh behind this glb to see the bug
  3. add two directional lights (optional?)
  4. move camera

Code

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

// Scenes
const scene = new THREE.Scene();

// Sizes
let width = window.innerWidth;
let height = window.innerHeight;

// Renderer
const renderer = new THREE.WebGLRenderer({ 
  preserveDrawingBuffer: true,
  background: 0xffffff,
});
    renderer.outputColorSpace = THREE.SRGBColorSpace;
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(width, height);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);

// Camera
const camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
camera.position.set(4, 9, 6);
camera.up.set(0, 0, 1);

const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 5);
camera.lookAt(0, 0, 5);

const sun = new THREE.DirectionalLight(0xffffff, 3);
sun.position.set(200, 150, 120);
scene.add(sun);
const sky = new THREE.DirectionalLight(0xaaaaff, 0.4);
sky.position.set(-200, -150, 20);
scene.add(sky);

for (let i = -2; i < 2; i++) {
  for (let j = -2; j < 2; j++) {
    new GLTFLoader().load(
      "https://gg-web-demos.guraklgames.com/assets/fly-city/city_tile.glb",
      (gltf) => {
        gltf.scene.position.set(i * 70, j * 70, 0);
        scene.add( gltf.scene );
      }
    );
  }
}
new GLTFLoader().load(
  "https://gg-web-demos.guraklgames.com/assets/fly-city/lambo/body.glb",
  (gltf) => {
    gltf.scene.position.set(10, 0, 0);
    scene.add( gltf.scene );
  }
);

const envMap = new THREE.CubeTextureLoader()
  .setPath(`https://gg-web-demos.guraklgames.com/assets/fly-city/`)
  .load([
  'sky_nx.png', 'sky_px.png',
  'sky_py.png', 'sky_ny.png',
  'sky_pz.png', 'sky_nz.png',
]);
envMap.format = THREE.RGBAFormat;
envMap.mapping = THREE.CubeReflectionMapping;
scene.background = envMap;

function render(time) {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();

// Resize
function resize() {
  width = window.innerWidth;
  height = window.innerHeight;
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}
window.addEventListener('resize', resize);

Live example

CodePen

Screenshots

0.163.0 Знімок_20240518_204900

0.164.0(1) Знімок_20240518_204920

Version

r164

Device

Desktop

Browser

Chrome

OS

Linux

WestLangley commented 4 months ago

To clarify, the artifacts occur when zooming out.

If I set preserveDrawingBuffer: false, the artifacts disappear for me.

Alternatively, call renderer.clear() in the render loop, and the artifacts disappear.

Confirmed with git bisect, the change in behavior was introduced in #28118.

Mugen87 commented 4 months ago

As a quick workaround, remove preserveDrawingBuffer: true from your scene. You don't need it anyway and it is also slower to keep in set to true. Besides, WebGLRenderer has no background parameter. outputColorSpace is already THREE.SRGBColorSpace so there is no need to set it explicitely.

Mugen87 commented 4 months ago

More simplified test case: https://jsfiddle.net/uwom15j7/1/

The expected behavior would be white trails of the cube. However, you see flickering all over the mesh.

Mugen87 commented 4 months ago

This issue also happens with r163: https://jsfiddle.net/yjxsed1f/

Edit: Even with r120.

I suspect this is related how the (mesh-based) backgrounds are implemented. Looks like a depth related issue since what you see is essentially z fighting, imo.

Mugen87 commented 4 months ago

@AndyGura Why do you use preserveDrawingBuffer: true in your scene? Is there a special reason we currently overlook?

AndyGura commented 4 months ago

@Mugen87 and @WestLangley thanks for advise, setting preserveDrawingBuffer to false indeed solves the problem in my example. I do not remember why exactly it was set to true in my project, this example is oversimplified squeeze from project with big codebase.

Regarding @Mugen87 example, although the problem looks like mine, it can be reproduced with r163. But my original problem does not appear in r163 and appears in r164, so it looks like regression? Or you mean that it was "hidden" somehow up until r164?

Mugen87 commented 4 months ago

Or you mean that it was "hidden" somehow up until r164?

Yes. I suspect the same root cause but it was overshadowed up to r164. I believe if the simplified fiddle would work, the original codepen would work, too.

Mugen87 commented 4 months ago

I have eventually found the issue. It is indeed a regression!

Thanks for reporting the issue.