0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Blenderの辺を目的のワールド位置までスライドさせる係数計算アドオン

Last updated at Posted at 2024-12-29

概要

Blenderの任意の位置に(UVを崩さずに)辺をスライドさせたい!という場合、手段がありません。
Slide.png

Gキーを2回押すとUVの状態を崩さずに辺をスライドさせられますが、数値指定できるのは「係数」とかいう謎の値……。

スクリーンショット 2024-12-29 051815.png

この「係数」を計算するアドオンを作りました。

対応

Blenderアドオンをインストールしてください。

slide_coefficient_calculator.cs
bl_info = {
    "name": "Slide Coefficient Calculator",
    "blender": (2, 82, 0),  # 対応するBlenderのバージョン
    "category": "Object",
    "author": "Your Name",
    "version": (1, 0),
    "description": "Calculates slide coefficient based on selected edge positions.",
    "warning": "",
    "doc_url": "",
    "tracker_url": "",
    "support": "COMMUNITY",
    "location": "View3D > Tool Shelf",
    "warning": "",
    "category": "Object",
}

import bpy

# 選択した辺の座標を取得する関数
def get_selected_edge_coordinates(axis):
    obj = bpy.context.object

    # オブジェクトが選択されているか確認
    if obj and obj.type == 'MESH':
        # メッシュデータの更新
        obj.update_from_editmode()
        
        # 選択されたエッジを取得
        edges = [e for e in obj.data.edges if e.select]
        if edges:
            # エッジの頂点座標をワールド座標に変換
            edge_coords = []
            for edge in edges:
                v1_co = obj.matrix_world @ obj.data.vertices[edge.vertices[0]].co
                v2_co = obj.matrix_world @ obj.data.vertices[edge.vertices[1]].co
                edge_coords.append((v1_co, v2_co))

            # ワールド座標の指定軸だけを抽出
            if axis == 'X':
                return [coord.x for edge in edge_coords for coord in edge]
            elif axis == 'Y':
                return [coord.y for edge in edge_coords for coord in edge]
            elif axis == 'Z':
                return [coord.z for edge in edge_coords for coord in edge]
    return None

# オペレーターを作成
class SLIDE_OT_CalculateSlideCoefficient(bpy.types.Operator):
    bl_idname = "object.calculate_slide_coefficient"
    bl_label = "Calculate Slide Coefficient"

    def execute(self, context):
        target_edge_position = context.scene.target_edge_position
        end_edge_position = context.scene.end_edge_position
        world_destination_position = context.scene.world_destination_position

        print(f"Target Edge Position: {target_edge_position}, End Edge Position: {end_edge_position}, World Destination Position: {world_destination_position}")

        if end_edge_position == target_edge_position:
            self.report({'ERROR'}, "Target Edge and End Edge cannot have the same position.")
            return {'CANCELLED'}

        try:
            coefficient = (world_destination_position - target_edge_position) / (end_edge_position - target_edge_position)
            self.report({'INFO'}, f"Calculated Coefficient: {coefficient:.9f}")
        except ZeroDivisionError:
            self.report({'ERROR'}, "Division by zero error.")
            return {'CANCELLED'}

        return {'FINISHED'}

class SLIDE_OT_SetEdgePosition(bpy.types.Operator):
    bl_idname = "object.set_target_edge_position"
    bl_label = "Set Target Edge Position"

    def execute(self, context):
        axis = context.scene.selected_axis
        selected_edge_coords = get_selected_edge_coordinates(axis)
        if selected_edge_coords is not None and selected_edge_coords:
            context.scene.target_edge_position = selected_edge_coords[0]
        else:
            self.report({'ERROR'}, "No edge selected.")
            return {'CANCELLED'}
        return {'FINISHED'}

class SLIDE_OT_SetEndEdgePosition(bpy.types.Operator):
    bl_idname = "object.set_end_edge_position"
    bl_label = "Set End Edge Position"

    def execute(self, context):
        axis = context.scene.selected_axis
        selected_edge_coords = get_selected_edge_coordinates(axis)
        if selected_edge_coords is not None and selected_edge_coords:
            context.scene.end_edge_position = selected_edge_coords[1]
        else:
            self.report({'ERROR'}, "No edge selected.")
            return {'CANCELLED'}
        return {'FINISHED'}

