nodejs渲染glb模型

更新时间: 2024-12-05 15:35:35

上一篇用threejs加载了简单的几何体构成的场景,今天我们加载3d模型,这次加载glb格式

来先看效果:

# 库文件改造

# 安装并改造xmlhttprequest

  • 首先npm i xmlhttprequest
    因为nodejs不支持XMLHttpRequest,但threejs.module.js会用到XMLHttpRequest,所以先安装

  • 然后将 /node_modules/xmlhttprequest/lib/XMLHttpRequest.js 复制一份出来放到项目的lib文件夹下

  • 修改XMLHttpRequest.js 304行开始的代码:

// ....
// 下面一行是309行
// 先是去掉readFile中间的参数“utf8”,此处转utf8会出问题  
fs.readFile(url.pathname, function(error, data) {
    if (error) {
    self.handleError(error);
    } else {
    self.status = 200;
    if(self.responseType == 'arraybuffer') {
        // 然后将Buffer转为arrayBuffer并放入response属性中  
        var buf = Buffer.from(data)
        var ab = new ArrayBuffer(buf.length);
        var view = new Uint8Array(ab);
        for (var i = 0; i < buf.length; ++i) {
            view[i] = buf[i];
        }
        self.response = ab
    }else{
        self.response = data;
    }
        self.responseText = data;
        setState(self.DONE);
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 改造three.module.js

  • 复制 /node_modules/three/lib/three.module.js 到 项目的lib文件夹下

  • 在/lib/three.module.js开头加上两行

var xml = require("./XMLHttpRequest.js");

var XMLHttpRequest = xml.XMLHttpRequest 
1
2
3

# 改造GLTFLoader.js 和 DRACOLoader.js

复制 three/examples/jsm/loaders/DRACOLoader.js 和 three/examples/jsm/loaders/GLTFLoader.js,将它们改成CommonJS模块

# 客户端代码

<template>
  <div class="main">
    <button @click="next">下一帧</button>
    <div class="img-wrapper">
      <img :src="imageSrc" alt="">
    </div>
  </div>
</template>

<script setup>
  import {ref, onMounted} from "vue"
  import {io} from  "socket.io-client/dist/socket.io.js" 
  let socket = null
  const imageSrc = ref('')

  onMounted(() => {

    socket = io("http://192.168.2.122:3000")

    socket.on('img',(data) => {
      const blob = new Blob([data])
      imageSrc.value = URL.createObjectURL(blob)
    })
  })

  function next() {
    socket.emit('next')
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 复制draco文件夹

将 /node_modules/three/examples/js/libs/draco 这个文件夹整体复制到 项目的lib文件夹下

现在我们的lib文件夹长这样

# 服务端代码

需要注意,服务端加载模型地址需要加上 file://

const express = require('express')
const {createServer} = require('node:http')
const {Server} = require('socket.io')  
const THREE = require('three');
const { GLTFLoader }  = require('./lib/GLTFLoader.js')
const { DRACOLoader } = require('./lib/DRACOLoader.js') 

const {createCanvas} = require('node-canvas-webgl/lib');
require('events').EventEmitter.defaultMaxListeners = 0
const app = express() 
const server = createServer(app)
const io = new Server(server,{
    cors: {
      origin: "*"
    }
})

const width = 1000,
  height = 600;

io.on('connection', (socket) => {
    const scene = new THREE.Scene(); 
    let horse = null
    scene.background = new THREE.Color( 0xf6eedc );

    camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
    camera.position.set( 500, 500, 0 );
    camera.lookAt(0,0,0)

    const canvas = createCanvas(width, height);

    const renderer = new THREE.WebGLRenderer({
        canvas,
        antialias: true
    });

    const hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 2 );
    hemiLight.color.setHSL( 0.6, 1, 0.6 );
    hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
    hemiLight.position.set( 0, 50, 0 );
    scene.add( hemiLight );

    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath( __dirname + '/lib/draco/gltf/' );

    const loader = new GLTFLoader();
    loader.setDRACOLoader( dracoLoader );
    loader.setPath( "file://"+__dirname + '/models/' );
    loader.load( 'Horse.glb', function ( gltf ) {
        console.log("gltf",gltf)
        horse = gltf.scene
        scene.add( horse );

        update();

    } );


    function update() {
        horse && (horse.rotation.x += 0.1 )
        horse && (horse.rotation.y += 0.1 )
        renderer.render(scene, camera);
        socket.emit('img', canvas.toBuffer())
    }

    socket.on('next', () => {
        update()
    })
})

server.listen(3000, () => {
    console.log('server running at http://localhost:3000')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73