3D View - Как отобразить данные камеры в кадре камеры?

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 строки при первом запуске скрипта? А пока скрипт считывает фокус и записывает его. Как сделать так, чтобы сценарий читался каждый раз при смене фокуса?

Ответы

3 brockmann Aug 20 2020 at 00:55

AFAIK это невозможно по умолчанию, и я предполагаю, что не существует надстройки, которая могла бы отображать любую информацию в кадре камеры.

Однако вы можете нарисовать текст с помощью модуля python bgl и создать свое собственное дополнение. Следующий пример кода основан на нашем знаменитом шаблоне Operator Modal Draw, который поставляется с блендером, расширенный ответами из Координаты углов границы обзора камеры и Многострочный текст в 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 View, нажмите F3и введите «Simple Operator ...» для выполнения. Если вы хотите преобразовать его в надстройку, просто добавьте словарь python с именем «bl_info» вверху надстройки:https://wiki.blender.org/wiki/Process/Addons/Guidelines/metainfo


Чтобы заставить его работать для версий 2.7x, вам придется заменить 2 строки из-за изменений в Matrix Multiplication и того, как установить цвет текста с помощью blf.color в более новых версиях:

# 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