3Dビュー—カメラフレームにカメラデータを表示する方法は?

Aug 17 2020

「オブジェクト情報」や「ビュー名」(ビューポートの設定)などの表示オプションを使用して、アクティブなカメラの焦点の長さや位置などの他の情報を表示する方法はありますか。そして、この情報を3Dウィンドウのどこかに移動する方法はありますか?この例のように:

そこで、3Dウィンドウに焦点を表示できるスクリプトを見つけました。

import bpy
import blf

dns = bpy.app.driver_namespace 
dc = dns.get("dc")
dc.remove_handle()

class DrawingClass:
    def __init__(self, context, prop):
        self.prop = prop
        self.handle = bpy.types.SpaceView3D.draw_handler_add(
                   self.draw_text_callback,(context,),
                   'WINDOW', 'POST_PIXEL')

    def draw_text_callback(self, context):
        font_id = 0  # XXX, need to find out how best to get this.

        # draw some text
        blf.position(font_id, 15, 350, 0)
        blf.size(font_id, 20, 72)
        blf.draw(font_id, "%s %s" % (context.scene.name, self.prop))

    def remove_handle(self):
         bpy.types.SpaceView3D.draw_handler_remove(self.handle, 'WINDOW')

context = bpy.context             
dns = bpy.app.driver_namespace
dns["dc"] = DrawingClass(context, bpy.context.object.data.lens)

最初の3行で、前の表示を消去できます。スクリプトを最初に実行したときに、scipteが最初の3行を読み取らないようにするにはどうすればよいですか?今のところ、スクリプトはフォーカルを1回読み取り、書き込みます。フォーカルが変更されるたびにスクリプトが確実に読み取られるようにするにはどうすればよいですか?

回答

3 brockmann Aug 20 2020 at 00:55

デフォルトでは不可能なAFAIKであり、カメラフレームにあらゆる種類の情報を表示できる既存のアドオンはないと思います。

ただし、Pythonのbglモジュールを使用してテキストを描画し、独自のアドオンを作成することはできます。次のコード例が基づいている私たちの有名なオペレータモーダル描くから回答によって拡張ブレンダーに付属しているテンプレート、カメラビューの境界線の角の座標と(マルチカラーオプション付き)BLFでの複数行のテキストボールの転がりを得るために:

hud.py

import bpy
import blf
import bgl


# -> BASED ON: https://blender.stackexchange.com/a/14746/31447
def view3d_find(context):
    # returns first 3d view, normally we get from context
    for area in 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':
                    return region, rv3d
    return None, None

def view3d_camera_border(context):
    obj = context.scene.camera
    cam = obj.data

    frame = cam.view_frame(scene=context.scene)
    # move from object-space into world-space 
    frame = [obj.matrix_world @ v for v in frame]

    # move into pixelspace
    from bpy_extras.view3d_utils import location_3d_to_region_2d
    region, rv3d = view3d_find(context)
    frame_px = [location_3d_to_region_2d(region, rv3d, v) for v in frame]
    return frame_px

# -> BASED ON: https://blender.stackexchange.com/a/31799/31447
def draw_string(x, y, packed_strings):
    font_id = 0
    blf.size(font_id, 18, 72) 
    x_offset = 0
    y_offset = 0
    line_height = (blf.dimensions(font_id, "M")[1] * 1.45)
    for command in packed_strings:
        if len(command) == 2:
            pstr, pcol = command
            blf.color(font_id, pcol[0], pcol[1], pcol[2], pcol[3]) # #bgl.glColor4f(pcol)
            text_width, text_height = blf.dimensions(font_id, pstr)
            blf.position(font_id, (x + x_offset), (y + y_offset), 0)
            blf.draw(font_id, pstr)
            x_offset += text_width
        else:
            x_offset = 0
            y_offset -= line_height

def draw_callback_px(self, context):
    
    WHITE = (1, 1, 1, .7)
    CR = "Carriage Return"
    
    x, y = view3d_camera_border(context)[3]
    cam_ob = context.scene.camera
    
    if cam_ob is not None:
        ps = [
            ("{} {}mm".format(cam_ob.name, cam_ob.data.lens), WHITE), 
            CR,
            CR, 
            ("T: {:.2f}, {:.2f}, {:.2f}".format(
                cam_ob.location.x, 
                cam_ob.location.y, 
                cam_ob.location.z), WHITE),
            CR,
            ("R: {:.2f}, {:.2f}, {:.2f}".format(
                cam_ob.rotation_euler.x, 
                cam_ob.rotation_euler.y, 
                cam_ob.rotation_euler.z), WHITE),        
        ]
    
    draw_string(x+10, y-20, ps)
    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)

# -> MODAL OPERATOR TEMPLATE
class ModalDrawOperator(bpy.types.Operator):
    """Draw a line with the mouse"""
    bl_idname = "view3d.modal_operator"
    bl_label = "Simple Modal View3D Operator"

    @classmethod
    def poll(cls, context):
        return context.area.type == 'VIEW_3D'
    
    def modal(self, context, event):
        context.area.tag_redraw()
        
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}
        
        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        if context.space_data.region_3d.view_perspective == 'CAMERA':
            # the arguments we pass the the callback
            args = (self, context)
            # Add the region OpenGL drawing callback
            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "Switch into Camera View")
            return {'CANCELLED'}



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


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


if __name__ == "__main__":
    register()

スクリプトをコピーしてテキストエディタに貼り付け、実行し、3Dビューに移動し、F3「SimpleOperator ...」を押して入力して実行します。アドオンに変換したい場合は、アドオンの上部に「bl_info」という名前のPython辞書を追加するだけです。https://wiki.blender.org/wiki/Process/Addons/Guidelines/metainfo


2.7xバージョンで機能させるには、行列乗算の変更と、新しいバージョンでblf.colorを使用してテキストの色を設定する方法のために、2行を置き換える必要があります。

# draw_string()
- blf.color(font_id, pcol[0], pcol[1], pcol[2], pcol[3]) # Blender 2.8x
+ bgl.glColor4f(*pcol) # Blender 2.7x

# view3d_camera_border()
- frame = [obj.matrix_world @ v for v in frame] # Blender 2.8x
+ frame = [obj.matrix_world * v for v in frame] # Blender 2.7x