Open stephengold opened 2 years ago
Proposed (re-)implementation inspired by Retzinsky's PR 267:
IntRectangle
defines a rectangle in 2-D (similar to com.jme3.font.Rectangle
, but with integer coordinates)IntRectangle
field, with getter/setter, to each Geometry
(in window coordinates, using null
to disable clipping)void clip(IntRectangle)
to the Renderer
interfaceGLRenderer
to track whether the GL_SCISSOR_TEST
enumerator is enabled and also the current glScissor()
boxMaterial.render()
, invoke r.clip()
with the geometry's clip rectangleThe weird thing about clipping is that a spatial can be in any number of viewports. When I tried to mess with this before, that was the ultimate sticking point. The nifty JME interface already has some backdoor access to clip(rect) stuff and unfortunately it did not easily translate to the general "spatial can be in multiple viewports" case.
The only real usecase that comes into my mind is creating some texture atlas. (Shared shadwos maps ...) Even for the "Gui" usecase using clipping breaks if any rotations are allowed. I fail to see the point where a per geometry clip rect is usefull at all.
Yes, a Spatial
can be rendered in multiple viewports. Is that a detail that needs to be addressed in this PR?
I fail to see the point where a per geometry clip rect is useful
A likely use case would be to render labels in a GUI.
The most likely use case would be for things like scroll panels, etc.... but that would require this on the spatial level.
I looked at this some time back ready to dive in and got stumped by how ugly things got when considering multiple viewports. I started implementing a map(Viewport, Clip) of clipping areas per spatial but it gets nasty fast.
For just a single geometry, for the limited use cases that require it, it's better to just build the facility into the shader. Way simpler and all the same viewport problems/limitations without dirtying up scene graph code with what amounts to a partial solution.
Retzinsky's PR 267 implemented Node.enableClipping()
by recursively applying it down the scene graph to the geometries. I cut that from my design to simplify, thinking it's something apps can easily do on their own using a scene-graph visitor. If node-level clipping were implemented in a sophisticated way, with local clips at each level and caching of the effective global clip, would that enable more use cases?
I'm not worrying about multiple viewports. Many applications have only a single viewport per geometry, and as you said, it gets nasty fast.
- add
void clip(IntRectangle)
to theRenderer
interface- add state to
GLRenderer
to track whether theGL_SCISSOR_TEST
enumerator is enabled and also the currentglScissor()
box
It turns out none of this is necessary, since Renderer
already has setClipRect()
and clearClipRect()
methods and GLRenderer
implements it (using float
and boolean
instead of a rectangle object).
So is there also a mechanism to specify a clip rectangle for a Material
? I'm not seeing it.
Note: that at the Geometry level, clipping is nearly useless and can already be done by 1-2 lines in a material. That's also why I was not really a fan of the previous PR... it was only a partial solution and didn't really solve any real-world problems that weren't already solvable by a Viewport.
That's why simply pushing the traversal onto the application isn't really a solution, either.
The most common use-case I know of, and the reason I invested some large number of hours looking into this already, is the idea of a scroll panel in a UI. In that case, you want everything under a node to be clipped by some area... but to be better than a Viewport you will also want some change in how things are sorted, too. Else two separate sibling nodes with overlapping clip regions may behave unintentionally. The down side of using Viewports is that we cannot control the order at all through JME's API.
In a pure scene graph implementation that does not make JME's optimizations of compiling a geometry list, this sort of clipping is relatively trivial as things are rendered as the scene graph is traversed. This scene graph approach is undesirable for a lot (lot lot) of reasons but often when thinking about environmental effects like clipping, it comes up.
When I looked into this before, not only was the geometry-level style approach not useful but it was completely vestigial/superfluous in the presence of better solutions. That being said, "perfect is the enemy of good" and just because I can't imagine a use-case for and cannot see a reason that I would ever in a million years use a feature, doesn't mean that we shouldn't have it.
As to the existing clipping support and whether Material allows it, keep in mind that clip rect back doors exist for the NiftyJmeDisplay stuff. So you might find that code is the only caller of the methods you've discovered.
...but if one were thinking of putting clipping on the Geometry then putting it on the Material seems equally as cromulent.
can already be done by 1-2 lines in a material
How would one add clipping to a Material
in the current Engine?
When I forked my own font shader to better support BM font features, it was a vec4 I passed that would discard every fragment outside that range. And I still only used it one place. (In the modern engine, we could even use material parameter overrides on a whole tree that way... I could not at the time.)
The down side of using Viewports is that we cannot control the order at all through JME's API.
I had an idea: perhaps the Picture
class could be used to implement scroll panels. Then the Z-coordinates of the pictures would control overlapping, and no new scene-graph features would be needed.
you might find that code is the only caller of the methods you've discovered.
With that hint, I found where setClipRect()
is used in jme3-niftygui.
Given that there's a way to implement clipping in materials, and no plausible use case for dynamic scene-graph clipping, I've decided to defer this project indefinitely.
Requested at the Forum/Hub: https://hub.jmonkeyengine.org/t/next-release-of-the-engine/44988/9
PR #267 provides a possible starting point.