2
$\begingroup$

I have created a simple addon that creates a series of metaballs. Sometimes when the addon executes, the metaballs are rendered invisible (as only outlines, no surface). Usually the metaballs seem to be created correctly (ie, visible) -- sometimes it can be a little bit hard to reproduce the problem.

When I encounter the problem, I can re-execute the script with the same parameters (click to edit a field and then hit enter) and the metaballs/surface will often then suddenly appear. The inconsistency here makes me wonder if this is really a bug in my script or if it might be a bug in Blender itself.

Any ideas what could be causing the issue?

Edit: bpy.context.scene.update() has been no help.

enter image description here

bl_info = {
    "name": "Metaball Thing",
    "category": "Object",
}

import logging
import random
import math
import mathutils
from mathutils import Vector
import string
import abc
import bpy

log = logging.getLogger(__name__)

class ObjectMetaballThing(bpy.types.Operator):
    """Object Metaball Thing"""
    bl_idname = "object.metaball_thing"
    bl_label = "Metaball Thing"
    bl_options = {'REGISTER', 'UNDO'}

    # ========= Properties =========
    primaryRadius = bpy.props.FloatProperty(name="Primary Radius", default=9, min=0, max=10000)
    seriesRatio = bpy.props.FloatProperty(name="Series Ratio", default=0.333, min=0, max=1)
    scale = bpy.props.FloatProperty(name="Scale", default=1.0, min=0, max=100)
    numBubbles = bpy.props.IntProperty(name="Num Bubbles", default=3, min=1, max=10)
    resFactor = bpy.props.FloatProperty(name="Res Factor", default=0.01, min=0, max=100)


    def execute(self, context):
        # add metaball object
        disambiguator = '-' + ''.join(random.choice(string.ascii_uppercase + string.digits) for c in range(8))
        mball = bpy.data.metaballs.new("SurfaceBall" + disambiguator)
        obj = bpy.data.objects.new("SurfaceBallObject" + disambiguator, mball)
        context.scene.objects.link(obj)

        # resolution is based on radius
        mball.resolution = self.primaryRadius * self.resFactor
        mball.render_resolution = mball.resolution * 0.25

        # create the initial ball
        centerball = mball.elements.new()
        centerball.co = (0, 0, 0)
        centerball.radius = self.primaryRadius

        # build a series of smaller metaelements
        dist = 0
        radius = self.primaryRadius
        postElements = []
        for p in range(self.numBubbles):
            dist += radius * 0.5
            radius *= self.seriesRatio;
            dist += radius * 0.5

            center = Vector([0, 0, 1])
            center *= dist * self.scale

            element = mball.elements.new()
            element.co = center
            element.radius = radius

            log.warning("element at " + str(center.z) + ", radius " + str(radius))
            postElements.append(element)


        obj.select = True
        context.scene.objects.active = obj

        return {'FINISHED'}


def menu_func(self, context):
    self.layout.operator(ObjectMetaballThing.bl_idname)

# store keymaps here to access after registration
addon_keymaps = []


def register():
    bpy.utils.register_class(ObjectMetaballThing)
    bpy.types.VIEW3D_MT_object.append(menu_func)

    # handle the keymap
    wm = bpy.context.window_manager
    # Note that in background mode (no GUI available), keyconfigs are not available either, so we have to check this
    # to avoid nasty errors in background case.
    kc = wm.keyconfigs.addon
    if kc:
        km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
        kmi = km.keymap_items.new(ObjectMetaballThing.bl_idname, 'SPACE', 'PRESS', ctrl=True, shift=True)

        addon_keymaps.append((km, kmi))


def unregister():
    # Note: when unregistering, it's usually good practice to do it in reverse order you registered.
    # Can avoid strange issues like keymap still referring to operators already unregistered...
    # handle the keymap
    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()

    bpy.utils.unregister_class(ObjectMetaballThing)
    bpy.types.VIEW3D_MT_object.remove(menu_func)


if __name__ == "__main__":
    register()
$\endgroup$

1 Answer 1

1
$\begingroup$

Try to bpy.context.scene.update()

Update data tagged to be updated from previous access to data or operators

$\endgroup$
1
  • $\begingroup$ That's a good idea, but I tried it -- adding the update() call right before execute() returns -- and I was still able to reproduce the problem after that. $\endgroup$ Commented May 17, 2019 at 16:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .