Skip to content

Instantly share code, notes, and snippets.

@tomol
Last active February 7, 2020 06:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomol/418b1bbbdaf2f5b4d72f336c1a41d260 to your computer and use it in GitHub Desktop.
Save tomol/418b1bbbdaf2f5b4d72f336c1a41d260 to your computer and use it in GitHub Desktop.
頂点を1点または2点選択して,その頂点の座標が指定した値の位置になるよう,選択したオブジェクト全てを拡縮する(実行は編集モードのメッシュから) 特定の箇所の大きさを基準にしてスケールを合わせたいときに
bl_info = {
"name": "Scaling objects by selected vert location",
"author": "mol",
"version": (1, 0),
"blender": (2, 81, 0),
"location": "View3D > Mesh",
"description": "Scaling selected objects by specifying selected vert location",
"warning": "",
"support": "COMMUNITY",
"wiki_url": "",
"category": "Scaling Object",
}
import bpy
from bpy.props import FloatProperty
from bpy.props import BoolVectorProperty
from bpy.props import EnumProperty
from mathutils import Vector
import math
def axis_list_fn(scene, context):
items = [
('X', "X", "Scaling to x axis"),
('Y', "Y", "Scaling to y axis"),
('Z', "Z", "Scaling to z axis")
]
return items
class SCALING_OT_selected_objects_by_vert_location(bpy.types.Operator):
bl_idname = "scaling.selected_object"
bl_label = "Scaling selected object"
bl_options = {'REGISTER', 'UNDO'}
location: FloatProperty(
name = "location",
description = "",
default = 1.0
)
axis: EnumProperty(
name = "axis",
description = "",
items = axis_list_fn
)
def execute(self, context):
bpy.ops.object.mode_set(mode='OBJECT')
# Search selected vert from selected objects
# Get vert location and vert belongs obj
w_slct_verts_subed = None
# 選択されてる点の座標をworld座標系で取得
for obj in context.selected_objects:
# 他の種類のオブジェクト(特にアーマチュア)を選択していても一緒に拡大できるように
if type(obj.data) != bpy.types.Mesh:
continue
w_mat = obj.matrix_world
for vert in obj.data.vertices:
if vert.select == True:
# 1点よりも多く選択されていたらエラー
if w_slct_verts_subed != None:
self.report({'WARNING'}, "Operate is canceled. More than one vertex selected.")
return{'CANCELLED'}
w_slct_verts_subed = w_mat @ vert.co
# 選択が無ければエラー
if w_slct_verts_subed == None:
self.report({'WARNING'}, "Operate is canceled. Vertex not selected.")
return{'CANCELLED'}
# axisの値に応じてscaleに使う値を変更
scale = 1
if self.axis == 'X':
# 0除算対策
if w_slct_verts_subed[0] != 0:
scale = self.location / w_slct_verts_subed[0]
elif self.axis == 'Y':
if w_slct_verts_subed[1] != 0:
scale = self.location / w_slct_verts_subed[1]
elif self.axis == 'Z':
if w_slct_verts_subed[2] != 0:
scale = self.location / w_slct_verts_subed[2]
# 各オブジェクトの原点が(0, 0, 0)にあるとは限らないので,3Dカーソルを(0, 0, 0)に移してそこを中心に拡大
# 最後に戻すために現在の設定を取得
temp_cursor_loc = Vector(context.scene.cursor.location)
temp_pivot = context.scene.tool_settings.transform_pivot_point
context.scene.cursor.location = (0, 0, 0)
context.scene.tool_settings.transform_pivot_point = 'CURSOR'
bpy.ops.transform.resize(value = (scale, scale, scale))
context.scene.cursor.location = temp_cursor_loc
context.scene.tool_settings.transform_pivot_point = temp_pivot
bpy.ops.object.mode_set(mode='EDIT')
return {'FINISHED'}
class SCALING_OT_scaling_by_two_selected_verts_location(bpy.types.Operator):
bl_idname = "scaling.by_two_selected_verts_location"
bl_label = "Scaling selected object by two selected verts location"
bl_options = {'REGISTER', 'UNDO'}
location: FloatProperty(
name = "location",
description = "",
default = 1.0
)
axis: EnumProperty(
name = "axis",
description = "",
items = axis_list_fn
)
def execute(self, context):
bpy.ops.object.mode_set(mode='OBJECT')
# Search selected vert from selected objects
# Get vert location and vert belongs obj
w_slct_vert_co_1 = None
w_slct_vert_co_2 = None
# 選択されてる点の座標をworld座標系で取得
for obj in context.selected_objects:
# 他の種類のオブジェクト(特にアーマチュア)を選択していても一緒に拡大できるように
if type(obj.data) != bpy.types.Mesh:
continue
w_mat = obj.matrix_world
for vert in obj.data.vertices:
if vert.select == True:
if w_slct_vert_co_1 == None:
w_slct_vert_co_1 = w_mat @ vert.co
elif w_slct_vert_co_2 == None:
w_slct_vert_co_2 = w_mat @ vert.co
# 2点よりも多く選択されていたらエラー
else:
self.report({'WARNING'}, "Operate is canceled. More than two vertex selected.")
return{'CANCELLED'}
# 選択が無ければエラー
if w_slct_vert_co_1 == None:
self.report({'WARNING'}, "Operate is canceled. Vertex not selected.")
return{'CANCELLED'}
# 選択が1つならエラー
if w_slct_vert_co_2 == None:
self.report({'WARNING'}, "Operate is canceled. Not enough vertices selected.")
return{'CANCELLED'}
# axisの値に応じてscaleに使う値を変更
scale = 1
w_slct_verts_subed = w_slct_vert_co_1 - w_slct_vert_co_2
if self.axis == 'X':
# 0除算対策
if w_slct_verts_subed[0] != 0:
# fabsで絶対値にすることでx軸方向の長さに変換
scale = self.location / math.fabs(w_slct_verts_subed.x)
elif self.axis == 'Y':
if w_slct_verts_subed[1] != 0:
scale = self.location / math.fabs(w_slct_verts_subed.y)
elif self.axis == 'Z':
if w_slct_verts_subed[2] != 0:
scale = self.location / math.fabs(w_slct_verts_subed.z)
# 各オブジェクトの中心へ拡縮するため,ピボットを変更しつつ拡縮
# 最後に戻すために現在の設定を取得
temp_cursor_loc = Vector(context.scene.cursor.location)
temp_pivot = context.scene.tool_settings.transform_pivot_point
context.scene.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
bpy.ops.transform.resize(value = (scale, scale, scale))
context.scene.cursor.location = temp_cursor_loc
context.scene.tool_settings.transform_pivot_point = temp_pivot
bpy.ops.object.mode_set(mode='EDIT')
return {'FINISHED'}
# メニューを構築する関数
def menu_fn(self, context):
self.layout.separator()
self.layout.operator(SCALING_OT_selected_objects_by_vert_location.bl_idname)
self.layout.operator(SCALING_OT_scaling_by_two_selected_verts_location.bl_idname)
classes = [
SCALING_OT_selected_objects_by_vert_location,
SCALING_OT_scaling_by_two_selected_verts_location
]
def register():
for c in classes:
bpy.utils.register_class(c)
bpy.types.VIEW3D_MT_edit_mesh.append(menu_fn)
def unregister():
for c in classes:
bpy.utils.unregister_class(c)
bpy.types.VIEW3D_MT_edit_mesh.append(menu_fn)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment