bs-community / skinview3d

Three.js powered Minecraft skin viewer.
https://skinview3d-demo.vercel.app
MIT License
550 stars 90 forks source link

Better performance when rendering a lot of skins #167

Open zardoy opened 3 months ago

zardoy commented 3 months ago

Hi I’m making a game and wanted to reuse your models for players and I wonder if it’s possible to get a good performance with many models displaying at the same time. Eg I’m getting 20fps and significant page lag on mobile with 75 player models on the page.

I understand that it might be more issue with my personal use case, but I can imagine other use cases as well such as displaying many skin models (such as a 5x15 gallery grid) on the same page so I think it’s worth mentioning a solution for such use cases. I have no idea what optimizations I can use here since using instanced meshing would not allow to use of animations & dynamic textures for each player.

UPD: I think I was able to triple the fps by removing second layer from legs & arms groups (which reduces the number of meshes to render as I understand)

Hacksore commented 3 months ago

So I was able to create a sandbox with 17 renderers and the perf seems ok (over 60+ FPS for me).

https://codesandbox.io/p/sandbox/blue-haze-y2hyp5

I soon as I made 18 it causes this error 😂

THREE.WebGLRenderer: Context Lost.
 Uncaught TypeError: Failed to execute 'shaderSource' on 'WebGL2RenderingContext': parameter 1 is not of type 'WebGLShader'.
    at WebGLShader (/node_modules/three/build/three.cjs:13897:5)
    at new WebGLProgram (/node_modules/three/build/three.cjs:14230:25)
    at Object.acquireProgram (/node_modules/three/build/three.cjs:14738:14)
    at getProgram (/node_modules/three/build/three.cjs:20190:27)
    at setProgram (/node_modules/three/build/three.cjs:20326:14)
    at WebGLRenderer.renderBufferDirect (/node_modules/three/build/three.cjs:19758:19)
    at renderObject (/node_modules/three/build/three.cjs:20150:10)
    at renderObjects (/node_modules/three/build/three.cjs:20126:5)
    at renderScene (/node_modules/three/build/three.cjs:20066:33)
    at WebGLRenderer.render (/node_modules/three/build/three.cjs:19955:4)
    at FullScreenQuad.render (/node_modules/three/examples/jsm/postprocessing/Pass.js:45:14)
    at ShaderPass.render (/node_modules/three/examples/jsm/postprocessing/ShaderPass.js:40:19)
    at EffectComposer.render (/node_modules/three/examples/jsm/postprocessing/EffectComposer.js:100:12)
    at SkinViewer.render (/node_modules/skinview3d/libs/viewer.js:480:19)
    at SkinViewer.draw (/node_modules/skinview3d/libs/viewer.js:476:10)
    at eval (/node_modules/skinview3d/libs/viewer.js:315:66)
zardoy commented 3 months ago

So I was able to create a sandbox with 17 renderers

I could not access the sandbox as it's private, but I assume you are creating individual renderers and I presume that's the most ineffective way to render a lot of things, there is simply no need for it. Of course, I changed the skinview3d code a bit to use a single renderer instead. However that's a dead end for me, I have no idea what optimizations can be used to render all these skins on the same page smoothly. As I said earlier the only thing that seems helped me was removing the second layer objects from legs and arms (effectively reducing the number of objects to render), but it was also weird to me - it seems to be transparent anyway by default. Anyway, I will continue investigating...

Hacksore commented 3 months ago

Sorry it's public now.

One optimization you could try is render all of them off screen then you could have them become an interactive viewer on mouse over?

https://github.com/bs-community/skinview3d/blob/master/examples/offscreen-render.html https://bs-community.github.io/skinview3d/offscreen-render.html

zardoy commented 3 months ago

One optimization you could try is render all of them off screen then you could have them become an interactive viewer on mouse over?

Yes, I could even server-side render them. Static rendering is not a problem, but I want all them animated (the animations you made are just awesome), I already tried rendering videos on the server, but it's slow even with webp (low res videos are not good for highdpi screens) so I'm still looking for a way to solve it on the client side...