0
votes

I created a very simple cube using Blender and exported it using the Three.js Blender Exporter.

I am now attempting to load the exported model and apply a texture using Node. When I run the script, I see no error. What am I doing wrong?

'use strict';

const JSDOM = require('jsdom').JSDOM;
const THREE = require('three');

const dom = new JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`);

global.window = dom.window;
global.document = dom.window.document;
global.XMLHttpRequest = require('xhr2');

const loadTexture = (path) => {
    return new Promise((resolve, reject) => {
        const loader = new THREE.TextureLoader();

        loader.load(
            path,

            // success
            (texture) => resolve(texture),

            // progress
            undefined,

            // error
            (error) => reject(error)
        );
    });
};

const loadGeometry = (path) => {
    const loader = new THREE.JSONLoader();

    return new Promise((resolve, reject) => {
        loader.load(
            path,

            // success
            (geometry) => resolve(geometry),

            // progress
            undefined,

            // error
            (error) => reject(error)
        );
    });
};

const createObject = () => {
    return Promise.all([
        loadTexture('./image.jpg'),
        loadGeometry('./cube.json')
    ]).then(results => {
        const texture = results[0];
        const material = new THREE.MeshBasicMaterial({map: texture});
        const geometry = results[1];
        const object = new THREE.Mesh(geometry, material);

        return object;
    });
};

const scene = new THREE.Scene();

createObject()
    .then(object => {
        scene.add(object);

        console.log('Success!');
    })
    .catch(error => console.error(error.message));

Here is the model I am using:

{
    "normals":[-5.32907e-15,-1,2.98023e-08,1.06581e-14,1,-2.98023e-08,1,4.47034e-08,2.83122e-07,-2.83122e-07,-7.45059e-08,1,-1,-1.3411e-07,-2.23517e-07,2.38419e-07,1.78814e-07,-1],
    "faces":[33,0,1,2,3,0,0,0,0,33,4,7,6,5,1,1,1,1,33,0,4,5,1,2,2,2,2,33,1,5,6,2,3,3,3,3,33,2,6,7,3,4,4,4,4,33,4,0,3,7,5,5,5,5],
    "metadata":{
        "normals":6,
        "faces":6,
        "type":"Geometry",
        "vertices":8,
        "generator":"io_three",
        "uvs":0,
        "version":3
    },
    "vertices":[1,-1,-1,1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1,0.999999,1,1,-1,1,1,-1,1,-1],
    "uvs":[]
}
1
I don't see a renderer in your code, so nothing would appear... are you seeing no output at all but expecting Success!? Also note that jsdom probably does not support WebGL, you may need node-webgl or a headless browser here.Don McCurdy
Hi Don, thanks for your feedback. You are right about no renderer. For now, my goal is to test loading of the model and texture. Once that works, I will proceed to implement rendering. I wonder if node-webgl is necessary to even load the model? Something seems to be preventing model load.Chad Johnson
Since others can't run this code without your model, what do you see? Does any console.log output appear? Consider logging when the texture and model load or fail rather than resolving/rejecting immediately to narrow down the problem.Don McCurdy
@DonMcCurdy Just updated the question with the model :) No output appears with console.log(). But I just added a .catch() within createObject(), and 'lo and behold, I get an error message now: THREE.Object3D.add: object not an instance of THREE.Object3D. It then appears that scene.add(object) is causing this problem.Chad Johnson
Ah nevermind. I get that error because then in the .catch() block undefined is being returned.Chad Johnson

1 Answers

0
votes

Well, I got something almost working:

'use strict';

const fs = require('fs');
const JSDOM = require('jsdom').JSDOM;
const THREE = global.THREE = require('three');
require('three/examples/js/renderers/Projector');
const CanvasRenderer = require('three/examples/js/renderers/CanvasRenderer');
const Canvas = require('canvas');

const dom = new JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`);

global.window = dom.window;
global.document = dom.window.document;
global.XMLHttpRequest = require('xhr2');

const loadTexture = (url) => {
    const loader = new THREE.FileLoader();

    return new Promise((resolve, reject) => {
        console.log('loading texture');

        loader.load(
            url,

            // success
            (texture) => {
                console.log('loaded texture');
                resolve(texture);
            },

            // progress
            undefined,

            // error
            (error) => {
                console.log('error loading texture');
                reject(error);
            }
        );
    });
};

const loadGeometry = (url) => {
    const loader = new THREE.JSONLoader();

    return new Promise((resolve, reject) => {
        console.log('loading geometry');

        loader.load(
            url,

            // success
            (geometry) => {
                console.log('loaded geometry');
                resolve(geometry);
            },

            // progress
            undefined,

            // error
            (error) => {
                console.log('error loading geometry');
                reject(error);
            }
        );
    });
};

const createObject = () => {
    return Promise.all([
        loadTexture('http://localhost:8000/image.jpg'),
        loadGeometry('http://localhost:8000/cube.json')
    ]).then(results => {
        const texture = results[0];
        const geometry = results[1];
        const material = new THREE.MeshBasicMaterial({map: texture});
        const object = new THREE.Mesh(geometry, material);

        return object;
    });
};

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const canvas = new Canvas(800, 800);
const renderer = new THREE.CanvasRenderer({
    canvas: canvas
});

camera.position.z = 5;

canvas.style = {};

renderer.setClearColor(0xffffff, 0);
renderer.setSize(800, 800);

createObject()
    .then(object => {
        scene.add(object);

        renderer.render(scene, camera);

        const out = fs.createWriteStream('./rendered.png');
        const canvasStream = canvas.pngStream();
        canvasStream.on('data', function (chunk) { out.write(chunk); });
        canvasStream.on('end', function () { console.log('done'); });
    })
    .catch(error => console.error(error.message));

Except it renders a blank, transparent PNG.