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

Add primitive 2D meshes #100574

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

rburing
Copy link
Member

@rburing rburing commented Dec 18, 2024

Adds RectangleMesh2D, CircleMesh2D, and CapsuleMesh2D, inheriting from the virtual base class PrimitiveMesh2D.

Allows drawing 2D shapes by using the existing (but so far perhaps underused) MeshInstance2D node:

primitive_mesh_2d

Example project: godot-primitive-mesh-2d.zip

primitive_mesh_2d_examples

The two fancy shapes on the right are obtained by applying vertex shaders to primitive meshes (kind of silly, but it works).

If you want a triangle, use a Polygon2D instead.

The code is based on the code for primitive 3D meshes.

@smix8
Copy link
Contributor

smix8 commented Dec 18, 2024

If you want a triangle, use a Polygon2D instead.

Join the 3-Vertex-CircleShape-Club.

@Geometror
Copy link
Member

Geometror commented Dec 18, 2024

I like it, but to be honest, I'm not sure whether this really closes the linked proposal.
Is this meant as an alternative to #99210 or complementary? Since the problem with this approach is that compared to the other PR you can't have outlines and fake anti-aliasing (which are rather important features IMO).

@smix8
Copy link
Contributor

smix8 commented Dec 18, 2024

...and fake anti-aliasing (which are rather important features IMO).

The antialiased for the internal Polygon2D is pure placebo that does exactly nothing.

A leftover from the Godot 3 days that used opengl canvas item triangle arrays while Godot 4 uses actual meshes.

@rburing
Copy link
Member Author

rburing commented Dec 18, 2024

If you want a triangle, use a Polygon2D instead.

Join the 3-Vertex-CircleShape-Club.

I was going to object, pointing out the radius property would not be "respected", but instead I just made it work.

I like it, but to be honest, I'm not sure whether this really closes the linked proposal.

The proposal asks for the ability to draw simple 2D shapes. It's not clear if those who voted on it also wanted outlines and fake anti-aliasing (or different kinds of triangles).

Is this meant as an alternative to #99210 or complementary?

It is meant to fill a feature gap (primitive 2D meshes). It's partly an alternative to that PR.

Since the problem with this approach is that compared to the other PR you can't have outlines and fake anti-aliasing (which are rather important features IMO).

I do agree those are nice features. Outlines should be achievable with this PR, e.g. with a material. I don't know much about how to achieve fake anti-aliasing, but I'll look into it.


Edit: One way to add an outline to a MeshInstance2D with a primitive 2D mesh is to make a duplicate of the node, make that duplicate a child of the original, set show_behind_parent = true in the inspector, and set material to a ShaderMaterial with a "grow" shader like this:

shader_type canvas_item;

uniform float outline_width = 5.0;
uniform vec4 color: source_color;

void vertex() {
	vec2 direction = normalize(VERTEX);
	if (length(direction) > 0.0) {
		VERTEX += direction * outline_width;
	}
}

void fragment() {
	COLOR = color;
}

@tetrapod00
Copy link
Contributor

For meshes, is it really expected that fake antialiasing is supported, when there is real 2D edge antialising available by using MSAA? If we go by parity with 3D meshes, there shouldn't be an expectation that meshes antialias themselves, IMO.

