Add-ons Konversi Obyek di Blender 4.3.0 ke Skrip Python

Rabu, 09 Juli 2025 edit

Berikut ini hasil belajar membuat add-ons untuk Blender 3D. Add-ons ini untuk mengonversi obyek yang sedang aktif di Blender ke kode Python. Mungkin ini memudahkan ketika kita membuat add-ons atau otomatisasi obyek agar dapat bekerja lebih efektif dan efisien.

Untuk menambahkan add-ons ini sila unduh dari sini file phyton atau salin langsung dari kotak kode di bawah, perhatikan letak file hasil unduhan. Kemudian buka Aplikasi Blender (dianjurkan versi 4.3.0 atau lebih tinggi) > klik menu Edit > Preferences > Add-ons, klik tanda di bawah tanda x > Install from disk... Arahkan ke folder hasil unduhan.

Untuk mengaksesnya, buka aplikasi Blender 3D > Export > Object to Python. Silakan simpan file dengan ekstensi dot py. Untuk mencoba sila buka Aktive Work Space bagian Scripting (biasa ada di tab paling kanan) >  klik New dan salin hasil konversi dot py tadi di bagian layar kerja Scripting > klik tombol Run Script atau tekan Alt P.

Jika hasilnya sama persis dengan obyek sebelumnya artinya hasil konversi berhasil.

import bpy
import bmesh
import os
from bpy.types import Operator, Menu
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty
import uuid

bl_info = {
    "name": "Blender Object to Python Converter",
    "author": "Rukim",
    "version": (1, 0, 2),
    "blender": (4, 3, 0),
    "location": "File > Export > Object to Python",
    "description": "Exports the active mesh object to a Python script that recreates the mesh, including transforms and optional UV maps",
    "category": "Export",
    "warning": "Requires Blender 4.3 or higher.",
    "doc_url": "https://www.urip.info/2025/07/konversi-obyek-blender-to-python.html",
}

