A-Frame: Limit the number of faces and vertices on models - performance

I'm having trouble with the performance of A-Frame and all I tried had no effect. On the A-Frame website in Best Practices - Performance the following is mentioned:
Limit the number of faces and vertices on models.
This model has nearly 100k vertices and 30k faces. How can I reduce the number of faces and/or vertices? It is a requirement that the user can interact with every box in the model separately, e.g. by changing its color or transparency or position. Is there a way to create a mesh or whatever and still having full interaction with every element on its own?
Besides that, I have no idea how to improve performance. The scene has no lights, textures, collisions, raycasters and all the other heavy stuff. These are just some boxes ...

The problem in this scene is not the number of vertices or faces (100k and 30k respectively are fine), but the size of the scene graph and the number of GPU draw calls. There are 2400 <a-box/> elements, each requires a separate draw call, and that is too many. The number of draw calls should be as low as possible, ideally < 100.
To keep all 2400 boxes interactive, you'll need to either (1) create a custom component that puts all boxes into a single THREE.BufferGeometry and changes vertex positions and colors within geometry.attributes.position and geometry.attributes.color, or (2) use a technique like instancing. Both will require some custom JS, not just HTML markup, as they're not built into A-Frame as components.

Related

ThreeJS Vertices and Faces optimization

I have a BufferGeometry where say.., it has vertices ,faces and draw count of 967 , 210 and 1. Now when I increase the instance of geometry to 100 the respective vertices, faces and draw count are 9670, 2000 and 1. The draw call remains the same where the vertices and faces of the buffergeometry are doubling with the rate of the instance.
So, when ever I have some geometry with 15 thousand instances in it with vertices of above 1000 for a single buffergeoemtry the values are raising very high which inturn my browser is getting crashed and the basic orbit controls functionalities are lagging.
I just render the attributes in Interleavebuffer where I get the data from Revit / CAD Team.
The thing is why should the vertices count should increase since they are only instances and I though draw call may influence most in performance while the vertices/ faces also plays a major role in optimization.
Can anyone suggest me with the above concern. Thanks in advance.
Yes, the number of draw calls can have a major impact on the performance of a WebGL app. Using instanced rendering is one possible approach to lower the number of draw calls and thus improve performance.
However, instanced rendering does not lower the amount of vertices that have to be processed in the vertex shader. In some sense, you just lower the amount of communication that happens between the CPU and GPU (since you can tell the GPU with a single WebGL draw command to render many instances). But it's not possible to save processing time in the shaders.

What is the most efficient way to create a reservoir in Three.js?

I am creating a 3D reservoir model which looks like this.
It's made of hundreds of thousands of cells with outline. The outline is needed for all cells underneath, because there is an IJK filter used to hide cells on any level and thus show the rest. Once the model is rendered, it shouldn't need to be updated in terms of position or scale.
That's enough about the background. The approach I'm using is creating one large geometry, which stores all vertices cross the reservoir in one triangle strip. It also stores IJK index for each cell, so the IJK filter works in shader level. This should create the mesh part. Then I create another object to draw all outlines using one THREE.LineSegments.
The approach works pretty well for small amount of cells, but for large data set, frame rate drops.
I'm proposing another way of doing this by barycentric outline and instancing drawing. Barycentric outline drawing removes the extra LineSegment object, since it draws outline in fragment shader. However, it comes with drawbacks. Because of the missing of geometry shader in WebGL, I have to use full triangle rather than triangle strip to store barycentric coordinates for each vertex. I'm ok with this extra memory usage, if instanced drawing can boost the performance.(?) That's to say, I draw a cube with outline, and I create as many instances as I need and put them in right position.
I am wondering if this approach is indeed gonna increase the performance theoretically. Any thoughts are welcomed!
Ok I think I am gonna answer this question myself.
I implemented the change based on above ideas and it works pretty good compared to the original version.
Let's put the result first: this approach has no problem rendering hundreds of thousands of cells at reasonable frame rate. My demo contains 400,000 cells, with the frame rate at 50 fps in worst case, running on my Nvidia 1050Ti card and 4k monitor. For comparison, if I draw 400,000 cells in the previous version, the frame rate could drop to 10 fps.
This means using instanced drawing for a large object is faster than composing a single large geometry. For rendering performance, the instanced cube is rendered only one side, while triangle-stripped cube is two-sided. Once I can draw a single unit cube with ideal outline, I can transform it to any places in "any" shape in vertex shader. But of course instanced drawing comes with its restrictions: each cell doesn't have to be at same shape, but has to have same number of vertices, faces, etc; I lost control to change vertex color...
As for memory usage, the new approach actually use less. I provide position for 8 vertices, instead of 14, in each cell. Even though the first unit cube has 36 vertices, I can use its unit position as index, for subsequent instances. That is, for 36 unit vertices (0/1, 0/1, 0/1), I only need to provide 8 real positions.
Hope this helps for people who want to implement the same optimization.

Possibly to prioritise drawing of objects in Threejs?

