godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Add support for custom clipping planes in 3D #1753

Open bluenote10 opened 4 years ago

bluenote10 commented 4 years ago

Describe the project you are working on:

Various experiments.

Describe the problem or limitation you are having in your project:

A common problem I run into is to clip some geometry/mesh against some custom clipping boundaries. Currently I see two possible solutions:

Describe the feature / enhancement and how it helps to overcome the problem or limitation:

I am not an expert, and don't know how state of the art solutions to the problem would look like. I'm mainly opening this issue to follow up on the previous discussions on the topic over at https://github.com/godotengine/godot/issues/3499. Perhaps Vulkan opens new possibilities here?

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:

No plan yet.

If this enhancement will not be used often, can it be worked around with a few lines of script?:

By doing it manually as described above.

Is there a reason why this should be core and not an add-on in the asset library?:

Not really, it would be mainly a matter of convenience.

Calinou commented 4 years ago

See also https://github.com/godotengine/godot/issues/23721. In 2D, clipping is now supported in master thanks to https://github.com/godotengine/godot/pull/43167.

ChristianB84 commented 4 years ago

In my opinion, this can't be done manually in the fragment shader in a usable way, because the performance is too bad when using "discard".

I tried this in a project with GLSL shaders (not in Godot, obviously), replacing my prior implementation that uses "gl_ClipDistance" in the vertex shader with one that uses "discard" in the fragment shader. It renders a water plane with refraction and reflection by using three passes (from the same position): The first pass renders everything below the water line (+ some tiny overlap because I displace the vertices for waves) into a texture. The second pass renders everything below the water line, but mirrored for this plane, into another texture. In the final pass, I render the full scene, with the water shader reading from the textures created in the first two passes (with some distortion according to the waves).

It's essentially the refraction and reflection part of what's described here: https://blog.bonzaisoftware.com/tnp/gl-water-tutorial/ However, that implementation uses glClipPlane instead of gl_ClipDistance.

The variant with "gl_ClipDistance" runs with about 40 FPS, the variant with "discard" runs with slightly more than 15 FPS. Using "discard" doesn't seem to help much performance-wise, because removing it (i.e. rendering everything multiple times) doesn't make it much worse.

It's maybe possible to more efficently emulate "gl_ClipDistance" in a geometry shader, but those aren't available in Godot either. I haven't tried that anyway, so it could be slow, too.

"gl_ClipDistance" is available since GLSL 1.3 (!): https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_ClipDistance.xhtml Doesn't seem to be available in OpenGL ES 2.0 or 3.0 though, nor is glClipPlane.