4
$\begingroup$

I want to show some Info in the viewport something like vertex indices

enter image description here

you can see select a vertex and press N to see vertex position but it's hard.

enter image description here

so I liked to write a script to show the vertex position

enter image description here

I tried to use opengl but text was blurry and I couldn't make what I want.

# import stand alone modules
import blf
import bpy

font_info = {
    "font_id": 0,
    "handler": None,
}


def init():
    """init function - runs once"""
    import os
    # Create a new font object, use external ttf file.
    font_path = bpy.path.abspath('//Zeyada.ttf')
    # Store the font indice - to use later.
    if os.path.exists(font_path):
        font_info["font_id"] = blf.load(font_path)
    else:
        # Default font.
        font_info["font_id"] = 0

    # set the font drawing routine to run every frame
    font_info["handler"] = bpy.types.SpaceView3D.draw_handler_add(
        draw_callback_px, (None, None), 'WINDOW', 'POST_VIEW')


def draw_callback_px(self, context):

    """Draw on the viewports"""
    # BLF drawing routine
    font_id = font_info["font_id"]
    #blf.position(font_id, pos.x, pos.y, pos.z)
    #blf.size(font_id, 100,100)
    #blf.draw(font_id, "Hello World")

    pos = bpy.context.object.location
    v3d = context.space_data
    rv3d = v3d.region_3d
    pos_text = location_3d_to_region_2d(region, rv3d, context._center)
    
    blf.position(font_id, pos_text[0], pos_text[1], 0)
    blf.size(font_id, 100,100)
    blf.draw(font_id, "Hello World")


if __name__ == '__main__':
    init()
$\endgroup$
4
  • $\begingroup$ Related blender.stackexchange.com/questions/139831/… Suggest this could be marked as dupe of blender.stackexchange.com/questions/137816/… If you are sourcing code from elsewhere add a link for context. $\endgroup$
    – batFINGER
    Commented Sep 3, 2020 at 23:31
  • $\begingroup$ @batFINGER thank you it's what I want. I just want to show text in 3d viewport I'm wondering why I didn't find that post because I searched a lot! $\endgroup$ Commented Sep 4, 2020 at 4:32
  • $\begingroup$ @batFINGER I edited my question based on links that you sent me but I don't know why I can't see text in the viewport!!! $\endgroup$ Commented Sep 4, 2020 at 4:59
  • $\begingroup$ Convert 3d global coords to region coords. The global location of an object is always ob.matrix_world.translation which may or may not be ob.location See blender.stackexchange.com/questions/6155/… New edit are passing None as context argument, yet trying to use it, which will throw errors to console. $\endgroup$
    – batFINGER
    Commented Sep 4, 2020 at 5:33

3 Answers 3

2
$\begingroup$

Well, you are passing no context

(None, None)

but then using some context in draw_callback_px that is None

you should use POST_PIXEL because it isn't 3d

bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (bpy.context, None), 'WINDOW', 'POST_PIXEL')

you forgot to import location_3d_to_region_2d libraries

import bpy
from bpy_extras.view3d_utils import location_3d_to_region_2d

Go to Window > Open System Console and you will see all the errors so you can have something to debug what is happening there

enter image description here

convert coordinates from vertex to world-space

Multiply the world matrix by the object-space vector for world space coordinate:

import bpy

ob = bpy.data.objects['Cube']

v = ob.data.vertices[0].co
mat = ob.matrix_world

# Multiply matrix by vertex
loc = mat @ v

import blf
import bpy
from bpy_extras.view3d_utils import location_3d_to_region_2d


def draw_callback_px(context, dummy):
    ob = bpy.data.objects['Cube']

    v = ob.data.vertices[0].co
    mat = ob.matrix_world

    # Multiply matrix by vertex
    pos = mat @ v
    
    v3d = context.space_data
    rv3d = v3d.region_3d
    pos_text = location_3d_to_region_2d(context.region, rv3d, pos)

    blf.position(0, pos_text[0], pos_text[1], 0)
    blf.size(0, 1,1)
    blf.draw(0, str(pos))


bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (bpy.context, None), 'WINDOW', 'POST_PIXEL')

special thanks for @jfranmatheu and @batFINGER

$\endgroup$
1
  • 1
    $\begingroup$ Good one you got there in the end. Note using me.vertices will most likely not work as expected in edit mode if you start moving them. Check out blender.stackexchange.com/a/160913/15543 $\endgroup$
    – batFINGER
    Commented Sep 4, 2020 at 21:00
2
$\begingroup$

Although this has become a perfectly legitimate question about scripting, for anybody searching on the title alone, it might be worth pointing out that the shipped add-on MeasureIt tools can display vertex locations:

enter image description here

It's configurable for font size and color, and to show global or local coordinates.

$\endgroup$
1
$\begingroup$

I'm sorry for necroposting, but the selected answer seems like it is no more valid. I'm using Blender 3.0.0 and there are a lot of errors thrown around, so I decided to write the script myself. It is my first time creating a script, so pointing out problems in the comments would be useful

Aside from fixing it, I added some additional functionality, like 2 commands to toggle the script, reduced text bloat, display 2 sets of positions (actual vertices with RGBA (0, 0, 0, .5), and bounding box with RGBA (0, 0, 1, 1))

import blf
import bpy
import sys
from bpy_extras.view3d_utils import location_3d_to_region_2d
from mathutils import Vector

handler = None

class Show(bpy.types.Operator):
  bl_idname = "object.show_vertices_pos"
  bl_label = "Show vertices pos"
  def execute(self, context):
    global handler
    handler = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (bpy.context, None), 'WINDOW', 'POST_PIXEL')
    return {"FINISHED"}
class Hide(bpy.types.Operator):
  bl_idname = "object.hide_vertices_pos"
  bl_label = "Hide vertices pos"
  def execute(self, context):
    global handler
    bpy.types.SpaceView3D.draw_handler_remove(handler, 'WINDOW')
    return {"FINISHED"}

bpy.utils.register_class(Show)
bpy.types.VIEW3D_MT_object.append(lambda self, context: self.layout.operator(Show.bl_idname, text = Show.bl_label))
bpy.utils.register_class(Hide)
bpy.types.VIEW3D_MT_object.append(lambda self, context: self.layout.operator(Hide.bl_idname, text = Hide.bl_label))

def pos_to_text(context, pos, color):
  pos = bpy.context.object.matrix_world@pos
  pos_text = location_3d_to_region_2d(context.region, context.region_data, pos)

  blf.position(0, pos_text[0], pos_text[1], 0)
  blf.size(0, 35, 35)
  blf.color(0, *color)
  blf.draw(0, "{0:.1f} {1:.1f} {2:.1f}".format(pos.x, pos.y, pos.z))
def draw_callback_px(context, dummy):
  if bpy.context.object is None:
    return

  box = [Vector((sys.float_info.max, sys.float_info.max, sys.float_info.max)), Vector((sys.float_info.min, sys.float_info.min, sys.float_info.min))]

  for v in bpy.context.object.data.vertices:
    pos_to_text(context, v.co, [0, 0, 0, .5])
    box = [Vector((min(box[0][0], v.co[0]), min(box[0][1], v.co[1]), min(box[0][2], v.co[2]))), Vector((max(box[1][0], v.co[0]), max(box[1][1], v.co[1]), max(box[1][2], v.co[2])))]

  if len(bpy.context.object.data.vertices) > 0:
    for i in range(2):
      for i_2 in range(2):
        for i_3 in range(2):
          pos_to_text(context, Vector((box[i][0], box[i_2][1], box[i_3][2])), [0, 0, 1, 1])
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .