Skip to content

Instantly share code, notes, and snippets.

@fijisoo
Forked from donmccurdy/README.md
Created August 27, 2021 22:07
Show Gist options
  • Save fijisoo/6cf0ea51314f73c2cbcc0df9d4f0a848 to your computer and use it in GitHub Desktop.
Save fijisoo/6cf0ea51314f73c2cbcc0df9d4f0a848 to your computer and use it in GitHub Desktop.

Revisions

  1. @donmccurdy donmccurdy revised this gist Nov 27, 2019. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,8 @@
    # legacythree2gltf.js

    Converts legacy JSON models (created by three.js Blender exporter, for THREE.JSONLoader) to glTF 2.0. When original `.blend` files are available, prefer direct export from Blender 2.8+.
    Converts legacy JSON models (created by the three.js Blender exporter, for THREE.JSONLoader) to glTF 2.0. When original `.blend` files are available, prefer direct export from Blender 2.80+.

    > **NOTE:** JSON files created with `.toJSON()` use a newer JSON format, which isn't deprecated, and these are still supported by THREE.ObjectLoader. This converter does not support that newer type of JSON file.
    Installation:

  2. @donmccurdy donmccurdy revised this gist Nov 27, 2019. 2 changed files with 5 additions and 5 deletions.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ Converts legacy JSON models (created by three.js Blender exporter, for THREE.JSO
    Installation:

    ```
    npm install canvas vblob
    npm install canvas vblob three
    ```

    Usage:
    8 changes: 4 additions & 4 deletions legacythree2gltf.js
    Original file line number Diff line number Diff line change
    @@ -4,10 +4,10 @@ const fs = require( 'fs' );
    const path = require( 'path' );
    const Canvas = require( 'canvas' );
    const { Blob, FileReader } = require( 'vblob' );
    THREE = require( '../../build/three.js' );
    require( '../../examples/js/loaders/deprecated/LegacyJSONLoader.js' );
    require( '../../examples/js/exporters/GLTFExporter.js' );
    require( '../../examples/js/utils/BufferGeometryUtils.js' );
    THREE = global.THREE = require( 'three' );
    require( 'three/examples/js/loaders/deprecated/LegacyJSONLoader.js' );
    require( 'three/examples/js/exporters/GLTFExporter.js' );
    require( 'three/examples/js/utils/BufferGeometryUtils.js' );

    if ( process.argv.length <= 2 ) {

  3. @donmccurdy donmccurdy created this gist Nov 27, 2019.
    19 changes: 19 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    # legacythree2gltf.js

    Converts legacy JSON models (created by three.js Blender exporter, for THREE.JSONLoader) to glTF 2.0. When original `.blend` files are available, prefer direct export from Blender 2.8+.

    Installation:

    ```
    npm install canvas vblob
    ```

    Usage:

    ```
    ./legacythree2gltf.js model.json --optimize
    ```

    Known issues:
    - [ ] Creates `.gltf` files with embedded Data URIs. Optimize to `.glb` using glTF-Pipeline to reduce file size.
    - [ ] Limited support for morph targets (https://github.com/mrdoob/three.js/pull/15011)
    155 changes: 155 additions & 0 deletions legacythree2gltf.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,155 @@
    #!/usr/bin/env node

    const fs = require( 'fs' );
    const path = require( 'path' );
    const Canvas = require( 'canvas' );
    const { Blob, FileReader } = require( 'vblob' );
    THREE = require( '../../build/three.js' );
    require( '../../examples/js/loaders/deprecated/LegacyJSONLoader.js' );
    require( '../../examples/js/exporters/GLTFExporter.js' );
    require( '../../examples/js/utils/BufferGeometryUtils.js' );

    if ( process.argv.length <= 2 ) {

    console.log( `Usage: ${path.basename( __filename )} model.json [ --optimize ]` );
    process.exit( - 1 );

    }

    var file = process.argv[ 2 ];
    var optimize = process.argv.indexOf( '--optimize' ) > 0;
    var resourceDirectory = THREE.LoaderUtils.extractUrlBase( file );

    //

    // Patch global scope to imitate browser environment.
    global.window = global;
    global.Blob = Blob;
    global.FileReader = FileReader;
    global.THREE = THREE;
    global.document = {
    createElement: ( nodeName ) => {

    if ( nodeName !== 'canvas' ) throw new Error( `Cannot create node ${nodeName}` );

    const canvas = new Canvas( 256, 256 );
    // This isn't working — currently need to avoid toBlob(), so export to embedded .gltf not .glb.
    // canvas.toBlob = function () {
    // return new Blob([this.toBuffer()]);
    // };
    return canvas;

    }
    };

    //

    // Load legacy JSON file and construct a mesh.

    var jsonContent = fs.readFileSync( file, 'utf8' );
    var loader = new THREE.LegacyJSONLoader();
    var { geometry, materials } = loader.parse( JSON.parse( jsonContent ), resourceDirectory );

    var mesh;
    var boneDefs = geometry.bones || [];
    var animations = geometry.animations || [];
    var hasVertexColors = geometry.colors.length > 0;

    geometry = new THREE.BufferGeometry().fromGeometry( geometry );

    // Remove unnecessary vertex colors and groups added during BufferGeometry conversion.
    if ( ! hasVertexColors ) geometry.removeAttribute( 'color' );
    if ( geometry.groups.length === 1 ) geometry.clearGroups();

    if ( ! materials ) {

    materials = new THREE.MeshStandardMaterial( { color: 0x888888, roughness: 1, metalness: 0 } );

    }

    if ( optimize ) {

    geometry = THREE.BufferGeometryUtils.mergeVertices( geometry );

    }

    if ( boneDefs.length ) {

    var { roots, bones } = initBones( boneDefs );
    mesh = new THREE.SkinnedMesh( geometry, materials );
    roots.forEach( ( bone ) => mesh.add( bone ) );
    mesh.updateMatrixWorld( true );
    mesh.bind( new THREE.Skeleton( bones ), mesh.matrixWorld );
    mesh.normalizeSkinWeights();

    } else {

    mesh = new THREE.Mesh( geometry, materials );

    }

    //

    // Export to glTF.
    var exporter = new THREE.GLTFExporter();
    exporter.parse( mesh, ( json ) => {

    var content = JSON.stringify( json );
    fs.writeFileSync( path.basename( file, '.json' ) + '.gltf', content, 'utf8' );

    }, { binary: false, animations } );

    //

    /** Previously SkinnedMesh.initBones(). */
    function initBones( boneDefs ) {

    var bones = [], bone, gbone;
    var i, il;

    // first, create array of 'Bone' objects from geometry data

    for ( i = 0, il = boneDefs.length; i < il; i ++ ) {

    gbone = boneDefs[ i ];

    // create new 'Bone' object

    bone = new THREE.Bone();
    bones.push( bone );

    // apply values

    bone.name = gbone.name;
    bone.position.fromArray( gbone.pos );
    bone.quaternion.fromArray( gbone.rotq );
    if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );

    }

    // second, create bone hierarchy
    var roots = [];

    for ( i = 0, il = boneDefs.length; i < il; i ++ ) {

    gbone = boneDefs[ i ];

    if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {

    // subsequent bones in the hierarchy

    bones[ gbone.parent ].add( bones[ i ] );

    } else {

    // topmost bone, immediate child of the skinned mesh

    roots.push( bones[ i ] );

    }

    }

    return { roots, bones };

    }