I didn’t get any traction over at BA and I didn’t spot anything here either but how do I properly account for the screen-space size of my Gizmo?
Basically I want the Gizmo to be the same size regardless of how close the user is zoomed into the object. The built in gizmos seem to handle this properly but I can’t seem to find the right set of properties and matrices to set here.
Zoomed In – The spacing between the boxes here is what I’m after:
Zoomed Out – Incorrect; I want to maintain the offset between the boxes:
As you can see, the boxes correctly maintain their size (which is what I want), but they do NOT maintain their effective distance offset from each other (which I can’t figure out how to maintain).
And eh, why not, interesting code drop here. It’s a pretty standard setup except my GizmoGroup contains 6 Gizmo’s whereas the template examples typically deal with just 1:
class DCONFIG_GT_symmetry_gizmo(bpy.types.Gizmo):
# snip
# snip
# snip
def draw(self, context):
self.draw_custom_shape(self.custom_shape)
def draw_select(self, context, select_id):
self.draw_custom_shape(self.custom_shape, select_id=select_id)
def setup(self):
if not hasattr(self, "custom_shape"):
self.custom_shape = self.new_custom_shape('TRIS', self.cube_tri_verts)
def update(self, mat_target):
mat_t = Matrix.Translation(self.draw_offset * 0.25)
self.matrix_basis = mat_t @ mat_target
def invoke(self, context, event):
return {'RUNNING_MODAL'}
def modal(self, context, event, tweak):
if event.value == 'PRESS':
self.op.direction = self.direction
self.op.execute(context)
return {'FINISHED'}
return {'RUNNING_MODAL'}
class DCONFIG_GGT_symmetry_gizmo(bpy.types.GizmoGroup):
bl_label = "Symmetry Gizmo Group"
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_options = {'3D'}
@staticmethod
def my_target_operator(context):
wm = context.window_manager
op = wm.operators[-1] if wm.operators else None
return op if getattr(op, "dc_uses_symmetry_gizmo", False) else None
@classmethod
def poll(cls, context):
op = cls.my_target_operator(context)
if op is None:
wm = context.window_manager
wm.gizmo_group_type_unlink_delayed("DCONFIG_GGT_symmetry_gizmo")
DCONFIG_GT_symmetry_gizmo.restore_gizmos(context)
return False
return True
def setup(self, context):
def setup_widget(direction, draw_offset, color):
mpr = self.gizmos.new("DCONFIG_GT_symmetry_gizmo")
mpr.op = DCONFIG_GGT_symmetry_gizmo.my_target_operator(context)
mpr.direction = direction
mpr.draw_offset = draw_offset
mpr.color = color
mpr.alpha = 0.3
mpr.color_highlight = color
mpr.alpha_highlight = 0.5
mpr.select_bias = 0
mpr.scale_basis = 0.2
mpr.use_select_background = True
mpr.use_draw_scale = True
mpr.use_select_background = True
mpr.use_event_handle_all = False
ui_theme_prefs = context.preferences.themes[0].user_interface
setup_widget("POSITIVE_X", Vector((-1, 0, 0)), ui_theme_prefs.axis_x)
setup_widget("NEGATIVE_X", Vector((1, 0, 0)), ui_theme_prefs.axis_x)
setup_widget("POSITIVE_Y", Vector((0, -1, 0)), ui_theme_prefs.axis_y)
setup_widget("NEGATIVE_Y", Vector((0, 1, 0)), ui_theme_prefs.axis_y)
setup_widget("POSITIVE_Z", Vector((0, 0, -1)), ui_theme_prefs.axis_z)
setup_widget("NEGATIVE_Z", Vector((0, 0, 1)), ui_theme_prefs.axis_z)
def refresh(self, context):
target = context.active_object
mat_target = target.matrix_world.normalized()
for mpr in self.gizmos:
mpr.update(mat_target)