class OBJECT_OT_export_to_python(Operator, ExportHelper):
    """Export active mesh object to Python script"""
    bl_idname = "export.object_to_python"
    bl_label = "Object to Python"
    bl_options = {'REGISTER', 'UNDO'}

    # File picker properties
    filename_ext = ".py"
    filter_glob: StringProperty(
        default="*.py",
        options={'HIDDEN'},
        maxlen=255,
    )

    # Export options
    include_material: BoolProperty(
        name="Include Material",
        description="Include material properties in the Python script",
        default=True,
    )
    include_uv: BoolProperty(
        name="Include UV Map",
        description="Include UV map data in the Python script",
        default=False,
    )
    use_original_name: BoolProperty(
        name="Use Original Object Name",
        description="Use the original object name instead of a random UUID",
        default=False,
    )

    def execute(self, context):
        try:
            output_path = self.filepath

            # Cek kalau ada objek aktif
            obj = context.active_object
            if not obj or obj.type != 'MESH':
                self.report({'ERROR'}, "No active mesh object selected")
                return {'CANCELLED'}

            # Cek kalau mesh punya data
            mesh = obj.data
            if len(mesh.vertices) == 0:
                self.report({'ERROR'}, "Mesh has no vertices")
                return {'CANCELLED'}

            # Cek kalau path file valid
            if not output_path.endswith('.py'):
                output_path += '.py'
            if not os.path.isdir(os.path.dirname(output_path)):
                self.report({'ERROR'}, "Invalid output directory")
                return {'CANCELLED'}

            # Ambil data mesh
            bm = bmesh.new()
            bm.from_mesh(mesh)
            vertices = [(v.co.x, v.co.y, v.co.z) for v in bm.verts]
            edges = [(e.verts[0].index, e.verts[1].index) for e in bm.edges]
            faces = [[v.index for v in f.verts] for f in bm.faces]

            # Ambil UV map kalau dicentang
            uv_data = None
            if self.include_uv and mesh.uv_layers:
                uv_layer = mesh.uv_layers.active
                if uv_layer:
                    uv_data = []
                    for poly in mesh.polygons:
                        poly_uvs = []
                        for loop_index in poly.loop_indices:
                            uv = mesh.uv_layers.active.data[loop_index].uv
                            poly_uvs.append((uv.x, uv.y))
                        uv_data.append(poly_uvs)

            bm.free()

            # Ambil transformasi
            location = obj.location[:]
            rotation = obj.rotation_euler[:]
            scale = obj.scale[:]

            # Ambil material kalau dicentang
            material_data = None
            if self.include_material and mesh.materials:
                mat = mesh.materials[0]  # Ambil material pertama
                if mat and mat.node_tree and mat.node_tree.nodes.get("Principled BSDF"):
                    bsdf = mat.node_tree.nodes["Principled BSDF"]
                    base_color = bsdf.inputs["Base Color"].default_value[:]
                    alpha = bsdf.inputs["Alpha"].default_value
                    material_data = {
                        'name': mat.name,
                        'base_color': base_color,
                        'alpha': alpha,
                        'blend_method': mat.blend_method
                    }

            # Nama objek
            obj_name = obj.name if self.use_original_name else f"Mesh_{str(uuid.uuid4())[:8]}"

            # Buat kode Python
            code = [
                "import bpy",
                "import bmesh",
                "",
                f"def create_mesh_{obj_name}():",
                f"    # Buat mesh baru",
                f"    mesh = bpy.data.meshes.new('{obj_name}_Mesh')",
                f"    obj = bpy.data.objects.new('{obj_name}', mesh)",
                f"    bpy.context.collection.objects.link(obj)",
                "",
                f"    # Set transformasi",
                f"    obj.location = {location}",
                f"    obj.rotation_euler = {rotation}",
                f"    obj.scale = {scale}",
                "",
                f"    # Setup bmesh",
                f"    bm = bmesh.new()",
                "",
                f"    # Tambah vertices",
            ]
            for i, vert in enumerate(vertices):
                code.append(f"    bm.verts.new({vert})")
            code.append("    bm.verts.ensure_lookup_table()")
            code.append("")

            # Tambah edges
            if edges:
                code.append(f"    # Tambah edges")
                for edge in edges:
                    code.append(f"    bm.edges.new((bm.verts[{edge[0]}], bm.verts[{edge[1]}]))")
                code.append("")

            # Tambah faces
            if faces:
                code.append(f"    # Tambah faces")
                for face in faces:
                    code.append(f"    bm.faces.new([bm.verts[i] for i in {face}])")
                code.append("")

            # Tambah UV map kalau ada
            if uv_data:
                code.append(f"    # Tambah UV map")
                code.append(f"    uv_layer = mesh.uv_layers.new(name='UVMap')")
                for i, poly_uvs in enumerate(uv_data):
                    code.append(f"    for j, uv in enumerate({poly_uvs}):")
                    code.append(f"        uv_layer.data[mesh.polygons[{i}].loop_start + j].uv = uv")
                code.append("")

            code.append(f"    # Update mesh")
            code.append(f"    bm.to_mesh(mesh)")
            code.append(f"    bm.free()")
            code.append("")

            # Tambah material kalau ada
            if material_data:
                code.append(f"    # Tambah material")
                code.append(f"    mat = bpy.data.materials.new(name='{material_data['name']}')")
                code.append(f"    mat.use_nodes = True")
                code.append(f"    nodes = mat.node_tree.nodes")
                code.append(f"    nodes.clear()")
                code.append(f"    bsdf = nodes.new('ShaderNodeBsdfPrincipled')")
                code.append(f"    bsdf.inputs['Base Color'].default_value = {material_data['base_color']}")
                code.append(f"    bsdf.inputs['Alpha'].default_value = {material_data['alpha']}")
                code.append(f"    output = nodes.new('ShaderNodeOutputMaterial')")
                code.append(f"    mat.node_tree.links.new(bsdf.outputs['BSDF'], output.inputs['Surface'])")
                code.append(f"    mat.blend_method = '{material_data['blend_method']}'")
                code.append(f"    mesh.materials.append(mat)")
                code.append("")

            code.append(f"    # Set shade smooth")
            code.append(f"    for f in mesh.polygons:")
            code.append(f"        f.use_smooth = True")
            code.append("")
            code.append(f"if __name__ == '__main__':")
            code.append(f"    create_mesh_{obj_name}()")

            # Tulis ke file
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write('\n'.join(code))

            self.report({'INFO'}, f"Object '{obj.name}' exported to Python script: {output_path}")
            return {'FINISHED'}

        except Exception as e:
            self.report({'ERROR'}, f"Failed to export object: {str(e)}")
            return {'CANCELLED'}

def menu_func_export(self, context):
    self.layout.operator(OBJECT_OT_export_to_python.bl_idname, text="Object to Python")

def register():
    try:
        bpy.utils.register_class(OBJECT_OT_export_to_python)
        bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
    except Exception as e:
        print(f"Failed to register addon: {str(e)}")

def unregister():
    try:
        bpy.utils.unregister_class(OBJECT_OT_export_to_python)
        bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
    except Exception as e:
        print(f"Failed to unregister addon: {str(e)}")

if __name__ == "__main__":
    register()

Gunakan secara bijak, jangan disebarkan untuk komersialisasi.

Bagikan di

Tidak ada komentar:

Posting Komentar

 
Copyright © 2015-2025 Urip dot Info | Disain Template oleh Herdiansyah Dimodivikasi Urip.Info