Page MenuHome

Geometry Nodes: Mirror node
AbandonedPublic

Authored by Fabian Schempp (fabian_schempp) on Jan 1 2021, 9:26 PM.

Details

Summary

This mirror node works on mesh and pointcloud data.
It takes two inputs the position and rotation of the mirror plane.

Note: One problem, which I haven't found an elegant solution for is, that the user can change the X-axis of rotation of the mirror plane, which does not change the result because it rotates the plane around the reflection normal.
That can be confusing.



Diff Detail

Repository
rB Blender
Branch
geometry_node_mirror (branched from master)
Build Status
Buildable 13805
Build 13805: arc lint + arc unit

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Fabian Schempp (fabian_schempp) retitled this revision from Geometry Nodes: Initial Port of the Mirror Modifier for Geomerty Nodes to Geometry Nodes: Mirror node.
Fabian Schempp (fabian_schempp) edited the summary of this revision. (Show Details)

Changed the Design to a much simpler version.

  • Works for mesh and pointcloud data.
  • Takes a single vector which is the position of the mirrored element. Mirror plane will be halfway between origin and position.
  • Outputs the mirrored side.
  • Takes a single vector which is the position of the mirrored element. Mirror plane will be halfway between origin and position.

I'm not sure how I feel about that. You loose the ability to define arbitrary mirrors, which is a big loss. If the user wanted a quick and easy mirror they would just use the modifier. I just see more users struggling to offset the geometry to fight with the mirror direction. It just feels like the best way to go about it is to define it as if it was setting up an actual planar reflection (position + surface vector), this would be powerful to use alongside vector math nodes.

  • Takes a single vector which is the position of the mirrored element. Mirror plane will be halfway between origin and position.

I'm not sure how I feel about that. You loose the ability to define arbitrary mirrors, which is a big loss. If the user wanted a quick and easy mirror they would just use the modifier. I just see more users struggling to offset the geometry to fight with the mirror direction. It just feels like the best way to go about it is to define it as if it was setting up an actual planar reflection (position + surface vector), this would be powerful to use alongside vector math nodes.

Its actually an arbitrary planar reflection. You can see it in the video.

I sort of agree with Kenzie in that I like the idea of defining the center point of the plane, but I haven't tested this patch so I can't be completely sure.

Something I mentioned in chat: I think one thing it should do is reverse the direction of all polygons in the mesh (by flipping around their section of the corner array). Face normals are calculated with the right hand rule, so it's important to do that or the normals will be wrong on the flipped version.


In general I'd prefer adding new files as C++ files, including the gizmo type file, then you can use types like float4x4 and float3, etc.

