Determine the orientation of a view

I was hoping someone could help me to find the simplest means of determining the orientation of a 3D view. I am writing an operator that uses the mouse location as an input, converts to a 3d location and then scales the background image depending on the difference between two user selected points. It works just fine when I am in ‘top’ view, but it does not work when I am in right, left or any other view; basically because it only currently uses the x and y coordinates of the 3d view.

I am always using parallel projection for this script (since background images dont show in perspective). I know that I need to change my code to use the z-coordinate depending on the view orientation, but I dont know how to determine the current view orientation.

Thanks in advance…

Update…

Thanks for the replies. I managed to figure it out, essentially using the dir() commands and online docs. In the end I found that context.area.spaces[0].region_3d has a property called perspective_matrix. I normalised this and was able to then use it to test for the view orientation based on the pattern of -1, 0 and 1 in the third column of the matrix.

CoDEmanX… your suggestion was more related to the point picking routine, and I amde use of exactly that example when I derived that part of the code. The bit I have solved now is to determine whether the user is looking at the top, front, or side view so that I can properly scale the background image.

I never know quite how to find things in the context, but try finding the spaceView3d in the active context. I would assume you can find all of the transformation values on that object. I use the python dir() command on bpy.context to try to find whatever objects.

I’m sure there’s a much better way though. Sorry I can’t answer your question more concisely, but it’s a starting point if you don’t get a better response.

you may have a look at the Raycast template:

import bpyfrom mathutils import Vector
from bpy_extras import view3d_utils




def main(context, event, ray_max=10000.0):
    """Run this function on left mouse, execute the ray cast"""
    # get the context arguments
    scene = context.scene
    region = context.region
    rv3d = context.region_data
    coord = event.mouse_region_x, event.mouse_region_y


    # get the ray from the viewport and mouse
    view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
    ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
    ray_target = ray_origin + (view_vector * ray_max)




    def visible_objects_and_duplis():
        """Loop over (object, matrix) pairs (mesh only)"""


        for obj in context.visible_objects:
            if obj.type == 'MESH':
                yield (obj, obj.matrix_world.copy())


            if obj.dupli_type != 'NONE':
                obj.dupli_list_create(scene)
                for dob in obj.dupli_list:
                    obj_dupli = dob.object
                    if obj_dupli.type == 'MESH':
                        yield (obj_dupli, dob.matrix.copy())


            obj.dupli_list_clear()


    def obj_ray_cast(obj, matrix):
        """Wrapper for ray casting that moves the ray into object space"""


        # get the ray relative to the object
        matrix_inv = matrix.inverted()
        ray_origin_obj = matrix_inv * ray_origin
        ray_target_obj = matrix_inv * ray_target


        # cast the ray
        hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)


        if face_index != -1:
            return hit, normal, face_index
        else:
            return None, None, None


    # cast rays and find the closest object
    best_length_squared = ray_max * ray_max
    best_obj = None


    for obj, matrix in visible_objects_and_duplis():
        if obj.type == 'MESH':
            hit, normal, face_index = obj_ray_cast(obj, matrix)
            if hit is not None:
                hit_world = matrix * hit
                scene.cursor_location = hit_world
                length_squared = (hit_world - ray_origin).length_squared
                if length_squared < best_length_squared:
                    best_length_squared = length_squared
                    best_obj = obj


    # now we have the object under the mouse cursor,
    # we could do lots of stuff but for the example just select.
    if best_obj is not None:
        best_obj.select = True
        context.scene.objects.active = best_obj




class ViewOperatorRayCast(bpy.types.Operator):
    """Modal object selection with a ray cast"""
    bl_idname = "view3d.modal_operator_raycast"
    bl_label = "RayCast View Operator"


    def modal(self, context, event):
        if event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
            # allow navigation
            return {'PASS_THROUGH'}
        elif event.type == 'LEFTMOUSE':
            main(context, event)
            return {'RUNNING_MODAL'}
        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            return {'CANCELLED'}


        return {'RUNNING_MODAL'}


    def invoke(self, context, event):
        if context.space_data.type == 'VIEW_3D':
            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "Active space must be a View3d")
            return {'CANCELLED'}




def register():
    bpy.utils.register_class(ViewOperatorRayCast)




def unregister():
    bpy.utils.unregister_class(ViewOperatorRayCast)




if __name__ == "__main__":
    register()

There is some 2d / 3d conversion.

If you wanna do it yourself, then you can find the view matrix here:

bpy.context.space_data.region_3d.view_matrix

if you don’t run this from view 3d, then you rather need to use:

for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        area.spaces[0].region_3d.view_matrix
        break # only the first 3d view
else:
    print("no 3d view found")