I am working on a CAD type system using threejs. I have thin objects next to other objects (think thin 2mm metal sheeting fixed to posts on a building measured in metres). When I am zoomed in it all looks fine. The objects do not intersect at all. As I zoom out the objects get smaller and I end up with cases where the post object 'glimmers' (sort of shows through) the metal sheet object as I rotate it around.
I understand it's the small numbers I am working with that is causing this effect. However, is there a way to set a priority such that one object (the metal sheeting) is more important than another object (post) so it doesn't get that sort of effect?
To answer the question from the title, it is possible to prioritize drawing orders with.
myMesh.renderOrder = 5
myOtherMesh.renderOrder = 7
It is then possible to apply different depth effects, turn off the test etc.
Another way is to group objects with, layers. Set the appropriate layer mask on the camera and then render (multiple times).
myMesh.layers.set(5)
camera.layers.set(1)
renderer.render(scene,camera)
camera.layers.set(5)
renderer.render(scene,camera)
This is called z-fighting, where two fragments are so close in the given depth space that their z-values are within the margin of error that their true depths might get inverted.
The easiest way to resolve this is to reduce the scale of your depth buffer. This is controlled by the near and far properties on your camera. You'll need to play with the values to determine what works best for your senario. If you can minimize the distance between the planes, you'll have better luck avoiding z-fighting.
For example, if (as a loose estimate) the bounding sphere of your entire model has a diameter of 100, then the distance between near and far need only be 100. However, their values are set as the distance into camera space. So as you zoom out, and your camera moves further away, you should adjust the values to maintain the minimum distance between them. If your camera is at z = 100, then set near = 50 and far = 150. When you pull your camera back to z = 250, then update near = 200 and far = 300.
Another option is to use the WebGLRenderer.logarithmicDepthBuffer option. (example)
Edit: There is one other cause: the faces of the shapes are actually co-planar. If two triangles are occupying the same space, then you're all but guaranteeing z-fighting.
The simple solution is to move one of the components such that the faces are no longer co-planar. You could also potentially apply a polygonOffset to the sheet metal material, but your use-case doesn't sound like that is appropriate.

Vertex buffer objects and glutsolidsphere

I have to draw a great collection of spheres in a 3D physical simulation of a "spring-mass" like system.
I would like to know an efficient method to draw spheres without having to compile a display list at every step of my simulation (each step may vary from milliseconds to seconds, depending on the number of bodies involved in the computation).
I've read that vertex-buffer objects are an efficient method to draw objects which need also to be sometimes updated.
Is there any method to draw OpenGL spheres in a way faster than glutSolidSphere?
Spheres are self-similar; every sphere is just a scaled version of any other sphere. I see no need to regenerate any geometry. Indeed, I see no need to have more than one sphere at all.
It's simply a matter of providing the proper scaling matrix. I would suggest a sphere of radius one centered at the origin for your display list or buffer object mesh. Then you can just transform it to different locations, using a scale to set the new radius.
I would like to know an efficient method to draw spheres without having to compile a display list at every step of my simulation (each step may vary from milliseconds to seconds, depending on the number of bodies involved in the computation).
Why are you generating a display list at all, if the geometry you put into is is dynamic. Display lists are meant for static geometry that never or only seldomly changes.
I've read that vertex-buffer objects are an efficient method to draw objects which need also to be sometimes updated.
Actually VBOs are most efficient with static geometry as well. In general you want to keep the number of actual geometry updates as low as possible. In your case the only thing updating are the positions (and maybe the size) of the spheres. This is a prime example for instanced drawing. However this also works well, with updating only a uniform or the transformation matrix and do the call drawing a sphere.
The idea of Vertex Arrays and VBOs is, that you draw a whole batch of geometry with a single call. A sphere would be such a batch.

OpenGL ES and overlapping triangles with VBO

Some background:
I am very new to OGL. My application concerns itself with 2D only. All objects are normal to the viewing direction, and I use orthographic projection. I find that the performance of the system is limited by the number of draw* calls indicating that I need to batch more.
There is only one object that I need to draw, but it consists of thousands of triangles that potentially overlap. I have the ability to pre-compute geometry in my particular application and order the triangles back to front since they have varying degrees of transparency. The vertex attribute consists of the color (only) including alpha that is used in the fragment program.
What I've done:
All the primitives are triangles and I assign the 3 vertices of each triangle the same color since the color is constant across a face. I put all of the vertices, for all triangles, and their colors into a single VBO (16-bit; there aren't that many vertices). The index buffer orders the triangles back to front and I issue a single draw call. I use alpha blending (SRC_ALPHA, ONE_MINUS_SRC_ALPHA).
Result:
I see that the result is correctly blended and rendered on the only machine that I possess and test on. I have not tried it on others. I've searched for quite some time, but in vain, for some definitive answer. BTW, the only reference is in the VBO extension spec where there is a mention of a "sequence of primitives" but it does not address what happens when the primitives overlap.
Question:
Is this the guaranteed behavior? That is will the result be the same as issuing multiple calls within glBegin(...) and glEnd(...) in immediate mode (which is guaranteed by the standard)?
Note: Depth buffer and stencil buffer are turned off.
It is guaranteed by the OpenGL specification that primitives will be rendered in the order provided. Each primitive pulled from a glDraw* command will be rendered in the order specified by its component vertices.
So yes: if you put the triangles in an order, that's the order you'll get them out when you render them.

Resources