class SLIDE_OT_SetWorldDestinationPosition(bpy.types.Operator):
    bl_idname = "object.set_world_destination_position"
    bl_label = "Set World Destination Position"

    def execute(self, context):
        axis = context.scene.selected_axis
        selected_edge_coords = get_selected_edge_coordinates(axis)
        if selected_edge_coords is not None and selected_edge_coords:
            context.scene.world_destination_position = selected_edge_coords[0]
        else:
            self.report({'ERROR'}, "No edge selected.")
            return {'CANCELLED'}
        return {'FINISHED'}

class SLIDE_PT_CalculateSlidePanel(bpy.types.Panel):
    bl_label = "Slide Coefficient Calculator"
    bl_idname = "OBJECT_PT_slide_coefficient"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Tool'

    def draw(self, context):
        layout = self.layout

        layout.label(text="Select Axis:")
        row = layout.row(align=True)
        row.prop(context.scene, "selected_axis", expand=True)

        row = layout.row(align=True)
        row.prop(context.scene, "target_edge_position")
        row.operator("object.set_target_edge_position", text="Set")

        row = layout.row(align=True)
        row.prop(context.scene, "end_edge_position")
        row.operator("object.set_end_edge_position", text="Set")

        row = layout.row(align=True)
        row.prop(context.scene, "world_destination_position")
        row.operator("object.set_world_destination_position", text="Set")

        layout.operator("object.calculate_slide_coefficient")

def register():
    bpy.utils.register_class(SLIDE_OT_CalculateSlideCoefficient)
    bpy.utils.register_class(SLIDE_OT_SetEdgePosition)
    bpy.utils.register_class(SLIDE_OT_SetEndEdgePosition)
    bpy.utils.register_class(SLIDE_OT_SetWorldDestinationPosition)
    bpy.utils.register_class(SLIDE_PT_CalculateSlidePanel)
    
    bpy.types.Scene.selected_axis = bpy.props.EnumProperty(
        name="Axis",
        description="Choose the axis to use for edge coordinates",
        items=[('X', 'X Axis', 'Use the X axis'),
               ('Y', 'Y Axis', 'Use the Y axis'),
               ('Z', 'Z Axis', 'Use the Z axis')],
        default='X'
    )
    bpy.types.Scene.target_edge_position = bpy.props.FloatProperty(name="Target Edge Position", default=0.0)
    bpy.types.Scene.end_edge_position = bpy.props.FloatProperty(name="End Edge Position", default=0.0)
    bpy.types.Scene.world_destination_position = bpy.props.FloatProperty(name="World Destination Position", default=0.0)

def unregister():
    bpy.utils.unregister_class(SLIDE_OT_CalculateSlideCoefficient)
    bpy.utils.unregister_class(SLIDE_OT_SetEdgePosition)
    bpy.utils.unregister_class(SLIDE_OT_SetEndEdgePosition)
    bpy.utils.unregister_class(SLIDE_OT_SetWorldDestinationPosition)
    bpy.utils.unregister_class(SLIDE_PT_CalculateSlidePanel)
    
    del bpy.types.Scene.selected_axis
    del bpy.types.Scene.target_edge_position
    del bpy.types.Scene.end_edge_position
    del bpy.types.Scene.world_destination_position

if __name__ == "__main__":
    register()

インストールするとツールタブに新しく「Slide Coefficient Calculator」というウィンドウが表示されます。

image.png

今回はY軸方向にスライドさせたいので「Y軸」トグルボタンを選択します。
そうしたら3つの値を入力します。
・移動させたい辺を選択して「Set」
image.png

・移動先のMaxの行き先の辺を選択して「Set」
image.png

・目的の座標の辺を選択して「Set」(普通にスライドに手入力でもいいです)
image.png

3つの値を入力し終わったら、「Calculate Slide Cofficient」ボタンを押します。
すると、infoログに計算結果が出力されます。

image.png

この値をコピペして、スライド時の「係数」に入力します。
(EndEdgePositionとして選択した辺によっては符号が反転している場合があるので、必要に応じてマイナスをかけてください)

image.png

以上です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?