LoginSignup
3
0

More than 3 years have passed since last update.

Blockbenchのjsonを読み込むファイルローダーを作ってみた

Last updated at Posted at 2019-07-15

Blockbenchで作ったMinecraftのモデルをThree.jsで表示したい!

icon.png

image.png

読み込み結果
image.png

ソースコード

2019-07-26更新。Blockbenchのバージョンアップに伴う修正

BBModelLoader.js
// こちらはエンティティ専用、ブロック用はBBModelLoaderBlock()を使用してね
//引数
//  filename: xxxx.bbmodel のようなBlockbenchのjsonファイル
//  texture_canvas_name: CanvasやIMGなどのエレメント名"#texture"など
//  only_visible: 表示設定がオンになっているパーツのみ読み込む
//  onload: コールバック関数。自動でSceneに追加しないのでここで行う事。
//    コールバック関数の戻り引数
//         object:THREE.Object3D :  グループ化されたモデル
//         parts:{name:THREE.Object3D,...} : 連想配列。各パーツを名前で取得できる
function BBModelLoader(filename, textur_canvas_name, only_visible, onload) {
    $.getJSON(filename, function (data) {
        var parts = {};
        if (data.meta && data.meta.format == "1.0" && data["cubes"] && data["outliner"]) {
            var object = new THREE.Object3D();
            object.name = data.name;
            let used_child = [];
            data.outliner.forEach(outline => {
                if (!only_visible || outline.visibility != false) {
                    // outliner
                    let outliner = new THREE.Object3D();
                    outliner.name = outline.name;
                    let origin = [
                        (outline.origin ? outline.origin[0] : 0),
                        (outline.origin ? outline.origin[1] : 0),
                        (outline.origin ? outline.origin[2] : 0),
                    ];
                    data.cubes.forEach(element => {
                        if (outline.children.indexOf(element.uuid) > -1 && (!only_visible || element.visibility != false)) {
                            // cube
                            let size = [
                                Math.abs(element.from[0] - element.to[0]),
                                Math.abs(element.from[1] - element.to[1]),
                                Math.abs(element.from[2] - element.to[2])
                            ];
                            let uv_offset = [
                                element.uv_offset ? element.uv_offset[0] : 0,
                                element.uv_offset ? element.uv_offset[1] : 0
                            ];
                            let flip = false || element.shade == false;
                            let faces = getUVFacePoints(size[0], size[1], size[2], flip);
                            let inflate = (element.inflate ? element.inflate : 0) * 2;
                            let mesh;
                            if (size[0] > 0 && size[1] > 0 && size[2] > 0) {
                                let UVdata = { width: Math.round(size[0]), height: Math.round(size[1]), depth: size[2], left: uv_offset[0], top: uv_offset[1], flip: flip, iscube: true };
                                mesh = new THREE.Mesh(
                                    new THREE.BoxGeometry(size[0] + inflate, size[1] + inflate, size[2] + inflate),
                                    createBoxTexture(textur_canvas_name, UVdata.width, UVdata.height, UVdata.depth, UVdata.left, UVdata.top, flip)
                                );
                                mesh.userData.UVdata = UVdata;
                            } else {
                                /////// If not cube ///////
                                if (size[0] == 0) {
                                    //Left Face
                                    let UVdata = { width: faces[0].width, height: faces[0].height, depth: 0, left: uv_offset[0] + faces[0].left, top: uv_offset[1] + faces[0].top, flip: flip, iscube: false };
                                    mesh = new THREE.Mesh(
                                        new THREE.PlaneGeometry(faces[0].width + inflate, faces[0].height + inflate),
                                        createTexture(textur_canvas_name, UVdata.left, UVdata.top, UVdata.width, UVdata.height, flip)
                                    );
                                    mesh.rotation.set(0, deg2rad(90), 0);
                                    mesh.userData.UVdata = UVdata;
                                } else if (size[1] == 0) {
                                    //Top Face
                                    let UVdata = { width: faces[2].width, height: faces[2].height, z: 0, left: uv_offset[0] + faces[2].left, top: uv_offset[1] + faces[2].top, flip: flip, iscube: false };
                                    mesh = new THREE.Mesh(
                                        new THREE.PlaneGeometry(faces[2].width + inflate, faces[2].height + inflate),
                                        createTexture(textur_canvas_name, UVdata.left, UVdata.top, UVdata.width, UVdata.height, flip)
                                    );
                                    mesh.rotation.set(deg2rad(-90), 0, 0);
                                    mesh.userData.UVdata = UVdata;
                                } else if (size[2] == 0) {
                                    //Front Face
                                    let UVdata = { width: faces[4].width, height: faces[4].height, depth: 0, left: uv_offset[0] + faces[4].left, top: uv_offset[1] + faces[4].top, flip: flip, iscube: false };
                                    mesh = new THREE.Mesh(
                                        new THREE.PlaneGeometry(faces[4].width + inflate, faces[4].height + inflate),
                                        createTexture(textur_canvas_name, UVdata.left, UVdata.top, UVdata.width, UVdata.height, flip)
                                    );
                                    mesh.rotation.set(0, 0, 0);
                                    mesh.userData.UVdata = UVdata;
                                }
                            }
                            let cube = new THREE.Object3D();
                            cube.add(mesh);
                            cube.visible = element.visibility != false;
                            cube.name = element.name;
                            let center = [
                                element.from[0] + size[0] / 2,
                                element.from[1] + size[1] / 2,
                                element.from[2] + size[2] / 2
                            ];
                            let pos = [
                                center[0] - origin[0],
                                center[1] - origin[1],
                                center[2] - origin[2]
                            ];
                            cube.position.set(-pos[0], pos[1], -pos[2]);
                            outliner.add(cube);

                            //child added
                            used_child.push(element.uuid);
                        }
                    });
                    if (outline["rotation"]) {
                        let axis = new THREE.Vector3(1, 0, 0);
                        outliner.rotateOnWorldAxis(axis, deg2rad(-outline.rotation[0]));
                        axis.set(0, 1, 0);
                        outliner.rotateOnWorldAxis(axis, deg2rad(outline.rotation[1]));
                        axis.set(0, 0, 1);
                        outliner.rotateOnWorldAxis(axis, deg2rad(outline.rotation[2]));
                    }
                    if (outline["origin"]) {
                        outliner.position.set(-origin[0], origin[1], -origin[2]);
                    }
                    parts[outliner.name] = outliner;
                    object.add(outliner);
                }

            });
        }
        if (data.meta && data.meta.format_version == "3.0" && data["elements"] && data["outliner"]) {
            var object = new THREE.Object3D();
            object.name = data.name;
            data.outliner.forEach(outline => {
                if (!only_visible || outline.visibility != false) {
                    // outliner
                    let outliner = new THREE.Object3D();
                    outliner.name = outline.name;
                    let origin = [
                        (outline.origin ? outline.origin[0] : 0),
                        (outline.origin ? outline.origin[1] : 0),
                        (outline.origin ? outline.origin[2] : 0),
                    ];
                    data.elements.forEach(element => {
                        if (outline.children.indexOf(element.uuid) > -1 && (!only_visible || element.visibility != false)) {
                            // cube
                            let size = [
                                Math.abs(element.from[0] - element.to[0]),
                                Math.abs(element.from[1] - element.to[1]),
                                Math.abs(element.from[2] - element.to[2])
                            ];
                            let uv_offset = [
                                element.uv_offset ? element.uv_offset[0] : 0,
                                element.uv_offset ? element.uv_offset[1] : 0
                            ];
                            let flip = false || element.shade == false;
                            let faces = getUVFacePoints(size[0], size[1], size[2], flip);
                            let inflate = (element.inflate ? element.inflate : 0) * 2;
                            let mesh;
                            if (size[0] > 0 && size[1] > 0 && size[2] > 0) {
                                let UVdata = { width: Math.round(size[0]), height: Math.round(size[1]), depth: size[2], left: uv_offset[0], top: uv_offset[1], flip: flip, iscube: true };
                                mesh = new THREE.Mesh(
                                    new THREE.BoxGeometry(size[0] + inflate, size[1] + inflate, size[2] + inflate),
                                    createBoxTexture(textur_canvas_name, UVdata.width, UVdata.height, UVdata.depth, UVdata.left, UVdata.top, flip)
                                );
                                mesh.userData.UVdata = UVdata;
                            } else {
                                /////// If not cube ///////
                                if (size[0] == 0) {
                                    //Left Face
                                    let UVdata = { width: faces[0].width, height: faces[0].height, depth: 0, left: uv_offset[0] + faces[0].left, top: uv_offset[1] + faces[0].top, flip: flip, iscube: false };
                                    mesh = new THREE.Mesh(
                                        new THREE.PlaneGeometry(faces[0].width + inflate, faces[0].height + inflate),
                                        createTexture(textur_canvas_name, UVdata.left, UVdata.top, UVdata.width, UVdata.height, flip)
                                    );
                                    mesh.rotation.set(0, deg2rad(90), 0);
                                    mesh.userData.UVdata = UVdata;
                                } else if (size[1] == 0) {
                                    //Top Face
                                    let UVdata = { width: faces[2].width, height: faces[2].height, z: 0, left: uv_offset[0] + faces[2].left, top: uv_offset[1] + faces[2].top, flip: flip, iscube: false };
                                    mesh = new THREE.Mesh(
                                        new THREE.PlaneGeometry(faces[2].width + inflate, faces[2].height + inflate),
                                        createTexture(textur_canvas_name, UVdata.left, UVdata.top, UVdata.width, UVdata.height, flip)
                                    );
                                    mesh.rotation.set(deg2rad(-90), 0, 0);
                                    mesh.userData.UVdata = UVdata;
                                } else if (size[2] == 0) {
                                    //Front Face
                                    let UVdata = { width: faces[4].width, height: faces[4].height, depth: 0, left: uv_offset[0] + faces[4].left, top: uv_offset[1] + faces[4].top, flip: flip, iscube: false };
                                    mesh = new THREE.Mesh(
                                        new THREE.PlaneGeometry(faces[4].width + inflate, faces[4].height + inflate),
                                        createTexture(textur_canvas_name, UVdata.left, UVdata.top, UVdata.width, UVdata.height, flip)
                                    );
                                    mesh.rotation.set(0, 0, 0);
                                    mesh.userData.UVdata = UVdata;
                                }
                            }
                            let cube = new THREE.Object3D();
                            cube.add(mesh);
                            cube.visible = element.visibility != false;
                            cube.name = element.name;
                            let center = [
                                element.from[0] + size[0] / 2,
                                element.from[1] + size[1] / 2,
                                element.from[2] + size[2] / 2
                            ];
                            let pos = [
                                center[0] - origin[0],
                                center[1] - origin[1],
                                center[2] - origin[2]
                            ];
                            cube.position.set(-pos[0], pos[1], -pos[2]);
                            outliner.add(cube);
                        }
                    });
                    if (outline["rotation"]) {
                        let axis = new THREE.Vector3(1, 0, 0);
                        outliner.rotateOnWorldAxis(axis, deg2rad(-outline.rotation[0]));
                        axis.set(0, 1, 0);
                        outliner.rotateOnWorldAxis(axis, deg2rad(outline.rotation[1]));
                        axis.set(0, 0, 1);
                        outliner.rotateOnWorldAxis(axis, deg2rad(outline.rotation[2]));
                    }
                    if (outline["origin"]) {
                        outliner.position.set(-origin[0], origin[1], -origin[2]);
                    }
                    parts[outliner.name] = outliner;
                    object.add(outliner);
                }
            });
        }
        if (typeof onload === "function") {
            onload.call(this, object, parts);
        }
    });
}

