Skip to content

WebGPURenderer: Potential performance regression starting with r176. #32675

Description

@Jenychen1996

Description

Using WebGPURenderer, when comparing the R171 version with the R178 and dev versions, it was found that the rendering frame rate of the dev version was lower than that of the R171 version for the same model.

renderer.info.render:
{
"calls": 4960,
"frameCalls": 2,
"drawCalls": 4493,
"triangles": 1347487,
"points": 0,
"lines": 0,
"timestamp": 0,
"previousFrameCalls": 2,
"timestampCalls": 0
}

Hardware Information:
Processor: Intel(R) Xeon(R) W-2245 CPU @ 3.90GHz 3.91 GHz
Memory: 64.0 GB (63.7 GB available)
Graphics Card: NVIDIA RTX A4000

Reproduction steps

  1. Using different versions of three.js
  2. Loading models
  3. Comparing frame rate performance

Code

<html lang="en">

<head>
    <title>three.js webgl - animation retargeting</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link type="text/css" rel="stylesheet" href="main.css">
</head>

<body>

    <div id="info">
        <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - animation retargeting
    </div>

    <script type="importmap">
        {
            "imports": {
                "three": "https://raw.githack.com/mrdoob/three.js/dev/build/three.webgpu.js",
                "three/webgpu": "https://raw.githack.com/mrdoob/three.js/dev/build/three.webgpu.js",
                "three/addons/": "https://raw.githack.com/mrdoob/three.js/dev/examples/jsm/"
            }
        }
    </script>

    <script type="module">
        import * as THREE from 'three/webgpu';

        import Stats from 'three/addons/libs/stats.module.js';

        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
        import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
        import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";

        let camera, scene, renderer, stats, controls;

        init();

        function init() {
            renderer = new THREE.WebGPURenderer({
                antialias: true,
                logarithmicDepthBuffer: true,
                powerPreference: "high-performance"
            });
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setClearColor(0x000000, 0.0);
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setAnimationLoop(animate);
            document.body.appendChild(renderer.domElement);

            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xcccccc)

            camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100000);
            camera.position.set(1000, 1000, 1000);

            controls = new OrbitControls(camera, renderer.domElement);
            controls.enableDamping = true;

            stats = new Stats();
            document.body.appendChild(stats.dom);

            window.scene = scene;
            window.renderer = renderer;
            window.camera = camera;

            const light = new THREE.HemisphereLight(0xe9c0a5, 0x0175ad, 5);
            scene.add(light);

            const dirLight = new THREE.DirectionalLight(0xfff9ea, 4);
            dirLight.position.set(2, 5, 2);
            scene.add(dirLight);

            const axesHelper = new THREE.AxesHelper(500);
            scene.add(axesHelper);

            window.addEventListener('resize', onWindowResize);
            onWindowResize();

            loadGltf();
        }

        function loadGltf() {
           // Note: Perhaps you need to switch to a corresponding model dataset. When we compared it with our own business data, the frame rate dropped by about 4 frames. The model below is for example
            const url = `https://threejs.org/examples/models/gltf/LittlestTokyo.glb`;

            const dracoPath = 'https://raw.githack.com/mrdoob/three.js/dev/examples/jsm/libs/draco/gltf/';
            const gltfLoader = new GLTFLoader();
            const dracoLoader = new DRACOLoader();
            dracoLoader.setDecoderPath(dracoPath);
            dracoLoader.preload();
            gltfLoader.setDRACOLoader(dracoLoader);
            console.log('start load gltf');
            console.time('load gltf');

            let materialUUIDMap = new Map();
            gltfLoader.load(url, function (data) {
                const mesh = data.scene;
                console.timeEnd('load gltf');
                mesh.traverse(child => {
                    if (child.isMesh) {
                        let material = child.material;
                        if (!materialUUIDMap.has(material.uuid)) {
                            const {
                                uuid,
                                name,
                                side,
                                map,
                                roughness,
                                metalness
                            } = material;
                            const nodeMaterial = new THREE.MeshStandardNodeMaterial({
                                name,
                                side,
                                map,
                                roughness,
                                metalness,
                            });
                            materialUUIDMap.set(uuid, nodeMaterial);
                        }

                        child.material = materialUUIDMap.get(material.uuid);
                        child.material.needsUpdate = true;
                        material.dispose();
                        material = undefined;
                    }
                })
                // gltfMesh = mesh;
                for (var i = 0; i < 15; i++) {
                    let clonemesh = mesh.clone()

                    scene.add(clonemesh);
                }

                // scene.add(mesh);
                materialUUIDMap.clear();
                materialUUIDMap = undefined;
            })
        }

        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize(window.innerWidth, window.innerHeight);


        }

        function animate() {

            stats.update();

            controls.update();

            renderer.render(scene, camera);


        }


    </script>
</body>

</html>

Live example

Screenshots

No response

Version

r171,r178,dev

Device

Desktop

Browser

Chrome

OS

Windows

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions