Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

IDirectContext3DServer and scene size

16 REPLIES 16
SOLVED
Reply
Message 1 of 17
aignatovich
1495 Views, 16 Replies

IDirectContext3DServer and scene size

Hi, guys,

I use a direct context 3D server to display some analysis results in 3D views. I faced a problem that if the scene is large (has a lot of mesh triangles), then the displayed geometry becomes broken.

I've solved this issue by splitting the scene into multiple servers. However, I didn't find any information in the SDK about such limits.

 

@jeremytammik , could you ask the development team to confirm the exact limits of the direct context 3D server, please?

16 REPLIES 16
Message 2 of 17
RPTHOMAS108
in reply to: aignatovich

Would be good to get further guidance on this also.

 

The form of the 'duplicate graphics' sample (add multiple servers) suggests using a server for every Element i.e. many servers with fewer triangles in each. This kind of makes sense because each server can then independently check if it needs to update graphics:

 

In the said sample when you go into RenderScene method there is a compound Boolean check of various buffer states. If this check returns false, resulting in the CreateBufferStorageForElement function not being run (instead taking existing buffer and flushing it) then it is usually instantaneous.

 

I tried this with around 400 Elements (which is not an overly large set) and it was fine. However for some complex elements there was still a noticeable delay (7 seconds) in generating the graphics.

 

I wonder how the Coordination Model add-in within the link below does it, this is showing an entire Navis model in ghost form overlaid with Revit:

DirectContext3D: API for Displaying External Graphics in Revit | Autodesk University

Message 3 of 17
jeremytammik
in reply to: aignatovich

Impressive information from Richard, as usual. Thank you for that, Richard!

 

Yes, sure, Alexander, I asked the development team for you.

  



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 4 of 17
aignatovich
in reply to: RPTHOMAS108

@RPTHOMAS108,Nope. Buffer states checks (for example VertexBuffer.IsValid method) have a different purpose.

 

From the SDK:

The buffers are internally associated with low-level graphics state and may become invalidated when the state
changes. Therefore, an application should test each buffer for validity before submitting its contents for rendering.
If the buffer becomes invalid, the application should re-create its contents and write them to a new buffer.
 
So it is for the case when you choose the strategy of reusing buffers. Yes, I chosed it for my app, and yes,
I check the results from these methods
 
 
Sorry for a such ugly link, I can't the page where I've download this PDF again. See page 54-55.
 
At page 55 there is a remark "For medium-sized scenes, splitting buffers between servers shouldn’t matter"
 
So I want to see the limits documented somewere...
 
@jeremytammik, Thank you!
Message 5 of 17
aignatovich
in reply to: aignatovich

I also tried the approach from the sample in SDK, but I faced a serious performance issue. In my case I have thousands of "elements". So now I split them into rather big portions. It works, but I want to know more about the tools I use.

Message 6 of 17
RPTHOMAS108
in reply to: aignatovich

Can only go from experience tried it both ways and having fewer servers with many triangles is incredibly slow.

 

It's not the check itself so much as what happens when you recreate buffers. Most of the items were static in the view as they often are so recreating static objects is a waste of time i.e. view changes but geometry is the same unless the object in the view changes.

 

@jeremytammik thanks. Was wondering also why the edges for cylindrical faces do not show as they do in the actual Revit views i.e. if I duplicate a circular hollow section the outlines are not shown in DirectContext3D. A cylindrical face only has end edges but Revit somehow shows the longitudinal edges between the ends, regardless of this. I don't know if these edges are classed as something else (a different classification type of edge) missing from DirectContext3D? Thinking about it they are just missing from actual geometry element used for the graphics but how would we generate them to show? There must be a method Revit is using to show these silhouette outline like edges.

 

 

Message 7 of 17
aignatovich
in reply to: RPTHOMAS108

Just what I've talked about:

 

That's how it should work (splitted for several servers):

aignatovich_0-1607965615337.png