// ブロック専用
//引数
//  filename: xxxx.bbmodel のようなBlockbenchのjsonファイル
//  texture_canvas_names: CanvasやIMGなどのエレメント名"#texture"などを配列でぶちこむ事
//  only_visible: 表示設定がオンになっているパーツのみ読み込む
//  onload: コールバック関数。自動でSceneに追加しないのでここで行う事。
//    コールバック関数の戻り引数
//         object:THREE.Object3D :  グループ化されたモデル
//         parts:{name:THREE.Object3D,...} : 連想配列。各パーツを名前で取得できる
function BBModelLoaderBlock(filename, textur_canvas_names, only_visible, onload) {
    $.getJSON(filename, function (data) {
        var parts = {};
        if (data.meta && data.meta.format_version == "3.0" && data.meta.model_format == "java_block" && data["elements"] && data["outliner"]) {
            var object = new THREE.Object3D();
            object.name = data.name;

            ////// Cube Loading
            data.elements.forEach(element => {
                if (!only_visible || element.visibility != false) {
                    let origin = [
                        (element.origin ? element.origin[0] : 0),
                        (element.origin ? element.origin[1] : 0),
                        (element.origin ? element.origin[2] : 0),
                    ];
                    let size = [
                        Math.abs(element.from[0] - element.to[0]),
                        Math.abs(element.from[1] - element.to[1]),
                        Math.abs(element.from[2] - element.to[2])
                    ];
                    let faces = [
                        convUVFaceData(textur_canvas_names, element.faces.east),
                        convUVFaceData(textur_canvas_names, element.faces.west),
                        convUVFaceData(textur_canvas_names, element.faces.up),
                        convUVFaceData(textur_canvas_names, element.faces.down),
                        convUVFaceData(textur_canvas_names, element.faces.south),
                        convUVFaceData(textur_canvas_names, element.faces.north),
                    ];
                    let mesh;
                    if (size[0] > 0 && size[1] > 0 && size[2] > 0) {
                        mesh = new THREE.Mesh(
                            new THREE.BoxGeometry(size[0], size[1], size[2]),
                            [
                                createTexture(faces[0].texture, faces[0].left, faces[0].top, faces[0].width, faces[0].height, faces[0].hflip, faces[0].vflip, faces[0].rotate),
                                createTexture(faces[1].texture, faces[1].left, faces[1].top, faces[1].width, faces[1].height, faces[1].hflip, faces[1].vflip, faces[1].rotate),
                                createTexture(faces[2].texture, faces[2].left, faces[2].top, faces[2].width, faces[2].height, faces[2].hflip, faces[2].vflip, faces[2].rotate),
                                createTexture(faces[3].texture, faces[3].left, faces[3].top, faces[3].width, faces[3].height, faces[3].hflip, faces[3].vflip, faces[3].rotate),
                                createTexture(faces[4].texture, faces[4].left, faces[4].top, faces[4].width, faces[4].height, faces[4].hflip, faces[4].vflip, faces[4].rotate),
                                createTexture(faces[5].texture, faces[5].left, faces[5].top, faces[5].width, faces[5].height, faces[5].hflip, faces[5].vflip, faces[5].rotate),
                            ]
                        );
                        mesh.userData.UVdata = faces;
                    } else {
                        /////// If not cube ///////
                        if (size[0] == 0) {
                            //Left Face
                            let UVdata = convUVFaceData(textur_canvas_names, element.faces.west);
                            mesh = new THREE.Mesh(
                                new THREE.PlaneGeometry(faces[0].width, faces[0].height),
                                createTexture(UVdata.texture, UVdata.left, UVdata.top, UVdata.width, UVdata.height, UVdata.hflip, UVdata.vflip, UVdata.rotate)
                            );
                            mesh.rotation.set(0, deg2rad(-90), 0);
                            mesh.userData.UVdata = UVdata;
                        } else if (size[1] == 0) {
                            //Top Face
                            let UVdata = convUVFaceData(textur_canvas_names, element.faces.up);
                            mesh = new THREE.Mesh(
                                new THREE.PlaneGeometry(faces[2].width, faces[2].height),
                                createTexture(UVdata.texture, UVdata.left, UVdata.top, UVdata.width, UVdata.height, UVdata.hflip, UVdata.vflip, UVdata.rotate)
                            );
                            mesh.rotation.set(deg2rad(-90), 0, 0);
                            mesh.userData.UVdata = UVdata;
                        } else if (size[2] == 0) {
                            //Front Face
                            let UVdata = convUVFaceData(textur_canvas_names, element.faces.north);
                            mesh = new THREE.Mesh(
                                new THREE.PlaneGeometry(faces[5].width, faces[5].height),
                                createTexture(UVdata.texture, UVdata.left, UVdata.top, UVdata.width, UVdata.height, UVdata.hflip, UVdata.vflip, UVdata.rotate)
                            );
                            mesh.rotation.set(0, 0, 0);
                            mesh.userData.UVdata = UVdata;
                        }
                    }
                    let cube = new THREE.Object3D();
                    cube.add(mesh);
                    cube.visible = element.visibility != false;
                    cube.name = element.name;
                    cube.userData.uuid = element.uuid;
                    cube.userData.origin = origin;
                    let center = [
                        element.from[0] + size[0] / 2,
                        element.from[1] + size[1] / 2,
                        element.from[2] + size[2] / 2
                    ];
                    let pos = [
                        center[0],// - origin[0],
                        center[1],// - origin[1],
                        center[2],// - origin[2]
                    ];
                    if (element["rotation"]) {
                        let axis = new THREE.Vector3(1, 0, 0);
                        cube.rotateOnWorldAxis(axis, deg2rad(element.rotation[0]));
                        axis.set(0, 1, 0);
                        cube.rotateOnWorldAxis(axis, deg2rad(element.rotation[1]));
                        axis.set(0, 0, 1);
                        cube.rotateOnWorldAxis(axis, deg2rad(element.rotation[2]));
                    }
                    cube.position.set(pos[0], pos[1], pos[2]);
                    object.add(cube);
                    parts[cube.name] = cube;
                }
            });

            // append outliners
            data.outliner.forEach(appendOutline, object);

            // for nesting
            function appendOutline(outline, owner){
                if(typeof outline === "string"){
                    object.children.forEach(element => {
                        if (element.userData.uuid == outline && element.userData.origin) {
                            element.position.set(
                                element.position.x - element.userData.origin[0],
                                element.position.y - element.userData.origin[1],
                                element.position.z - element.userData.origin[2],
                            );
                        }
                    });
                    return;
                }
                if (!only_visible || outline.visibility != false) {
                    // outliner
                    let outliner = new THREE.Object3D();
                    outliner.name = outline.name;
                    outliner.userData.uuid = outline.uuid;
                    let origin = [
                        (outline.origin ? outline.origin[0] : 0),
                        (outline.origin ? outline.origin[1] : 0),
                        (outline.origin ? outline.origin[2] : 0),
                    ];
                    outliner.userData.origin = origin;

                    outline.children.forEach(child => {
                        if(typeof child === "string"){
                            object.children.forEach(element => {
                                if (element.userData.uuid == child) {
                                    element.position.set(
                                        element.position.x - origin[0],
                                        element.position.y - origin[1],
                                        element.position.z - origin[2],
                                    );
                                    outliner.add(element);
                                }
                            });
                        } else {
                            appendOutline(child, outliner);
                        }
                    });

                    if (outline["rotation"]) {
                        let axis = new THREE.Vector3(1, 0, 0);
                        outliner.rotateOnWorldAxis(axis, deg2rad(outline.rotation[0]));
                        axis.set(0, 1, 0);
                        outliner.rotateOnWorldAxis(axis, deg2rad(outline.rotation[1]));
                        axis.set(0, 0, 1);
                        outliner.rotateOnWorldAxis(axis, deg2rad(outline.rotation[2]));
                    }

                    outliner.position.set(-origin[0], -origin[1], -origin[2]);

                    if(typeof owner !== "object"){
                        object.add(outliner);
                    } else {
                        owner.add(outliner);
                    }
                }
            }
        };

        if (typeof onload === "function") {
            onload.call(this, object, parts);
        }
    });
}

