Last active
February 7, 2020 06:08
-
-
Save tomol/418b1bbbdaf2f5b4d72f336c1a41d260 to your computer and use it in GitHub Desktop.
頂点を1点または2点選択して,その頂点の座標が指定した値の位置になるよう,選択したオブジェクト全てを拡縮する(実行は編集モードのメッシュから) 特定の箇所の大きさを基準にしてスケールを合わせたいときに
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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