Create a Blender Add-on for your Simplygon pipeline

Written by Jesper Tingvall, Product Expert, Simplygon

Disclaimer: The code in this post is written using version 9.1.36100 of Simplygon and Blender 2.93.5. If you encounter this post at a later stage, some of the API calls might have changed. However, the core concepts should still remain valid.

Introduction

In this post we will take the script created in A simple reduction script in Blender and turn it into a simple Blender Add-on with a basic user interface. That allows us to easily share it and makes it easy to use for non-programmers.

Blender with reduce and export UI

Prerequisites

This example will use the Simplygon integration in Blender, but the same concepts can be applied to all other integrations of the Simplygon API.

Solution

The solution is to create a Python script which adds a new operator to Blender - reduce and export.

Reduce mesh

The reduction part of the script is straight from A simple reduction script in Blender. It reduces the selected object to specified triangle ratio.

def reduce_selection(self, sg, ratio):
    file_path = 'c:/Temp/_intermediate.glb'
    bpy.ops.export_scene.gltf(filepath = file_path, use_selection=True)
    pipeline = sg.CreateReductionPipeline()
    pipeline.GetReductionSettings().SetReductionTargetTriangleRatio(ratio)
    pipeline.RunSceneFromFile(file_path, file_path, Simplygon.EPipelineRunMode_RunInThisProcess) 
    bpy.ops.import_scene.gltf(filepath=file_path)
    os.remove(file_path)

Export from Blender

After reducing it is time to export our mesh. This will be done via Blenders export_scene function. Export settings depends on which engine that is targeted.

def export_to_path(self, export_path):
    # Export result from Blender. Settings for Unity.
    bpy.ops.export_scene.fbx(filepath=export_path, check_existing=False, 
        use_selection=True,
        object_types={'ARMATURE', 'EMPTY', 'MESH', 'OTHER'}, 
        apply_unit_scale=True, apply_scale_options='FBX_SCALE_ALL',
        path_mode='COPY', embed_textures=False, axis_forward='-Y', axis_up='Z')

    # Clean up optimized objects from Blender
    bpy.ops.object.delete(use_global=False, confirm=False)

Operator

We can capsulate the reduction and export function into a Blender operator. That allows us to showcase a popup box where the user can specify settings. In our example we just have two; export path and how much it should be reduced.

User interface for reduce and export operation

The execute method contains the code which does the processing.

class ReduceAndExport(bpy.types.Operator):
    """Simplygon reduce and export selected objects as fbx"""
    bl_idname = "object.reduce_and_export"
    bl_label = "Reduce and export"
    bl_options = {'REGISTER'}

    reduction: bpy.props.FloatProperty(default=50, max=100, min=0,subtype='PERCENTAGE')
    path: bpy.props.StringProperty(default="C:\\Temp\\Exported.fbx")

    @classmethod
    def poll(cls, context):
        return True

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        row = self.layout
        row.label(text="Simplygon reduce selected meshes and export.")
        row.prop(self, "path", text="Export path")
        row.prop(self, "reduction", text="Reduction")


    def execute(self, context):
        reduce = self.reduction/100
        self.report({'INFO'}, 'Reduction of %f' % reduce)
        sg = simplygon_loader.init_simplygon()
        self.reduce_selection(sg, reduce)
        self.export_to_path(self.path)
        sg = None
        return {'FINISHED'}

We also need a function to show the operator popup window.

def show_reduce_and_export_popup(self, context):
    self.layout.operator(ReduceAndExport.bl_idname)

Add-on

Make the script easy to share we are going to package our script as a Blender Add-on. First we need to add meta information.

bl_info = {
    "name": "Simplygon reduce and export",
    "description": "Simplygon reduce and export selected objects as fbx.",
    "version": (1, 0),
    "location": "View3D > Object",
    "blender": (2, 93, 0),
    "category": "Import-Export",
}

We also need to register, and unregister, our new operation as well as adding it to the Object menu.