(I'm also not sure if this closes the linked issue, but that seems like a separate concern)

@AThousandShips AThousandShips added this to the 4.x milestone Dec 18, 2024
@mk56-spn
Copy link

this is very useful for those of us directly using the rendering server who want easy to use pre made meshes 👍

@rburing
Copy link
Member Author

rburing commented Dec 22, 2024

From the notes of the rendering team meeting on 19/12/2024:

AA should be built into the mesh.

  • Color should be set to white, then add a skirt around the mesh with color set to transparent white

The latest push adds an antialiased option to all primitive 2D meshes. Example project: godot-primitive-mesh-2d.zip

primitive_mesh_2d_antialiased

(Anti-aliasing is disabled for the procedural shapes on the right.)

Testing / reviews welcome!

@mk56-spn
Copy link

Screenshot from 2024-12-23 20-58-39

mostly works great, but rect mesh anti aliasing seems broken when the subdivide counts on each axis are mismatched

Copy link
Member

@kleonc kleonc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've checked only RectangleMesh2D generation, left some comments.

Comment on lines +269 to +277
Vector2 rect_size = size;
Vector2 uv_scale = Vector2(1, 1);
Vector2 uv_offset = Vector2(0, 0);
if (antialiased) {
rect_size -= Vector2(FEATHER_SIZE, FEATHER_SIZE);
uv_scale = Vector2(rect_size.x / (size.x + FEATHER_SIZE), rect_size.y / (size.y + FEATHER_SIZE));
uv_offset = Vector2(FEATHER_SIZE / (size.x + FEATHER_SIZE), FEATHER_SIZE / (size.y + FEATHER_SIZE));
}
Vector2 start_pos = rect_size * -0.5;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the uvs I'm not sure if it's desired that toggling antialiasing makes the texture "move":
VtEHYD6Bnq

Shouldn't it be shown exactly the same within the original rect regardless of the antialiasing, plus for antialiasing just add additional "smears" around? 🤔 (I think this would need more vertices for the corners though so it would interpolate correctly)

Also is it supposed to be FEATHER_SIZE-wide on each side, or FEATHER_SIZE * 0.5 on each side? Cause currently the original rect size is growing by FEATHER_SIZE, not by 2 * FEATHER_SIZE.

Copy link
Member Author

@rburing rburing Dec 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now turning on antialiasing shrinks each shape by FEATHER_SIZE * 0.5 and adds a border of size FEATHER_SIZE, so that the halfway point between solid and transparent lines up with where the border used to be. I did it that way to preserve the visual size, which works well at sizes a bit bigger than your tiny 5px rectangle. Maybe we could scale the feather size with the regular size (for tiny shapes), but it would become a bit unintuitive.

I would have liked to keep the texture shown the same way when antialiasing is toggled, but since there is no general UV scale/offset available to manipulate I think the only way would be to give the non-antialliased shape a shrunk UV map, which would be awkward as well for people who just want to use a normal primitive shape.

Allows drawing (anti-aliased) 2D shapes using MeshInstance2D.
Based on the code for primitive 3D meshes.
@KoBeWi
Copy link
Member

KoBeWi commented Jan 12, 2025

I tested this PR and #99210 is much better UX-wise.
Resizing mesh in 2D editor will change scale instead of mesh size and there are no convenient options for converting to other types.

Although the proposal pretty much only requests something to draw shapes, so this PR does the job too I guess.
EDIT:
Although it's interesting that for an arguably simpler solution, it introduces almost twice as much code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The icons are the same as for Shape2D.
You could make them filled at least.

@mk56-spn
Copy link

I tested this PR and #99210 is much better UX-wise. Resizing mesh in 2D editor will change scale instead of mesh size and there are no convenient options for converting to other types.

Although the proposal pretty much only requests something to draw shapes, so this PR does the job too I guess. EDIT: Although it's interesting that for an arguably simpler solution, it introduces almost twice as much code.

I don't have the ability to comment on UX and code quality stuff but i can say that that PR does not offer near the same convenience for certain work flows .

For example this PR allows making meshes you can pretty much directly throw at the rendering server. for the other pr such usage would require instantiating the node in code then generating the meshinstance2D from the nodes drop-down then getting and saving the mesh from that meshinstance and then using it on the rendering server, which is comically obtuse

maybe i'm wrong and a step or two can be spared but it stands that these do not ( imo ) target the same use cases an should not be seen as true alternatives ( not necessarily saying you are treating them as such )

@kitbdev
Copy link
Contributor

kitbdev commented Jan 14, 2025

Note that this also adds these options to MeshInstance3D as well. They work, so I don't think it is an issue.

When a capsule is at its minimum height to radius ratio and anti-aliasing is on a line shows:

Screenshot 2024-12-28 140607

Using the circle to make polygons would be better if they pointed up instead of down.

There is no way to make a right triangle with these, but I don't know how much demand there is for it.

Compared to #99210 sizes are changed from 128x128 to 20x20, I feel like that is a bit small but maybe its just me.

This could have custom handles like the CollisionShape2DEditor for better usability so resizing doesn't scale.

There is no conversion to other types, and it is trickier since it is not stored as a polygon.

I was thinking that there could be an alternate way to define the 2D shapes to make the code smaller and easier to use. Since they are all 2D, they can be defined by a polygon (a list of points). It can convert the points into the required mesh vertices, indexes, and UVs. This would be on top of the regular functionality so it is optional. All the antialiasing (or outlines if added) could be added there and generically used for all of the shapes. If it is stored it would also be useful to convert into other types in the Editor. I guess its is pretty similar to what Polygon2D does, but saved in a Mesh Resource.

If all of this can be done, I think the UX would be better than #99210.
Lots of it can be done in future PRs as well.

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.

Add a Shape2D node to draw 2D shapes
9 participants