source/blender/editors/space_view3d/view3d_gizmo_mirror_plane.c
32 ↗(On Diff #35653)

Unused include (there are probably others)

58–64 ↗(On Diff #35653)

I'd return early instead of indenting here, sure it's a few more lines, but much more readable IMO

65–66 ↗(On Diff #35653)

You can probably use nodeGetActive and then check if it's a mirror node.

69 ↗(On Diff #35653)

I wonder if we should check whether there's a link into this socket, it's sort of misleading to expose the plane when it's controlled by a value from another socket.

121–125 ↗(On Diff #35653)

Same, nodeGetActive. Generally if you're doing trivial checks like this there's probably an existing abstraction.

source/blender/nodes/geometry/nodes/node_geo_mirror.cc
44

So far this function is the same as the existing transform_mesh from the transform node, maybe you can just call that for the actual position change part of it.

49–51

float4x4 mtx_loc = float4x4::itentity();

83

Don't forget to call geometry_set_realize_instances

Fabian Schempp (fabian_schempp) marked 7 inline comments as done.Mar 28 2021, 1:41 AM
Fabian Schempp (fabian_schempp) added inline comments.
source/blender/nodes/geometry/nodes/node_geo_mirror.cc
49–51

float4x4 mtx_loc = float4x4::itentity();

Strange. float4x4::itentity() does not build for me.

  • Changes based on review by Hans Goudey.
  • replaced float[3] with float3 and float[4][4] with float4x4 in c++ files
Fabian Schempp (fabian_schempp) marked an inline comment as done.Mar 28 2021, 9:19 AM
Fabian Schempp (fabian_schempp) added inline comments.
source/blender/nodes/geometry/nodes/node_geo_mirror.cc
49–51

Found the problem.

  • fixed mirror plane X rotation
  • Added normal recalculation.
  • fixed crash bug in gizmo poll.

Fix trivial merge conflicts with latest master

Hans Goudey (HooglyBoogly) requested changes to this revision.Mar 29 2021, 5:36 PM
  • The gizmo is very helpful!
  • If this works on point clouds (and potentially other geometry types), does it make sense to have it in the mesh category?
  • I still think "normal" might be a more useful input when this is controlled with vector math nodes, I'd like to get more opinions there, maybe when the patch is further along.
    • It would also avoid the problem with the X rotation.
  • I'm still running into the issue with the normals. Try moving the position attribute with the normal attribute. For the original mesh this makes it bigger, for the result of this, it makes it smaller.
  • Design-wise, the remaining question is whether this should deal with attributes like UV attributes, and if so, how. This is a bit of a more general question for attributes.
  • There is some really weird dependency on the last operation going on, only with meshes, not with point clouds though.

source/blender/editors/space_view3d/view3d_gizmo_mirror_plane.cc
65–71

Maybe do both of these checks on one line? Just like you did with the active node

122–137

You're basically repeating the entire "poll" check here.

  1. Is that necessary?
  2. If so, it makes sense to split it to a separate function and call it from here and the poll callback.
140

You can use rotation = float3(...

151

float3(0.0f) or float3(0) reads much better IMO.

Similarly for the other components.

source/blender/nodes/geometry/nodes/node_geo_mirror.cc
55

for (MVert &vert : MutableSpan(mesh->mvert, mesh->totvert)) {

60–62

Looks like you're only affecting the translation of the matrix. Do you really have to use matrix multiplication then or can you just translate? If so, maybe a comment or two would be helpful.

66

Pass arguments as const where possible

70

You should be able to skip the normalization that happens in project_v3_plane if you make sure normal is already normalized

95

This should be called in mirror_mesh

This revision now requires changes to proceed.Mar 29 2021, 5:36 PM
Fabian Schempp (fabian_schempp) marked 9 inline comments as done.
  • rebased to master
  • Changes based on Review by Hans Goudey.
  • changes category to geometry
  • Applied changes also to pointcloud code.
  • Revert poly winding order to solve normals.

This is only some code review. Didn't think about the ui part in more detail yet, Hans has thought about that more than I did :)

source/blender/editors/space_view3d/view3d_gizmo_mirror_plane.cc
76

Use an early return if the node is not of the correct type. This avoids some indentation.

96

I don't really know the widget system, but it seems like the wwrapper name is wrong. In other cases variables of this type are called navgroup.
wwrapper is used for variables with type wmGizmoWrapper.

source/blender/nodes/geometry/nodes/node_geo_mirror.cc
48

I think this function has to tag the normals dirty, otherwise smooth shading can get wrong.

67

Use a comment to explain what this loop is doing or extract it into a separate function with a meaningful name.

69

It seems in this specific case it would make sense to use a slightly large inline buffer by using Vector<uint, 16>. This will avoid allocations as long as polygons don't have a large number of vertices.
Furthermore, given that you know how many elements will by added beforehand, you can use an Array<uint, 16> instead. Then you need to assign the elements using an index instead of using append.

Fabian Schempp (fabian_schempp) marked 5 inline comments as done.Apr 7 2021, 11:35 PM
  • Changes based on Review by Jacques Lucke.
Kenzie (kenziemac130) added a comment.EditedApr 8 2021, 7:44 PM

I'm not sure I'm a fan of how internally the mirror_mesh function takes a normal input yet the node exposes a rotation. In my opinion rotations should only be used where a unit vector does not provide enough information to an operation, this is not the case here. I can get how Euler might be more friendly to people hand tweaking values it also adds an unnecessary step for people working with vector math who have to convert it to Euler only for it to be converted back internally. Maybe gathering more community feedback could be helpful here.

It also feels like while the widget is cool, since to my knowledge no other node implements widgets and there is no design precedent: it feels a bit "add-onish" rather than an atomic node and might be a bit of bloat that ends up weighing the task down in code review.

In the future more nodes should have their own widgets and it would be awesome to be able for users to write/compose their own for node assets. But for now it feels like you might be taking on some dead weight.

Thank you for working on this!

I'm not sure I'm a fan of how internally the mirror_mesh function takes a normal input yet the node exposes a rotation. In my opinion rotations should only be used where a unit vector does not provide enough information to an operation, this is not the case here. I can get how Euler might be more friendly to people hand tweaking values it also adds an unnecessary step for people working with vector math who have to convert it to Euler only for it to be converted back internally. Maybe gathering more community feedback could be helpful here.

And at the time I decided to use rotation instead of the normal it we haven't had the ball input in Geometry Nodes. It might work a lotbetter with that.

It also feels like while the widget is cool, since to my knowledge no other node implements widgets and there is no design precedent: it feels a bit "add-onish" rather than an atomic node and might be a bit of bloat that ends up weighing the task down in code review.

I still find that without the widget its very hard to understand what is happening. That was the main reason I added it as a possible solution.
But sure, as it is the first node that is using a widget, that puts additional weight on it.

The gizmo prototype is very interesting here, but at this point it's clear that a mirror node should be implemented as a node group.