//// MISC Utils /////////////////////////////////////////////////////////////

// IMG->Canvas コンバーター
function imageToCanvas(element) {
    var img = document.querySelector(element);
    var texture_canvas = document.createElement("canvas");
    texture_canvas.setAttribute("width", img.width);
    texture_canvas.setAttribute("height", img.height);
    var texture_contex = texture_canvas.getContext('2d');
    texture_contex.imageSmoothingEnabled = false;
    texture_contex.beginPath();
    texture_contex.clearRect(0, 0, img.width, img.height);
    texture_contex.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height);
    return texture_canvas;
}

// キャンバス単体を張り付けたマテリアルを返す
function createTexture(element, posx, posy, width, height, hflip, vflip, rotation) {
    let mag = 1; //resample magnify
    var img = document.querySelector(element);
    var texture_canvas = document.createElement("canvas");
    texture_canvas.setAttribute("width", width * mag);
    texture_canvas.setAttribute("height", height * mag);
    var texture_contex = texture_canvas.getContext('2d');
    texture_contex.imageSmoothingEnabled = false;
    texture_contex.beginPath();
    texture_contex.clearRect(0, 0, width * mag, height * mag);
    texture_contex.scale(hflip ? -1 : 1, vflip ? -1 : 1);
    texture_contex.drawImage(img, posx, posy, width, height, hflip ? -1 * width * mag : 0, vflip ? -1 * height * mag : 0, width * mag, height * mag);
    let rotated_canvas = rotate_img(texture_canvas, rotation);
    texture_canvas.remove();
    let texture = new THREE.CanvasTexture(rotated_canvas);
    texture.magFilter = THREE.NearestFilter;
    texture.minFilter = THREE.NearestFilter;
    texture.type = THREE.FloatType;
    return new THREE.MeshLambertMaterial({ map: texture, alphaMap: createAlphaMap(rotated_canvas), transparent: true, side: THREE.DoubleSide });
}

// アルファチャンネル付きのキャンバスからアルファマップ用モノトーンテクスチャを作成
function createAlphaMap(canvas) {
    var img = canvas;
    var img_ctx = img.getContext('2d');
    var img_data = img_ctx.getImageData(0, 0, img.width, img.height);
    var texture_canvas = document.createElement("canvas");
    texture_canvas.setAttribute("width", img.width);
    texture_canvas.setAttribute("height", img.height);
    var texture_contex = texture_canvas.getContext('2d');
    for(let x = 0; x < img.width; x++){
        for(let y = 0; y < img.height; y++){
            let d = (x + y * img_data.width) * 4;
            let data = img_data.data;
            data[d  ] = data[d+3];
            data[d+1] = data[d+3];
            data[d+2] = data[d+3];
            data[d+3] = 255;
        }
    }
    texture_contex.putImageData(img_data, 0, 0);
    let texture = new THREE.CanvasTexture(texture_canvas);
    texture.magFilter = THREE.NearestFilter;
    texture.minFilter = THREE.NearestFilter;
    texture.type = THREE.FloatType;
    return texture;
}

// 立方体テクスチャを作成してマテリアルの配列を返す
function createBoxTexture(element, x, y, z, posx, posy, hflip) {
    let faces = getUVFacePoints(x, y, z, hflip);
    let img = document.querySelector(element);
    let mag = 1; //resample magnify

    let materials = [];
    for (let i = 0; i < 6; i++) {
        let texture_canvas = document.createElement("canvas");
        texture_canvas.setAttribute("width", faces[i].width * mag);
        texture_canvas.setAttribute("height", faces[i].height * mag);
        let texture_contex = texture_canvas.getContext('2d');
        texture_contex.imageSmoothingEnabled = false;
        texture_contex.beginPath();
        texture_contex.clearRect(0, 0, faces[i].width * mag, faces[i].height * mag);

        texture_contex.scale(hflip ? -1 : 1, faces[i].vflip ? -1 : 1);
        texture_contex.drawImage(img, (posx + faces[i].left), posy + faces[i].top, faces[i].width, faces[i].height, hflip ? -1 * faces[i].width * mag : 0, faces[i].vflip ? -1 * faces[i].height * mag : 0, faces[i].width * mag, faces[i].height * mag);

        let texture = new THREE.CanvasTexture(texture_canvas);
        texture.magFilter = THREE.NearestFilter;
        texture.minFilter = THREE.NearestFilter;
        materials.push(
            new THREE.MeshLambertMaterial({ map: texture, transparent: false, side: THREE.DoubleSide, alphaTest: 0.9, wireframe: false })
        )
    }
    return materials;
}

// 角度からラジアンを返す
function deg2rad(deg) {
    return deg * (Math.PI / 180)
}

//90°単位の画像回転専用関数(THREE.Textureのrotationがなんか変なので)
function rotate_img(img, rotate){
    let canvas_half= ([img.height,img.width]).sort((a,b)=>{return a-b})[1];
    let texture_canvas = document.createElement("canvas");
    texture_canvas.setAttribute("width", canvas_half * 2);
    texture_canvas.setAttribute("height", canvas_half * 2);
    let texture_contex = texture_canvas.getContext('2d');
    texture_contex.imageSmoothingEnabled  = false;
    texture_contex.clearRect(0, 0, canvas_half * 2, canvas_half * 2);
    rotate = (Math.floor(rotate / 90) * 90) % 360;
    const rotated = {
        //  ____|270
        // |_180|__|_
        //   |  |_0__|
        //   |90|
        "0":   {x: canvas_half           , y: canvas_half           , width: img.width, height: img.height},
        "180": {x: canvas_half-img.width , y: canvas_half-img.height, width: img.width, height: img.height},
        "90":  {x: canvas_half-img.height, y: canvas_half           , width: img.height, height: img.width},
        "270": {x: canvas_half           , y: canvas_half-img.width , width: img.height, height: img.width},
    }
    let r = rotated[rotate];
    texture_contex.translate(canvas_half, canvas_half);
    texture_contex.rotate(deg2rad(rotate));
    texture_contex.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height);
    let temp_canvas = document.createElement("canvas");
    temp_canvas.setAttribute("width", r.width);
    temp_canvas.setAttribute("height", r.height);
    let temp_contex = temp_canvas.getContext('2d');
    temp_contex.imageSmoothingEnabled  = false;
    temp_contex.clearRect(0, 0, r.width, r.height);
    temp_contex.drawImage(texture_canvas, r.x, r.y, r.width, r.height, 0, 0, r.width, r.height);
    texture_canvas.remove();

    return temp_canvas;
}

