1
$\begingroup$

I am using only objects from photogrammetry and the scale is far from ok when I import them. I would like to be able to scale it automatically on selection if its mesh volume is lower than a precise value.

I tried to do this like below :

def setup_handler():
   for h in [x for x in bpy.app.handlers.scene_update_pre]:
       if h == scale_function:
           bpy.app.handlers.scene_update_pre.remove( scale_function )

   bpy.app.handlers.scene_update_pre.append( scale_function )

def scale_function():
    if bpy.types.Object.test != scn.objects.active.name :
        bpy.types.Object.test = scn.objects.active.name
        if bpy.context.mode == 'OBJECT':
            volume = volumeDeterminationFunction()
            if volume <= 1 :
                scale=3
                bpy.ops.transform.resize(value=(scale,) * 3, mirror=False, proportional='DISABLED', snap=False, texture_space=False)

I call setup_handler function in a draw function class, but it doesn't work, maybe I should call the function elsewhere ? if you have any idea ? Thanks

$\endgroup$
  • $\begingroup$ You can use handlers to fire your function. See docs.blender.org/api/2.79/bpy.app.handlers.html (not the same in 2.8 afaik). Usage here in this answer (scene handler part): blender.stackexchange.com/questions/143273/… $\endgroup$ – lemon Jul 23 '19 at 10:48
  • $\begingroup$ What importer? does it have a scale property. What is possibly easiest here is to add your own operator that imports and post processes. $\endgroup$ – batFINGER Jul 23 '19 at 13:02
  • $\begingroup$ I mean, when I import an Obj object, I would like to scale it on the same time if it's too small, but I am looking for solutions. I really don't know how to create an operator to do those two actions but it would be perfect, I am a novice in blender's code.. If you could show me an example or something I would be grateful ! $\endgroup$ – art2611 Jul 23 '19 at 13:11
  • $\begingroup$ Do it in the register function of your addon. See blender.stackexchange.com/questions/9357/… $\endgroup$ – lemon Jul 23 '19 at 14:16
  • $\begingroup$ I just tried this line in the register and unregister function : bpy.app.handlers.scene_update_pre.append(setup_handler) Still not working.. I don't understand what I am doing wrong $\endgroup$ – art2611 Jul 23 '19 at 14:39
1
$\begingroup$

Use the import operator in another.

As commented, rather than importing, then waiting for object selection to rescale, recommend rescaling on import.

Here is script that uses the template Text Editor > Templates > Python > Operator Import as a starting point.

Note I am using 2.8. If you are using 2.7x or before, adjust to reflect that version accordingly. Most notably annotations. where the annotation foo : BarProperty() needs to be replaced with assignment foo = BarProperty()

Assumes you are doing little else than choosing a filename of obj, and when selected passes it to the import operator.

After import the new objects are selected, and in the context.selected_objects list.

Following test script prints out name and a volume based on object dimensions.

import bpy


def read_some_data(context, filepath):

    bpy.ops.import_scene.obj(filepath=filepath)
    for o in context.selected_objects:

        dim = o.dimensions
        vol = dim.x * dim.y * dim.z
        print(o.name, vol)
        # scale based on volume
        if vol < 1:
            o.scale *= 2

    return {'FINISHED'}


from bpy_extras.io_utils import ImportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator


class ImportSomeData(Operator, ImportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "import_test.some_data" 
    bl_label = "Import Some Data"

    filename_ext = ".obj"

    filter_glob: StringProperty(
        default="*.obj",
        options={'HIDDEN'},
        maxlen=255,  # Max internal buffer length, longer would be clamped.
    )

    def execute(self, context):
        return read_some_data(context, self.filepath)


# Only needed if you want to add into a dynamic menu
def menu_func_import(self, context):
    self.layout.operator(ImportSomeData.bl_idname, text="Text Import Operator")


def register():
    bpy.utils.register_class(ImportSomeData)
    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)


def unregister():
    bpy.utils.unregister_class(ImportSomeData)
    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.import_test.some_data('INVOKE_DEFAULT')
|improve this answer|||||
$\endgroup$
  • $\begingroup$ It really the perfect solution here, thank you a lot for the time you took to answer me. $\endgroup$ – art2611 Jul 23 '19 at 15:00
  • $\begingroup$ However, just a little precision if possible please, how I save the operator Import when the entire code is replaced by yours ? Run script is not working :/ $\endgroup$ – art2611 Jul 23 '19 at 15:45
  • $\begingroup$ Example written for 2.8. If you are using version 2.7x or prior will need to amend script accordingly. See edit. Basically get the template from your version, glob for "obj" an replace read_some_data $\endgroup$ – batFINGER Jul 24 '19 at 10:39
  • $\begingroup$ Ok I better understand know, I am in version 2.79 ! Thanks for your explanations, my problem is now when I want to save it, I can only "save as' and not 'save' so the file is still the original one when I launch Blender. I am sorry but I don't know how to run this new file instead of the existing one.. $\endgroup$ – art2611 Jul 24 '19 at 14:52
  • $\begingroup$ Totally confused by this comment, save what? $\endgroup$ – batFINGER Jul 24 '19 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.