mrdoob / three.js

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

GLTFLoader: Loading fails when same geometry is reused with multiple skeletons. #16475

Closed donmccurdy closed 5 years ago

donmccurdy commented 5 years ago

This example contains a mesh, and that mesh is instantiated multiple times in the scene. Different instantiations assign a different skeleton/bones, so it should be treated as multiple SkinnedMesh instances sharing a single geometry:

Screen Shot 2019-05-17 at 9 56 52 AM

InfiniteSkinnedTentacle.glb.zip

Currently loading runs without errors, but nothing is rendered. Reported by @vpenades in https://github.com/donmccurdy/three-gltf-viewer/issues/147.

Three.js version
Browser
OS
Hardware Requirements (graphics card, VR Device, ...)
titansoftime commented 5 years ago

Is this related to the issue that SkeletonUtils currently works around?

https://discourse.threejs.org/t/solved-issue-with-gltfloader-and-reusing-geometry/6697

Mugen87 commented 5 years ago

I've integrated the asset in the webgl_loader_gltf example and everything looks good:

image

The code looks like so:

var container, stats, controls;
var camera, scene, renderer, mixer, clock;

init();
animate();

function init() {

    container = document.createElement( 'div' );
    document.body.appendChild( container );

    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
    camera.position.set( - 1.8, 0.9, 2.7 );

    scene = new THREE.Scene();

    clock = new THREE.Clock();

    var loader = new THREE.RGBELoader().setPath( 'textures/equirectangular/' );
    loader.load( 'pedestrian_overpass_2k.hdr', function ( texture ) {

        texture.encoding = THREE.RGBEEncoding;
        texture.minFilter = THREE.NearestFilter;
        texture.magFilter = THREE.NearestFilter;
        texture.flipY = true;

        var cubeGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: 1024 } );
        cubeGenerator.update( renderer );

        var pmremGenerator = new THREE.PMREMGenerator( cubeGenerator.renderTarget.texture );
        pmremGenerator.update( renderer );

        var pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( pmremGenerator.cubeLods );
        pmremCubeUVPacker.update( renderer );

        var envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture;

        // model

        var loader = new THREE.GLTFLoader();
        loader.load( 'models/gltf/InfiniteSkinnedTentacle.glb', function ( gltf ) {

            gltf.scene.traverse( function ( child ) {

                if ( child.isMesh ) {

                    child.material.envMap = envMap;

                }

            } );

            var animations = gltf.animations;

            mixer = new THREE.AnimationMixer( gltf.scene );
            var action = mixer.clipAction( animations[ 0 ] );
            action.play();

            scene.add( gltf.scene );

        } );

        pmremGenerator.dispose();
        pmremCubeUVPacker.dispose();

        scene.background = cubeGenerator.renderTarget;

    } );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.gammaOutput = true;
    container.appendChild( renderer.domElement );

    controls = new THREE.OrbitControls( camera, renderer.domElement );
    controls.target.set( 0, - 0.2, - 0.2 );
    controls.update();

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

    // stats
    stats = new Stats();
    container.appendChild( stats.dom );

}

function onWindowResize() {

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

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

}

//

function animate() {

    requestAnimationFrame( animate );

    var delta = clock.getDelta();

    if ( mixer ) mixer.update( delta );

    renderer.render( scene, camera );

    stats.update();

}

Interestingly, you can actually see the animated skeletons in glTF viewer.

donmccurdy commented 5 years ago

Nice, thanks! My code for determining the camera position doesn't take skinning into account when computing the bounding box, and I guess that makes a big difference in this case:

Screen Shot 2019-05-18 at 10 14 01 AM

Can consider this a bug in my viewer, then.