Search code examples
three.jsaframegltf

How do I get a gltfpack-processed model to appear in A-Frame?


I compressed my models and textures with gltfpack and now they are invisible in A-Frame 1.1.0. In gltfpack, I used -tc to convert the texture files to BasisU and left everything else as is. When I loaded them in A-Frame, the models aren't there. Interestingly, the models work in Don McCurdy's viewer. Update: there is a relevant Javascript console message

THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures.

So it appears I'm misusing Three.js.

Here is a bare Glitch showing the issue. There should be two models visible in the scene but only the unprocessed one is there. Anyone know I could fix it?


Solution

  • The models are working with Don's viewer because he isn't using the standard gltf-model component, but uses a raw threejs loader(with multiple extras):

    const loader = new GLTFLoader().setCrossOrigin('anonymous');
    loader.setDRACOLoader(new DRACOLoader().setDecoderPath('./wasm/'));
    loader.setKTX2Loader(new KTX2Loader().detectSupport(renderer));
    

    Afaik the KTX2Loader on the threejs repo is available only as a module (here), so I've managed to make it work by creating my own module which imports the KTX2Loader. In a nutshell:

    // probably only need the KTX2Loader since aframe gives access to 
    // the GLTFLoader and DRACOLoader.
    import { GLTFLoader } from './path_to_three/examples/jsm/loaders/GLTFLoader.js';
    import { KTX2Loader } from './path_to_three/examples/jsm/loaders/KTX2Loader.js';
    import { DRACOLoader } from './path_to_three/examples/jsm/loaders/DRACOLoader.js';
    
    // this is a 'minimal' version of the gltf-component,
    // a more faithful one is linked later on
    module.exports.Component = 
    AFRAME.registerComponent("full-gltf-model", 
       schema: { type: 'model' },
       init: function() { 
          const loader = new GLTFLoader().setCrossOrigin('anonymous')
                   .setDRACOLoader(new DRACOLoader().setDecoderPath('./wasm/'))
                   .setKTX2Loader(new KTX2Loader().detectSupport(renderer));
          var src = this.data;
          // load the model:
          loader.load(src, 
             function gltfLoaded(gltfModel) {
                let model = self.model = gltfModel.scene || gltfModel.scenes[0];
                // assuming el is an entity;
                el.setObject3D("mesh", model);
             }, undefined /* in progress */, 
             function error(err) {
                console.log("error:", err);         
          })
       }
    })
    

    I've bundled it with browserify (browserify index.js -p esmify > dist/full-gltf-model.js), and used like this:

    <!-- Somewhere in the scripts -->
    <script src="dist/full-gltf-model.js>
    <!-- Somewhere in the scene -->
    <a-entity full-gltf-model="#model"></a-entity>
    

    You can check it out here. The models are straight from Your glitch (credited to you ofc).

    Feel free to check out the directory with the component and package.json. I'm pretty sure the bundle contains already defined stuff (1Mb even with only the KTX2Loader imported o.O), so there definitely is room for improvement. Still this seems like a good start :)