在node.js服务器上运行Three.js WebGLRenderer是否可行?

3

我需要在服务器上运行WebGLRenderer,但是有不同的声音关于这个问题。有些人说这是不可能的,有些人则表示他们正在尝试解决问题,但那时讨论就结束了。

是否有可能做到这一点?如果可以,采用什么方法?是否可以使用moch-browser结合node-gl或其他工具来实现?

[编辑] 添加解决方案


你打算如何处理渲染结果?是将其流式传输回用户的浏览器,还是保存到文件中或其他方式? - Matey
@Matey 将其作为 PNG 格式流回给用户。 - JakobMiller
流式传输一系列的PNG文件?还是发送单个PNG文件? - Matey
1
@Matey 我会将它流回客户端。我实际上成功地渲染了它。当我有一个干净的解决方案时,我会发布它! - JakobMiller
@JakobMillah,你为什么想要使用JavaScript进行服务器端渲染? - Ramil Kudashev
@mlkn 我们将使用Three.js来渲染物理窗户的3D模型。客户可能会订购10个不同的窗户,我们希望服务器为每个窗户渲染一个图像版本并生成一个报价文件。我猜想这背后有一个理由,即不想存储大量图像和/或安全性问题,以防渲染/Three.js库在客户端无法工作。 - JakobMiller
4个回答

6
这是我对问题的解决方案。根据场景和对象的大小,可能需要一些时间。在我的情况下,我想返回相当小的对象版本,但仍需要大约400毫秒才能响应一个400x400像素的png。希望这能帮助到某个人!

enter image description here

Server.js

var THREE = require("three.js");

// Create a DOM
var MockBrowser = require('mock-browser').mocks.MockBrowser;
var mock = new MockBrowser();
var document = MockBrowser.createDocument();
var window = MockBrowser.createWindow();

//REST API
var express     = require('express');      
var app         = express();    
var bodyParser  = require('body-parser');
var router = express.Router();

var gl = require('gl')(1,1); //headless-gl

var pngStream = require('three-png-stream');
var port = process.env.PORT || 8080;

router.get('/render', function(req, res){

    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);
    var renderer = new THREE.WebGLRenderer({context:gl});

    scene.add(camera);

    renderer.setSize(this.width, this.height);
    renderer.setClearColor(0xFFFFFF, 1);

    /*...
        Add your objects & light to the scene 
    ...*/

    var target = new THREE.WebGLRenderTarget(this.width, this.height);
    renderer.render(scene, camera, target);


   res.setHeader('Content-Type', 'image/png');
   pngStream(renderer, target).pipe(res);
});

app.use('/api', router);

app.listen(port);
console.log('Server active on port: ' + port);

这对于复杂的3D动画来说可行吗?我想不太可能,因为网络延迟的原因,但我很好奇。 - zephos2014

2

是的,headless-gl 就是我最终使用的!结合 mock-browser 来生成 DOM。而 three-png-stream 则用来将渲染流返回客户端。 - JakobMiller

1

我成功地做到了这一点,诀窍是渲染到画布上并取出一个png图像对象。

var fs = require("fs")

var self = {};

var ratio = 16/9.0;

var canvasWidth = 500;
var canvasHeight = 500;

var window = {
    innerWidth: canvasWidth,
    innerHeight: canvasHeight

};
var document = {
    createElement: function(name) {
        if (name == "canvas") {
            //return new Canvas(canvasWidth, canvasHeight);
        }
        var Canvas = require('canvas')
        return new Canvas(500,500)
    },
    createElementNS: function(name) {

        var Canvas = require('canvas')
        return new Canvas(500,500)
    }
};

var THREE = require("./threejs/three.js")
eval(fs.readFileSync("threejs/additionalRenderers.js").toString())
eval(fs.readFileSync("threejs/SceneUtils.js").toString())

const EventEmitter = require('events');

//var OS = new ShereOS()

class ThreeClient extends EventEmitter {
    constructor() {
        super()
        var self = this
        this.appId = 667


        self.loaded = false

        this.bgColor = '#282c34'
        this.textColor = '#fff'
        this.tildeColor = '#0000ff'
        this.selectColor = '#ffffff'

        this.width = 500
        this.height = 500



        this.renderer = new THREE.CanvasRenderer();
        this.renderer.setSize(this.width, this.height);

        this.camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.001, 3000);
        this.camera.position.z = 2;




        this.scene = new THREE.Scene();

        this.scene.background = new THREE.Color( 0xECF8FF );
        this.scene.add( new THREE.HemisphereLight( 0x606060, 0x404040 ) );
        this.light = new THREE.DirectionalLight( 0xffffff );
        this.light.position.set( 1, 1, 1 ).normalize();
        this.scene.add( this.light );
        //console.log(this.scene.children)


        this.updated = false
        /*
        var geometry = new THREE.SphereGeometry( 0.1, 32, 32 );
        var material = new THREE.MeshBasicMaterial( {color: 0xFF0000} );
        this.sphere = new THREE.Mesh( geometry, material );
        this.scene.add( this.sphere );
        */
    }




    getTexture() {
        this.renderer.render(this.scene, this.camera);
        var data = this.renderer.domElement.toDataURL().substr("data:image/png;base64,".length)
        var buf = new Buffer(data, 'base64');
        fs.writeFile('image.png', buf);
        //return this.renderer.domElement.toDataURL().substr("data:image/png;base64,".length);
        
    }
}

var THREEClient = new ThreeClient();

npm install avros


0
你不能直接在node.js中使用Canvas。使用JSDOM或mockbrowser对我来说效果不好。所以,我使用了node-canvas库来虚拟化canvas。之后你知道该怎么做了!
还有,这是我的基本代码片段。希望能帮到你!
const { createCanvas } = require("canvas");
const THREE = global.THREE = require("three");
const fs = require("fs");

async function Virtuealize_Canvas() {

    this.width = 512
    this.height = 512
    const canvas = createCanvas(this.width, this.height, { alpha: true })
    
    const renderer = new THREE.WebGLRenderer({ canvas });
    renderer.setSize(this.width, this.height);
    
    const scene = new THREE.Scene();
    
    const camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);
    camera.position.z = 11
    
    const ambientLight = new THREE.AmbientLight('white', 0.8);
    scene.add(ambientLight);
    
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshBasicMaterial({color: 0x00ff00});
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    
    renderer.render(scene, camera);
    
    const buffer = canvas.toBuffer();
    
    fs.writeFileSync(__dirname + `image.png`, buffer)

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接