Sending non-premultiplied Model + View matrices to shaders #1309
Replies: 5 comments
-
The projection matrix isn't pre-multiplied, what is set by the View's Camera's ProjectionMatrix will be what is set to the GPU via push constant. The scene model matrices (Transform nodes) and view matrices are multiplied, done by the Transform::transform(..) method, and then passed to the GPU via push constant. This modelview multiplication is done with double matrices to preserve precision as long as possible, before being converted to float and pushed. The RecordTraversal is intended to be a const operation, to make it easy to multi-thread when required, updates to the scene graph are done prior to the viewer.recordAndSubmit() method. This obviously doesn't quite fit with how you are want to tackle your task right now, but it's likely this is not the cleanest way, an approach more in keeping with how the VSG is intended to be used will likely provide the a more flexible solution long term. Perhaps we can suggest a direction of how to approach the task without getting into the weeds of the low level code side prematurely. Could you provide some background on the technique you are trying to implement? Links to articles/3rd party code/screenshots are useful. This means a little more upfront discussion but this should mean for a more seamless implementation. |
Beta Was this translation helpful? Give feedback.
-
Hey Robert, thanks for the quick reply! To be 100% clear, I'm trying to implement the infinite grid technique from this article: https://asliceofrendering.com/scene%20helper/2020/01/05/InfiniteGrid/ (Obviously cleaning up the shader code and adding C++ infrastructure around it to make it vsg-compatible). As I dug into it, I found that sending the model, view matrices separately would be useful in any situation where model-space could be made irrelevant (such as optimized skyboxes). So I was curious as to how that could be done in VSG |
Beta Was this translation helpful? Give feedback.
-
The VSG accumulates model and view matrices and passes them as modelview matrix to avoid precision issues - without doing this when you dealing with larger datasets you end up with jitter in the on screen positions of vertices and jitter in the lighting and shadows. For scenes where the camera and model coordinate remain near an origin you don't notice the jitter, so you can get away with passing the model and view matrices separately, often you'll find this in simpler game engines or simple examples. However, if you try to adapt to handle larger scenes you end up with various hacks to work around the jitter issues, these hacks just makes things more complex and complicated in the end. Both the VulkanSceneGraph and OpenSceneGraph before take this same approach with combining view and model matrices for the same numerical precision reasons, enabling them to handle whole earth databases seamlessly, with any additional complexity or special handling of large coordinates. However, it does requires shaders and handling of lights/shadows that are in model coordinates in the scene to be converted into eye coordinates and passed as eye coordinates to the GPU so all the lighting and shadows can also benefit from the same precision benefits as provided by combining the model and view matrices before passing to the GPU. The VSG does this conversion to eye coordinates for uses via the vsg::ViewDependentState class that is automatically assigned to the vsg::View. An irony about an "infinite" grid implementation that passes model and view matrices to the GPU to be combined on the GPU is that it won't really handle large coordinates, it'll be a local "infinite" grid as long as you keep local and not going to any large let along infinity. With the "infinite" grid you are wanting to implement, do you intend it to scale to a whole planet level and follow an ellipsoid, do you want it to be planar? |
Beta Was this translation helpful? Give feedback.
-
Thanks for the elaboration. The precision issue was not a concern to me yet - since I want to solve the issue of getting the right data to the shader first. 1 step at a time, right? :) I strictly want to build a planar grid - not ellipsoid. So the scene space it occupies is potentially unbounded. For my application, it's unlikely users will go extraordinarily near/far from the origin (on all axis). As I work on the grid and adapt it to user needs, I have various "tricks" I could use to work-around precision issues - such as premultiplication of some calculations on the CPU, or pallettizing the scene space such that precision becomes less of an issue (although the tradeoff between precision and how large the value can be accurately stored is related - I still expect users to not come near to approaching the issue). I could also just turn off rendering the "infinite" grid at some point where numerical precision becomes a concern (really emphasizing those quotations marks around "infinite"). Although, perhaps you have a more wizened approach than me! |
Beta Was this translation helpful? Give feedback.
-
Turns out that all I had to do was use the identity matrix for the model. Problem solved! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
From what I gather - it looks like the
projection
andmodelView
matrices are pushed to graphics via push constants during record traversal withMatrixStack
.I'm hoping to be able to send the non-premultiplied
Model
,View
, andProjection
matrices to a custom shader to draw an infinite grid. I'm hoping to be able to do this during record traversal, so that if anything changes, the shader draws the grid correctly.I'm wondering if anyone has any suggestions/recommended ways to do this? So far I've considered subclassing
Transform
and changing the calculation there. But it would also be nice to know how to send custom push constants or update descriptors during record traversal.Beta Was this translation helpful? Give feedback.
All reactions