[Script] Make Particle Objects Real

Recently I tried to make particle objects real in the new Blender particle system but couldn’t. It doesn’t seem to be supported yet, so until it is, I made a little Python script to do just that.

(EDIT: Just to clarify: There’s a “Convert” button in the modifier tab for each particle system, which works for converting hair, for example. But it doesn’t work for duplicated objects, i.e. when visualization type is “Object” or “Group”.)

EDIT: It is now fixed in svn, and there’s also CTRL+SHIFT+A which already works, see my post further down.

The script converts duplicated particle objects of particle systems which visualization type is set to “Object”, to real objects. Those converted objects are either linked duplicates of the original object, or they get their own data, as user choice. I also wanted to support the visualization type “Group”, but access to the grouped particle objects doesn’t seem to be supported yet by Blender Python.

The script looks for particle systems on the active object only. After the operation the converted objects are selected and also part of a group for easy access.

Here’s the script. Put it in your Blender scripts or custom scripts folder and access it from the scripts window under “Object” or from the Object/Scripts menu entry in the 3D view menu header, menu entry “Make Particle Objects Real”.

[EDIT] Version 0.2
Made script work also for 3D Text and Surface objects, prevented crash with Empty objects.

Limitations:

  1. Right now only the first particle system gets operated on. Might be due to a bug in the Python API which I’ll be investigating and reporting if needed.
    [EDIT] Might be my mistake. I found that for baked particle systems it works fine, so it seems that’s the solution.

  2. Surface objects get duplicated as Curve objects, I found no way around that. Any modifiers on the original object therefore can’t be copied to the new duplicated objects, because their type doesn’t match.

object-make-partobs-real.py version 0.2

#!BPY
"""
Name: 'Make Particle Objects Real'
Blender: 247svn
Group: 'Object'
Tooltip: 'Convert particle objects to real objects'
"""
__author__= "Sanne"
__url__= ["blenderartists.org"]
__version__= "0.2"

__bpydoc__= """
"""

# --------------------------------------------------------------------------
# Make Particle Objects Real v0.2 by Sanne
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

import Blender

def copyObject(ob, data, scn):
    if hasattr(data, "copy"):
        newob = scn.objects.new(data.copy())
    else:
        # text data doesn't have copy() method
        if type(data) == Blender.Types.Text3dType:
            txt = Blender.Text3d.New()
            txt.setText(data.getText())
            newob = scn.objects.new(txt)
        else:
            newob = 0
    return newob

def makereal(ob, parts, scn, makelinks):
    """ Make particle objects real """
    
    for part in parts:
        if part.type != Blender.Particle.TYPE.EMITTER:
            continue
        if part.drawAs == Blender.Particle.DRAWAS.OBJECT:
            dupob = part.duplicateObject
            if dupob.type == "Empty":
                Blender.Draw.PupMenu("Unsupported object type %t | Can't convert Empty objects.")
                print "No or wrong selection
Can't convert Empty objects."
                return
            elif dupob.type == "Surf":
                Blender.Draw.PupMenu("Attention! %t | Surface object will be duplicated as curve objects. Modifiers can't be copied.")
                print "Attention
Surface object will be duplicated as curve objects.
Modifiers can't be copied."
    
            dupdata = dupob.getData(mesh=True)
            
            # get location, rotation and sizes of all particle objects
            plocs = part.getLoc()
            prots = part.getRot()
            psizes = part.getSize()
            
            grp = Blender.Group.New()
            
            # using part.amount sometimes gives list index out of range error
            # BUG?: all part.getLoc() except from the first particle system are empty,
            # so for now only objects of the first system are getting duplicated by the script
            numparts = len(plocs) 
            for i in range(numparts):
                if makelinks:
                    newob = scn.objects.new(dupdata)
                else:
                    newob = copyObject(dupob, dupdata, scn)
                
                if newob:
                    newob.loc = [x + y for x, y in zip(plocs[i], dupob.loc)]
                    newob.size = (psizes[i], psizes[i], psizes[i])
                    newob.rot = Blender.Mathutils.Quaternion(prots[i]).toEuler()
                    
                    # Object data of a surface object is curve data, so scn.objects.new() generates
                    # a curve object out of surface object data. A newly made surface object via 
                    # deprecated Blender.Object.New() can't be linked to curve data, getting:
                    # "AttributeError: The 'link' object is incompatible with the base object"
                    # Deaktivating copying modifiers for surface objects (can't be copied to curve duplicates)
                    if dupob.type != "Surf":
                        newob.modifiers = dupob.modifiers
                    
                    grp.objects.link(newob)
                
        elif part.drawAs == Blender.Particle.DRAWAS.GROUP:
            # no access to the group name yet
            pass
    
    ob.sel = False

