Georgi B. Nikolov
Georgi B. Nikolov

Reputation: 998

Loading a texture in THREE.js using Node

I am trying to build a messenger bot which does some image processing in 3d and returns a brand new image. I use THREE.CanvasRenderer and my app is hosted on Heroku.

When a user /POSTs an attachment to my webhook, I want to take the URL of the newly created image and insert it into my 3d Scene.

This is my code (using the node-canvas library):

const addTexture = (imageUrl) => {

    request({
        uri: imageUrl,
        method: 'GET'
    }, (err, res, body) => {
        let image = new Canvas.Image();
        image.src = body;
        mesh.material.map = new THREE.Texture(image);
        mesh.material.needsUpdate = true;
    });
}

The callback gets run and I can actually console.log() the image's contents, but nothing shows up in the scene - the plane I am supposed to render to just gets black without any errors... What am I missing here?

I also tried several other ways, without any success...

I tried using THREE.TextureLoader and patch it with jsdom (mock document, window) and node-xmlhttprequest, but then there is error with my load event (event.target is not defined...) Just like in this example

How should one approach this problem? I have a url generated by Facebook, I want to download the image from it and place it in my scene?

Upvotes: 1

Views: 1839

Answers (1)

Georgi B. Nikolov
Georgi B. Nikolov

Reputation: 998

Okay, I figured it out after half a day and am posting it for future generations:

Here is the code that did the trick for me:

const addTexture = (imageUrl) => {
    request.get(imageUrl, (err, res, data) => {
        if (!err && res.statusCode == 200) {
            data = "data:" + res.headers["content-type"] + ";base64," + new Buffer(data).toString('base64');

            let image = new Canvas.Image();

            image.onload = () => {
                mesh.material.map = new THREE.Texture(image);
                mesh.material.map.needsUpdate = true;
            }
            image.src = data;
        }
    });
}

This way, I still get an error: document is not defined, because it seems under the hood three.js writes the texture to a separate canvas.

So the quick and ugly way is to do what I did:

document.createElement = (el) => {
    if (el === 'canvas') {
        return new Canvas()
    }
}

I really hope this helps somebody out there, because besides all the hurdles, rendering WebGL on the server is pure awesomeness.

Upvotes: 2

Related Questions