// Minecraftのテクスチャの各面に対応する座標を返す
function getUVFacePoints(x, y, z, hflip) {
    // box face: [+X, -X, +Y, -Y, +Z, -Z]
    // box face: [Right, Left, Upper, Bottom, Front, Back]
    return [ //Minecraft Texture mapping
        { left: hflip ? 0 : z + x, top: z, width: z, height: y },
        { left: hflip ? z + x : 0, top: z, width: z, height: y },
        { left: z, top: 0, width: x, height: z },
        { left: z + x, top: 0, width: x, height: z, vflip: true }, // THREE.js bottom textures are flipped upside down
        { left: z, top: z, width: x, height: y },
        { left: z * 2 + x, top: z, width: x, height: y }
    ]
}

// bbmodelのfaceエレメントの負の数値から反転フラグを分解
function convUVFaceData(textures, uv_data){
    let texture = textures[uv_data.texture ? uv_data.texture: 0];
    let img = document.querySelector(texture);
    let hflip = uv_data.uv[0] > uv_data.uv[2];
    let vflip = uv_data.uv[1] > uv_data.uv[3];
    let uv_h = [
        hflip? uv_data.uv[2]: uv_data.uv[0],
        hflip? uv_data.uv[0]: uv_data.uv[2]
    ];
    let uv_v = [
        vflip? uv_data.uv[3]: uv_data.uv[1],
        vflip? uv_data.uv[1]: uv_data.uv[3]
    ];
    return {
        texture: texture,
        left: uv_h[0] % img.width,
        top: uv_v[0] % img.width,
        width: Math.abs(uv_h[1] - uv_h[0]),
        height: Math.abs(uv_v[1] - uv_v[0]),
        hflip: hflip,
        vflip: vflip,
        rotate: uv_data.rotation ? uv_data.rotation: 0,
    };
}

使い方

コールバック関数の中で出来たObjectをSceneに追加してください。
それぞれのパーツは第二引数のpartsに入っていますので、回転などのアニメーションも簡単にできます。

Blockbenchのアニメーション形式には対応していません。

なんでクラス化してないの?

こっちの方が使いやすそうだったので・・・(*´ω`*)

なんでOBJ/MTLローダーを使わないの?

便利なんですが、回転や拡大縮小がちゃんと再現されないようなのです。
直立なのに微妙に斜めになったりする。
float型による弊害か、Blockbench側の問題??

This page images are copyrights Mojang AB.

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0