def register():
    bpy.utils.register_class(ReduceAndExport)
    bpy.types.VIEW3D_MT_object.append(show_reduce_and_export_popup)

def unregister():
    bpy.utils.unregister_class(ReduceAndExport)
    bpy.types.VIEW3D_MT_object.remove(show_reduce_and_export_popup)

After that been added the add-on can be installed as a Blender Add-on.

Blender Add-on menu

Result

The result is a Blender add-on running a simple mesh reduction. The functionality is accessible via Blenders user interface and it can easily be shared around and installed.

The script could be very easy extended with more options and stop conditions. It would also be possible to change the pipeline into something else, for example remeshing.

Complete script

The resulting script can be found below.

# Copyright (c) Microsoft Corporation. 
# Licensed under the MIT license. 

bl_info = {
    "name": "Simplygon reduce and export",
    "description": "Simplygon reduce and export selected objects as fbx.",
    "version": (1, 0),
    "location": "View3D > Object",
    "blender": (2, 93, 0),
    "category": "Import-Export",
}
 
import os
import bpy
from simplygon import simplygon_loader
from simplygon import Simplygon
    
class ReduceAndExport(bpy.types.Operator):
    """Simplygon reduce and export selected objects as fbx"""
    bl_idname = "object.reduce_and_export"
    bl_label = "Reduce and export"
    bl_options = {'REGISTER'}

    reduction: bpy.props.FloatProperty(default=50, max=100, min=0,subtype='PERCENTAGE')
    path: bpy.props.StringProperty(default="C:\\Temp\\Exported.fbx")

    @classmethod
    def poll(cls, context):
        return True

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        row = self.layout
        row.label(text="Simplygon reduce selected meshes and export.")
        row.prop(self, "path", text="Export path")
        row.prop(self, "reduction", text="Reduction")


    def execute(self, context):
        reduce = self.reduction/100
        self.report({'INFO'}, 'Reduction of %f' % reduce)
        sg = simplygon_loader.init_simplygon()
        self.reduce_selection(sg, reduce)
        self.export_to_path(self.path)
        sg = None
        return {'FINISHED'}
    
    def reduce_selection(self, sg, ratio):
        file_path = 'c:/Temp/_intermediate.glb'
        bpy.ops.export_scene.gltf(filepath = file_path, use_selection=True)
        pipeline = sg.CreateReductionPipeline()
        pipeline.GetReductionSettings().SetReductionTargetTriangleRatio(ratio)
        pipeline.RunSceneFromFile(file_path, file_path, Simplygon.EPipelineRunMode_RunInThisProcess) 
        bpy.ops.import_scene.gltf(filepath=file_path)
        os.remove(file_path)
    
    def export_to_path(self, export_path):
        # Export result from Blender. Settings for Unity.
        bpy.ops.export_scene.fbx(filepath=export_path, check_existing=False, 
            use_selection=True,
            object_types={'ARMATURE', 'EMPTY', 'MESH', 'OTHER'}, 
            apply_unit_scale=True, apply_scale_options='FBX_SCALE_ALL',
            path_mode='COPY', embed_textures=False, axis_forward='-Y', axis_up='Z')

        # Clean up optimized objects from Blender
        bpy.ops.object.delete(use_global=False, confirm=False)

def show_reduce_and_export_popup(self, context):
    self.layout.operator(ReduceAndExport.bl_idname)

def register():
    bpy.utils.register_class(ReduceAndExport)
    bpy.types.VIEW3D_MT_object.append(show_reduce_and_export_popup)  # Adds the new operator to an existing menu.

def unregister():
    bpy.utils.unregister_class(ReduceAndExport)
    bpy.types.VIEW3D_MT_object.remove(show_reduce_and_export_popup)

if __name__ == "__main__":
    register()
⇐ Back to all posts

Request 30-days free evaluation license

*
*
*
*
Industry
*

Request 30-days free evaluation license

*
*
*
*
Industry
*