1
$\begingroup$

I am trying to work out a script that adds a plane aligned to the camera view, but I cannot figure out how to do anything past it being aligned to the current view. This works fine mostly, as long as I am in the camera view, but it would be much more convenient to not have to be in camera view.

This is what I have so far:

import bpy

# Add a plane and align it to view
for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        for region in area.regions:
            if region.type == 'WINDOW':
                ctx = bpy.context.copy()
                ctx['area'] = area
                ctx['region'] = region
                bpy.ops.mesh.primitive_plane_add(ctx, view_align=True)
                bpy.ops.object.editmode_toggle() # Avoid a missing face

# Add diffuse shader to object
activeObject = bpy.context.active_object
mat = bpy.data.materials.new(name="grey card")
activeObject.data.materials.append(mat)
bpy.context.object.active_material.diffuse_color = (.18, .18, .18)

I have seen this question, and the accepted answer says to assign the camera object's rotation_euler to the object to be aligned with C.object.rotation_euler = C.scene.camera.rotation_euler, but I am not sure what to do with this advice (as it may be evident, Python is not a strength, but I'm trying to learn).

What do I need to change in this script in order for it to work as I am wanting it to?

$\endgroup$
  • $\begingroup$ Assigning the Euler's rotation works in sens it will make the plane parallel to the camera view (which does not mean that the plane is visible by the camera). Could you please explain a bit more your issue from that? $\endgroup$ – lemon Mar 9 '17 at 9:09
2
$\begingroup$

You could simply use a 'Copy Rotation' constraint to ensure that the created plane always points in the same direction as the camera. To achieve this in Python you could do the following :

import bpy

# Create a new plane
bpy.ops.mesh.primitive_plane_add(radius=1, view_align=False, enter_editmode=False, location=(0, 0, 0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))

#Create constraint and set target to 'Camera'
bpy.ops.object.constraint_add(type='COPY_ROTATION')
bpy.context.object.constraints["Copy Rotation"].target = bpy.data.objects["Camera"]
| improve this answer | |
$\endgroup$
5
$\begingroup$

enter image description here

Since you want to align the object with the current view (and not the camera), you need to extract that view through the view 3D's region_3d (rv3d in the example below), then assign its rotation to the object you want to align the view with:

import bpy
def view3d_find( return_area = False ):
    # returns first 3d view, normally we get from context
    for area in bpy.context.window.screen.areas:
        if area.type == 'VIEW_3D':
            v3d = area.spaces[0]
            rv3d = v3d.region_3d
            for region in area.regions:
                if region.type == 'WINDOW':
                    if return_area: return region, rv3d, v3d, area
                    return region, rv3d, v3d
    return None, None

r3d, rv3d, v3d = view3d_find()

# Add new plane which will become the context object
bpy.ops.mesh.primitive_plane_add()

bpy.context.object.rotation_euler = rv3d.view_rotation.to_euler()
| improve this answer | |
$\endgroup$
  • $\begingroup$ Hi, thanks for the answer. Maybe I did something incorrectly, this does indeed align an existing object to the camera, but I want to add a new plane aligned to camera view. I replaced my first 7 lines with this, is this correct? $\endgroup$ – Timaroberts Mar 9 '17 at 9:33
  • $\begingroup$ @Timaroberts, revised code above to add a new plane which will be aligned with the view. $\endgroup$ – TLousky Mar 9 '17 at 9:36
  • $\begingroup$ I'm sorry if there was a missing detail in my question, but I'm afraid this is still where I started (though much cleaner it seems, no need to toggle edit mode to not lose a face). The objective is to align the plane with the camera regardless of the current view. $\endgroup$ – Timaroberts Mar 9 '17 at 9:55
  • $\begingroup$ That's exactly what C.object.rotation_euler = C.scene.camera.rotation_euler, will do. But you said that didn't work for you. Perhaps you can clarify what you need better, and what doesn't work? $\endgroup$ – TLousky Mar 9 '17 at 9:57
  • $\begingroup$ I didn't mean that it didn't work for me, sorry for the confusion. What I'm struggling with is understanding how to use it. $\endgroup$ – Timaroberts Mar 9 '17 at 10:10
1
$\begingroup$

the script can be simplified as a function

def main(context):

    rv3d = context.region_data
    context.object.rotation_euler = rv3d.view_rotation.to_euler()

you can run it putting the main in the simple object operator template and running it from the 3Dview. with an active object

| improve this answer | |
$\endgroup$
  • 2
    $\begingroup$ This is re script in answer of TLousky. Question was re aligning to camera not view3d. Assumes the object is in Euler rotation mode. For all rotation modes decompose the matrix and recompose with the new rotation. $\endgroup$ – batFINGER May 2 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.