Open nkallen opened 3 months ago
This sounds like a fairly minimal change and I'd support adding the couple lines required to the points and line dashed materials.
Out of curiosity - what's your use case for BatchedMesh lines and points?
I'm working on a CAD/3d modeling application. The user edits things like solids, curves, and surfaces. Curves and surfaces have control points that can be edited. Solids have faces and edges that can be selected and manipulated.
(We now use multidraw for everything possible, rather than one draw call per object. And we manage the buffer on the gpu explicitly using THREE.GLBufferAttribute)
In the attached picture you can see faces, edges, vertices, cvs, regions, hulls, curve segments. The points (cvs + vertices) are rendered using gl.POINTS. Curves and edges are rendered using LineSegments2. However, the in the image the editor is also in "xray mode" which renders edges and curves a second time using gl.LINES without depth testing, so you can see "through" objects.
You might wonder: why have both LineSegments2 and gl.LINES? It's just for performance reasons: gl.LINES is much faster if you only need 1px lines (which is what we do in xray mode, and for hulls). LineSegments2 is expensive both because of the massive instancing operation and (more importantly) it is extremely stressful for MSAA on the GPU. (We currently use MSAA but we will move away from it if I can find a high quality replacement)
LineSegments2 is expensive both because of the massive instancing operation and (more importantly) it is extremely stressful for MSAA on the GPU. (We currently use MSAA but we will move away from it if I can find a high quality replacement)
A bit off topic but I do wonder what kind of performance improvements can be made to Line2. I haven't done any specific benchmarks but does just using instancing specifically cause such a significant performance loss? My expectation was that by using discard and / or alpha-to-coverage there would be a lot of performance loss due to overdraw (no early z rejection). I do wonder if using something like 4 or 5 triangles per cap to round the edges rather than using pixel discard could help things.
It's on my todo to investigate more. In a test scene I use, a fully detailed ww2 tank with about 5k non-instanced objects, about 50mb worth of edges (LineSegments2):
The edges are by far the most expensive thing. I tried getting rid of the "mitres" (a few triangles) and didn't notice a significant difference. Almost by accident I decided to turn off MSAA and this is what I saw:
I read somewhere recently that very long skinny triangles are bad for gpus, and indeed that is what is happening here (basically 2px fat lines).
I read in a stackoverflow comment somewhere that someone also saw a performance benefit from reading from a texture rather than instancing. I find that hard to believe, but it's worth investigating also.
Well, interesting tidbit re edges. On my AMD gpu, the MSAA is the major bottleneck. On my Macbook M3 it is not, edges are still the most expensive thing and disabling msaa has a very small effect.
I read somewhere recently that very long skinny triangles are bad for gpus, and indeed that is what is happening here (basically 2px fat lines).
Small triangles have very poor quad utilization in rasterization, so you could see performance issues similar to overdraw where extra tiles are spawned purely as helper invocations, and this adversely affects mobile/TBDR GPUs. Desktop IMR GPUs are not as affected since triangles are rasterized immediately, which would explain the discrepancy you're seeing with those small triangles and increasing their coverage with MSAA.
Description
I am currently using BatchedMesh extensively -- not just with meshes but also with
gl.LINES
andgl.POINTS
Note that multidraw does accept a mode:
extension.multiDrawElementsWEBGL( mode, ... )
It may be unintended, but the
isBatchedMesh
check inWebGLRenderer
does not set the mode; rather it is set a few lines before with checks onisPoint
andisLine
. This is very convenient and everything almost works out of the box. Only the points shader isn't fully compatible.Solution
The only snag is that
points.glsl.js
needs to add#include <batching_vertex>
Alternatives
Well, the shader could be manipulated with a string replace but I think that is a gnarly hack
Additional context
I do want to note that while I don't actually use the THREE.BatchedMesh class very much, I have my own class with
isBatchedMesh = true
to benefit from access to multidraw