A bit more complex example (about 37.5k elements):

aignatovich_2-1607965982983.png

 

 

And that is when I try to push all the geometry in a single server (a part of the model):

aignatovich_1-1607965652703.png

Yep, the performance is not very good, however, it tooked about a minute to generate the geometry shown in the second image. Then it is rather fast, the buffers are cached and you can move or rotate the view without significant delays.

Now I have 2500 elements (usually a 3 or 4 corners "plate" and an arrow (cube + piramid) for each direct context 3D server.

 

Yep, in my first implementation I used a cylinder + cone as an "arrow", it was much slower, so I totally agree with your advice to minimize the number of meshes you want to display.

Message 8 of 17
aignatovich
in reply to: RPTHOMAS108


@jeremytammik thanks. Was wondering also why the edges for cylindrical faces do not show as they do in the actual Revit views i.e. if I duplicate a circular hollow section the outlines are not shown in DirectContext3D. A cylindrical face only has end edges but Revit somehow shows the longitudinal edges between the ends, regardless of this. I don't know if these edges are classed as something else (a different classification type of edge) missing from DirectContext3D? Thinking about it they are just missing from actual geometry element used for the graphics but how would we generate them to show? There must be a method Revit is using to show these silhouette outline like edges.

 


Perhaps, that is because DirectContext3D works with meshes, but Revit itself deals with more detailed faces objects, such as a Cylynrical face and can select level of detail based on, for example a size of the element on the screen.

 

You can try to replace Triangulate method used in DuplicateGraphics sample to:

public Mesh Triangulate(
	double levelOfDetail
)

 I'm pretty sure you'll see additional edges in the results

Message 9 of 17
RPTHOMAS108
in reply to: aignatovich

Good example. I'll try your suggestion regarding the edges thanks.

 

I was using idling event to to sequence a set of elements i.e. hide them from view temporarily and put them back with DirectContext3D (at the allotted time) but it was obviously getting slower and slower with one server. When I used a server for each Element the timing of each item being displayed was governed by the sequence timing as intended rather than by how long the graphics took to generate (apart from a few Elements that were probably too complex). 

 

We probably do need some guidance on these things though.

Message 10 of 17
jeremytammik
in reply to: aignatovich

Here is the first reply from the development team:

 

  


Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 11 of 17
aignatovich
in reply to: jeremytammik

Thank you, @jeremytammik 

 

I've realized I did it in the wrong way. So, in the example above (~37.5k elements) I have 15 direct context 3D servers. Each server serves 2500 "elements" with 2 large buggers: one for faces and one for edges. The common "element" has 18-19 mesh triangles. It works now, but I think, the performance could be improved.


I'll try to play with it tomorrow. First of all, I guess I don't need to have multiple servers. I'll also want to test different combinations of buffer size and the number of buffers.

What do they mean by "on how the objects in the buffers will be updated"? In my case I don't need to update particular buffers when the scene is ready, only to remove the existing scene and create a new one at some point (or just clear only). Should I use big or small buffers in such case?

Message 12 of 17
aignatovich
in reply to: aignatovich

I came back with the results.

There is no significant correlation between buffers count/size and the code execution time, only the total buffers size of the entire scene matters. If the buffers are big, then it will take a bit more time to build them, but subsequent renderings will be a bit faster.

So there is only one rule - buffers should not be very large, in such case the scene geometry will be broken.

The other thing I've learned - how to reuse existing buffers. My arrows share the same geometry.

aignatovich_0-1608032769196.png

 


So I build buffers once and then I use DrawContext.SetWorldTransform method before DrawContext.FlushBuffer invocation. This approach has a great impact on the performance of my app both on geometry build and render time.

 

Thank you all

Message 13 of 17
jeremytammik
in reply to: aignatovich

Thank you for your new question, interesting results and valuable conclusions. I asked the development team to take a look and confirm.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 14 of 17
Alex.Pytel
in reply to: aignatovich

Performance is a complicated matter, especially in this case when there are several layers of technology. Sometimes it is also possible to optimize the objects that are submitted to the graphics pipeline in some high-level application-specific manner. Time permitting, it is probably best to try different implementations.

 

I believe that it is better to allocate the buffers once and re-use them, instead of creating new buffers every time. (As mentioned above, it may still be necessary to re-create the buffers when they are invalidated internally, but this kind of invalidation should occur rarely.) However, this strategy only describes what to do with the buffers themselves, not their contents. It is possible to fill the buffers once and not touch them for a while or to fill and flush them on every RenderScene() or even multiple times for each RenderScene(). Navisworks Core Engine mentioned above implements the latter strategy, but it is extremely optimized. (It displays graphics in a view-dependent way, so that the contents of the buffers can be expected to change despite the model being static.)

 

Also, as a general rule, it is better to group similar objects together. More specifically, objects that use the same EffectInstance should be submitted together or merged into one set of buffers (vertex and index). DirectContext3D allows some flexibility in following this strategy, because if the color of objects does not change, it is possible to have the color specified at each vertex and stored in the vertex buffer. One trade-off is that the size of the buffer increases when color is included.

 

The above comment about "how the objects in the buffers will be updated" is referring to finding the optimal strategy to group or merge buffers, if some of the objects can be modified (by a user, by a simulation, or in response to some change in the Revit model.) It is probably better for objects that can change to be kept separately.

 

Transformation can also be a performance factor. For example, it is possible to have many objects, each with their own transformation, or to merge them into one buffer and transform them as one unit. In other words, in a hierarchical scene, it is possible to flatten the lower level(s) of transformations by applying them to the vertices and saving the transformed vertices in the buffers. The potential benefit of doing this depends on how often the transformations need to be updated. An additional constraint in DirectContext3D is that the reported bounding box should be transformed, as well.

 

As for displaying thousands of identical arrows, DirectContext3D does not currently have dedicated support for instancing. So, I would consider the following optimizations, time permitting: 1) constructing the arrows in such a way that they do not need to be transformed individually and grouping them into a few large buffers (that can still be transformed with the model if needed), 2) exploring some way to cull invisible arrows (by view frustum or possibly by extracting the floors of the model and testing whether they cover some of the arrows), 3) return early from RenderScene() when DrawContext.IsInterrupted() is true (this allows drawing to be interrupted, so that Revit can respond to input events). Please, note that these potential optimizations may not result in improvement given specific scenes and constraints of a particular application.

Message 15 of 17
Alex.Pytel
in reply to: aignatovich

The broken geometry case illustrated above seems to be a separate issue to me. As a complete guess, it may be occurring when the buffer size exceeds a certain value, which may be specific to a video card driver. If this is the case, it would be challenging for DirectContext3D to detect the issue and raise an exception. Visually, the appearance of the triangles is similar to a case when the vertex and index buffers contain incorrect values. Is there a chance that the geometry stored in the buffers becomes corrupted somehow? To test this, I would dump the beginning and end of the buffers and compare them. (It may help to display the arrows for the case when they are spaced uniformly on a grid and are all pointing in one direction.)

Message 16 of 17
aignatovich
in reply to: aignatovich

Thanks for the information, I'll try to see what I can do with it tomorrow

Message 17 of 17
alan.gay9RHA9
in reply to: aignatovich

I believe I may have hit the same issue. It looks like my issue could be to do with the IndexBuffer. The documentation hints at each index being composed of a Short Int, which I read as meaning an unsigned 16-bit integer. If this is the case the maximum vertex index that could possibly be referenced would be 65535.

 

Running with test data seems to suggest this is indeed the case, I get missing geometry as soon as I hit this limit.

 

I access the IndexBuffer using a IndexStreamTriangle via adding IndexTriangles whose indices are specified using Int32 values. I found this to be somewhat confusing.

 

I'm wondering if this is the same issue?

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community