How to use view_matrix to rotate bmesh

I’d like to align a plane to the current view with bmesh.
I can successfully do it without bmesh if I create the plane with bpy.ops.mesh.primitive_plane_add and use the view matrix transposed to Euler to orient it:

viewEuler=bpy.context.region_data.view_matrix.transposed().to_euler()
bpy.ops.mesh.primitive_plane_add(radius=1,location=(0,0,0),rotation=viewEuler)

However, this is not the case if I create it with bmesh and use the view_matrix as is:

obj=bpy.context.object
bm = bmesh.from_edit_mesh(obj.data)
viewMat=bpy.context.region_data.view_matrix
bmesh.ops.create_grid(bm, x_segments=3, y_segments=3, size=2, matrix=viewMat)

How can I convert the view matrix so that bmesh can use it to rotate the plane as expected?

In my case I don’t care about the position, whether it’s at 0 or somewhere else. I just need the rotation to be aligned.

When you say you want the rotation aligned, are you talking about the plane being visually aligned, or do you want the object itself to have the rotation while the mesh data is axis aligned (so if you were to zero out the object rotation it would be sitting flat on the ground plane)? Also, what results are you currently getting?

basically I want the same result as if I were to go in edit mode, add a plane and select “View” in the dropdown menu for Align.

Currently what I get in bmesh is an orientation that, while being dependent on the view, is not aligned to it, nor consistently following it. I don’t really understand what’s causing that. Perhaps a different rotation order or a different format for the matrix rows and columns.

if you run the above second snippet as an operator in the viewport, you can see that behavior.

you need to invert your view matrix. remember that it’s being created exactly at the camera’s position so you won’t see it until you move the camera back a bit (either that or transform the bmesh to move your geometry somewhere else)

import bpy, bmesh

area = None
for a in bpy.context.workspace.screens[0].areas:
    if a.type == 'VIEW_3D':
        area = a
        break

obj = bpy.context.active_object
bm = bmesh.from_edit_mesh(obj.data)
viewMat = area.spaces[0].region_3d.view_matrix
bmesh.ops.create_grid(bm, x_segments=3, y_segments=3, size=2, matrix=viewMat.inverted())
bmesh.update_edit_mesh(obj.data, destructive=True)
2 Likes

Awesome! Thank you very much!