def main():
    """GUI function"""
    
    scn = Blender.Scene.GetCurrent()
    ob = scn.objects.active
    if not ob:
        Blender.Draw.PupMenu("No or wrong selection %t | Please select an object.")
        print "No or wrong selection
Please select an object."
        return
    
    parts = ob.getParticleSystems()
    if len(parts) == 0:
        Blender.Draw.PupMenu("No or wrong selection %t | Active object has no particle system.")
        print "No or wrong selection
Active object has no particle system."
        return
    
    # Can't delete/unlink particle system with Python (yet?)
    #PREF_KEEPPARTSYS = Blender.Draw.Create(1)
    PREF_MAKELINKS = Blender.Draw.Create(1)
    
    # list for popup content    
    block = []
    
    # inputs: title, button, min/max values, tooltip
    #block.append(("Keep Particles ", PREF_KEEPPARTSYS, "Keep particle system"))
    block.append(("Use Linked Data ", PREF_MAKELINKS, "Use linked data for newly generated objects"))
    
    if not Blender.Draw.PupBlock("Make Particle Objects Real", block):
        return
    
    makereal(ob, parts, scn, PREF_MAKELINKS.val)
    Blender.Window.RedrawAll()

# ------------------------
if __name__ == "__main__":
    main()

Hey, thanks, that’s pretty darn useful.

I’m going to have to try that out. Its like a convert to mesh for particles.

Thank you Sanne!

I needed this couple weeks ago while testing one particle system setup. I used the conversion with hair, but it never gave satisfying results. I hope I find some free time to try that setup again.

Thanks all for your comments, I hope it is useful. Tell me if it breaks. :slight_smile:

Hi!

I’ve just tried it! Worked fine and should be very useful. I came here looking for information on generating particles oriented by the face/vertex’s normal, and would have had to think on how to use them afterwards, but your script has solved my problem before it was a problem. Thanks!

Urenze

Nice script, just tested it. Works well.

I just tested other object types (not meshes) as particle objects, and it works for most of them, but errors out in some cases with a nurbs surface, a text object, or an empty, and sometimes even crashes. Don’t use those objects for now, I will look into it, and exclude them if needed.

New version up, see first post.

Sorry to bump this, but, for the record… I just learned that we could make particle objects real with CTRL+SHIFT+A all along, and that my script is in fact unneccessary… except as a learning experience ha ha. This just got committed to svn:

blendix * r16921 /trunk/blender/source/blender/ (3 files in 2 dirs): Fix for bug #17752: the particle modifier convert button didn’t do anything for dupli objects and groups, which could already be converted with ctrl+shift+A, but convert can do it as well.

So, in addition to CTRL+SHIFT+A, the convert button will work in the future. Just so you know. :slight_smile:

I tried the key combination, but couldn’t get it to work in 247.

  • Created system.
  • Baked.
  • CTRL-SHIFT-A.
  • OK? -> Apply deformation.
    -> Apply deformation now only available in modifier buttons.

…and the modifier button does nothing.

Where do I go wrong?

You need to select the object which has the particle system. The particle system needs to be emitter, set amount a bit lower like 10, and visualization set to object with an existing object in the OB field. To see the duplicated objects hit the unborn button in visualization tab. Then hit CTRL+SHIFT+A and you should get “Make dupli objects real” popup.

I just tested it with 2.47 and it works as expected.

Ah ok, my setup was missing an object to be instanced, since I needed only one vertex per particle. It worked when I made a one vertex object and applied it to the system, thanks!

You’re welcome, glad you got it working. :slight_smile:

such a useful script