Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement preliminary support for bezier patch subdivision surfaces #79738

Closed
wants to merge 1 commit into from
Closed

Conversation

myaaaaaaaaa
Copy link
Contributor

@myaaaaaaaaa myaaaaaaaaa commented Jul 21, 2023

1690833275
1690833137
GREEN: Original lowpoly quad model ||| YELLOW: Bezier patch control points after preprocessing ||| RED: Final tessellated model ||| BLUE: Catmull-Clark subdivision for comparison ||| WHITE: Quad/Bezier patch borders

1690833156
Circle test. Note how bezier patch subdivision surfaces (RED) need fewer points than Catmull-Clark subdivision surfaces (BLUE) to create rounder circles.

1690833235
Bevel test. Support loops work the same way for both surfaces.

Bezier patch vs Catmull-Clark pros:

  • Bezier patches are simpler to evaluate and their mathematical properties have been more thoroughly researched.
  • Points on the limit surface can easily be directly evaluated (this is in fact the standard way to evaluate bezier curves/patches), unlike Catmull-Clark which by default must be iteratively refined and shrinks with every iteration
  • Patches are completely independent of each other, making them friendlier towards a potential tessellation or mesh shader implementation
  • More flexibility for the preprocessing algorithm to decide where to place control points, without affecting the complexity of bezier patch evaluation during runtime.

Cons:

  • Bezier patches are not an industry standard subdivision surface. While this PR has made great efforts to ensure that traditional Catmull-Clark modeling rules work as expected (edges are sharpened with support loops, regular polygons result in circles, etc), they will not be able to match the curvature exactly. This becomes less of a problem as the model is subdivided to a higher density.
  • The added flexibility of allowing the preprocessing algorithm freedom to assign control points doubles as a fantastic footgun.
  • The preprocessing implementation in this PR only supports quads. Non-quad models will need to be pre-subdivided once in the DCC application to produce quads.

Contents of this PR:

  • GLTF meshes suffixed with "-experimental-subd" are now treated as subdivision surfaces and automatically converted on load. This was done to simplify this PR as it aims to strictly focus on the backend. Replacing this with a proper interface in the future is highly recommended.
  • Subdivision surfaces conversion is done via the following two-step process:
    1. Preprocessing: Convert the input quad model into a list of bezier patches at load time. Control points are assigned based on neighboring faces to ensure G1 continuity between patch seams like with Catmull-Clark subdivision surfaces. Most of the complexity lies in this function, although this is in terms of comprehensibility. Performance should not be an issue.
    2. Tessellation: Convert the bezier patch list into a standard triangle model, tessellating faces up to a target polycount (100,000 for now) and adding them as LODs. This is currently also done at load time. In the future, bezier patches can be sent directly to a tessellation or mesh shader for direct evaluation on the GPU, without needing to compute and store the intermediate highpoly triangle model, allowing for per-frame adaptive runtime tessellation and reducing VRAM and rasterizer usage.
  • Standardizes a quad representation where every six indices form a triangle pair with the following ordering:
    1689912328
    This allows the rest of Godot's rendering system to remain blissfully quad-unaware. Note that I haven't checked thoroughly to see if quads won't be clobbered by mesh processing somewhere, but at least with the basic testing I've done so far, quads are preserved correctly from import to render.
  • Quad-based PrimitiveMeshes now always outputs in this format
  • The GLTF importer now attempts to detect quads if possible. This may or may not work depending on how the file was exported, but Blender seems to always place triangles in the same polygon next to each other.
  • Now preserves quads in OBJ files

@fire
Copy link
Member

fire commented Jul 22, 2023

Are you familiar with this encoding? KhronosGroup/glTF#1620

@myaaaaaaaaa
Copy link
Contributor Author

Are you familiar with this encoding? KhronosGroup/glTF#1620

I went with Ultra Engine's proposal for quads since I think there's value in having a low level GL_QUADS-like primitive.

Ngons should probably be considered a (slightly) higher level feature to be implemented separately. Using meshlets for this purpose may be a promising direction. Unlike FB_ngon_encoding, meshlets can represent concave polygons and holes, although they have a different type of limitation where vertex/triangle counts are capped to 256.

@myaaaaaaaaa myaaaaaaaaa requested review from a team as code owners July 22, 2023 18:41
@fire
Copy link
Member

fire commented Jul 22, 2023

Formal spec https://github.com/UltraEngine/glTF/blob/main/extensions/2.0/Vendor/ULTRA_primitive_quads/README.md @aaronfranke if youre interested

@myaaaaaaaaa myaaaaaaaaa changed the title Implement preliminary awareness of quads via triangle pairs Implement preliminary support for bezier patch subdivision surfaces Jul 28, 2023
@myaaaaaaaaa myaaaaaaaaa marked this pull request as draft July 28, 2023 01:53
@myaaaaaaaaa myaaaaaaaaa changed the title Implement preliminary support for bezier patch subdivision surfaces [WIP] Implement preliminary support for bezier patch subdivision surfaces Jul 28, 2023
@fire
Copy link
Member

fire commented Jul 31, 2023

For the record I would like this, but need some review from @clayjohn and others.

@myaaaaaaaaa
Copy link
Contributor Author

Incidentally, I initially wrote this PR against Godot core for convenience sake, and to make it easier to investigate feasibility.

However, it's becoming evident that this mainly affects the importer, so it should be possible to move most of this into an official glTF-focused GDExtension and avoid impacting non-3D users of Godot, if this is desired.

Tessellation shaders will still need to involve core if they're ever implemented, though.

@EIREXE
Copy link
Contributor

EIREXE commented Aug 1, 2023

Assuming I'm reading this PR right, there's actually a bit of a use for bezier patches in core, hell quake 3 used them extensively. I was going to implement them myself for my own q3 style map system too.

@fire
Copy link
Member

fire commented Aug 1, 2023

Let me know when this is ready for merge review.

@myaaaaaaaaa myaaaaaaaaa changed the title [WIP] Implement preliminary support for bezier patch subdivision surfaces Implement preliminary support for bezier patch subdivision surfaces Aug 3, 2023
@myaaaaaaaaa myaaaaaaaaa marked this pull request as ready for review August 3, 2023 22:43
@myaaaaaaaaa
Copy link
Contributor Author

Hopefully this is adequate for the first pass, since it's all I can find the time for right now. Some functionality (such as bones) is still missing though, so only merge this if it's useful as-is (essentially static meshes only) and it's acceptable for the missing features to be added later.

@fire
Copy link
Member

fire commented Aug 31, 2023

What do I need to get bones functionality?

@myaaaaaaaaa
Copy link
Contributor Author

myaaaaaaaaa commented Sep 1, 2023

quads_to_bezier_patch() and tessellate_bezier_patch() will need to be extended to handle Mesh::ARRAY_BONES. Unlike the other attributes, Mesh::ARRAY_BONES is made up of discrete integer IDs, so they will need to be copied from the nearest quad point/bezier control point (essentially, nearest neighbor interpolation rather than the linear interpolation being used for the other attributes).

@fire
Copy link
Member

fire commented Sep 1, 2023

I haven’t had any rendering team approvals, but I can look into bones. Since theres a lack of rendering team approvals, the probability of merge is lower.

@myaaaaaaaaa myaaaaaaaaa deleted the quad1 branch September 16, 2023 00:19
@AThousandShips AThousandShips removed this from the 4.x milestone Sep 16, 2023
@fire
Copy link
Member

fire commented Oct 14, 2023

I salvaged the branch here https://github.com/V-Sekai/godot/tree/quad-bezier-surfaces as I am still interested in this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants