Changing An Existing Mesh To A Single Vertex Mesh (2.56)

Hi All,

I am looking for a way to change an existing mesh into a single vertex mesh. The goal here is to reduce memory usage when my script discards a mesh that is no longer needed. It seems that 2.5 API has the same limitation as 2.49. You can not actually delete a mesh from memory. So my goal is to at least reduce the vertex count of a discarded mesh to 1 as a way to hold off memory overflow and eventual crashes.

Here is my code so far:


import bpy

# Get the default cube mesh.
ob = bpy.data.objects["Cube"]
me = ob.data

# Try to make the existing mesh a single vertex mesh.
me.name = "zz_garbage"
me.from_pydata([(0,0,0)],[(0)],[(0)])
me.update(True)

This actually crashes Blender.

I know you can remove vertices from a mesh via editing in the GUI, but I am wondering how do I do this via code?

a simple workaround with operators would be to scale to 0 and remove doubles…

why not simply remove it at least !

it wont be seen by blender but don’t know if this would reduce memory for it !

ob = bpy.data.objects[‘Cube’]
bpy.context.scene.objects.unlink(ob)
bpy.data.objects.remove(ob)

or
bpy.ops.mesh.remove_doubles(limit=0.1)
and set limit very large

happy 2.5

Well, I don’t want to remove the object from the scene. I just want to delete the mesh, which we can not do in the Blender API. Assume that the object will have a NEW mesh linked to it. So my thought was to at least convert the unwanted old mesh to it’s smallest possible memory footprint.

Also, I don’t really like using bpy.ops. For instance, your piece of code.


bpy.ops.mesh.remove_doubles(limit=0.1)

How do I know what mesh this line it effecting? When I run it I get ‘context is incorrect’.

Ideally we need something like this in the API.


bpy.data.meshes[myMesh].remove_doubles(limit=0.1)

Where myMesh, is a valid mesh.

I do like the idea of scale to 0 and then remove doubles. Any idea on how to get it to operate on a local variable?

operators works on the active or last selected object !

bpy.ops.object.select_all(action=‘DESELECT’)
bpy.ops.object.select_name(name=“Sun1”,extend=True)

happy 2.5

well this is some extreme test as will link all meshes data to a single point, and remove the old ones, but i don’t really see the memory going down…


import bpy

me = bpy.data.meshes.new('point')
me.from_pydata([(0,0,0)],[],[])
me.update()

for a in bpy.data.objects:
    if a.type == 'MESH' : a.data = me
for b in bpy.data.meshes:
    if not b.name.startswith('point') : bpy.data.meshes.remove(b)

cjeck file

cloe and re open the file and see if any memory change

where do you check to see this memory on top header on vista ?

happy 2.5

Here is a closer attempt, but I still get that ‘context is incorrect’ error when I try to remove doubles.


import bpy

def returnTorusMesh (r1,r2,s1,s2):
    bpy.ops.mesh.primitive_torus_add(major_radius=r1, minor_radius=r2, major_segments=s1, minor_segments=s2, use_abso=False, abso_major_rad=1, abso_minor_rad=0.5, view_align=False, location=(0, 0, 0), rotation=(0, -0, 0))
    ob = bpy.context.active_object
    me = ob.data
    bpy.ops.object.delete()
    return me


bpy.ops.object.select_all(action='DESELECT')            # Deselect all other objects.
bpy.ops.object.select_name(name="Cube",extend=True )    # Select the object.
bpy.ops.mesh.remove_doubles(limit=10000)                # Try to make the existing mesh a single vertex mesh.


ob = bpy.data.objects["Cube"]       # Fetch the object.
ob.data.name = "zz_garbage"         # Rename the remove_doubles mesh to garbage, it is being discarded.
me = returnTorusMesh(2,0.3,16,16)   # Get a new mesh to link to this object.
me.name = "me_torus"                # Name this mesh.
ob.data = me                        # Assign the new mesh to the old Cube object.

this works fine


 
 
import bpy, math
 
 
def returnTorusMesh (r1,r2,s1,s2):
    bpy.ops.mesh.primitive_torus_add(major_radius=r1, minor_radius=r2, major_segments=s1, minor_segments=s2, use_abso=False, abso_major_rad=1, abso_minor_rad=0.5, view_align=False, location=(0, 0, 0), rotation=(0, -0, 0))
    ob = bpy.context.active_object
    me = ob.data
    bpy.ops.object.delete()
    return me
 
bpy.ops.object.select_all(action='DESELECT')            # Deselect all other objects.
bpy.ops.object.select_name(name="Cube",extend=True )    # Select the object.
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.remove_doubles(limit=10000)                # Try to make the existing mesh a single vertex mesh.
bpy.ops.object.editmode_toggle()
ob = bpy.data.objects["Cube"]       # Fetch the object.
ob.data.name = "zz_garbage"         # Rename the remove_doubles mesh to garbage, it is being discarded.
me = returnTorusMesh(2,0.3,16,16)   # Get a new mesh to link to this object.
me.name = "me_torus"                # Name this mesh.
ob.data = me                        # Assign the new mesh to the old C
 
 
 

now i got 2 others things but not certain when to use or not and why ?


 
Remove data Block1
import bpy
class RemoveDatablocksOperator(bpy.types.Operator):
bl_idname = 'world.remove_redundant_datablocks'
bl_label = 'Remove Redundant Datablocks'
@classmethod
def poll(cls, context):
return True
def execute(self, context):
data_blocks = ['actions',
'armatures',
'brushes',
'cameras',
'curves',
'fonts',
'groups',
'images',
'lamps',
'lattices',
'materials',
'meshes',
'metaballs',
'objects',
'particles',
'scenes',
'texts',
'textures',
'worlds']
for item in data_blocks:
db = getattr(bpy.data, item)
for i in db:
if i.users <= 0:
db.remove(i)
return {'FINISHED'}
 
if __name__ == '__main__':
bpy.ops.world.remove_redundant_datablocks()
 
 
and this one
 
mod = bpy.data.objects['Cube'].modifiers.new(name='decimate', type='DECIMATE') 
mod.ratio = 0.5 
mod.realtime = True
 
 

happy 2.5

you need to enter edit mode and then return… something like this will work


import bpy
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.remove_doubles(limit=10000)
bpy.ops.object.mode_set(mode='OBJECT')

bpy.ops.object.mode_set() will set object mode
bpy.ops.object.editmode_toggle() will toggle modes
print (bpy.context.mode) may help

you will usually select in object mode and run the operators in edit mode

@liero: Thank you for the explanation on work flow with bpy.ops. That does make things a bit easier.

Your code worked.

Here is the final code with it working as I intended:


import bpy

def returnTorusMesh (r1,r2,s1,s2):
    bpy.ops.mesh.primitive_torus_add(major_radius=r1, minor_radius=r2, major_segments=s1, minor_segments=s2, use_abso=False, abso_major_rad=1, abso_minor_rad=0.5, view_align=False, location=(0, 0, 0), rotation=(0, -0, 0))
    ob = bpy.context.active_object
    me = ob.data
    bpy.ops.object.delete()
    return me


bpy.ops.object.select_all(action='DESELECT')            # Deselect all other objects.
bpy.ops.object.select_name(name="Cube",extend=True )    # Select the object.
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.remove_doubles(limit=10000)                # Try to make the existing mesh a single vertex mesh.
bpy.ops.object.mode_set(mode='OBJECT')


ob = bpy.data.objects["Cube"]       # Fetch the object.
ob.data.name = "zz_garbage"         # Rename the mesh to garbage, it is being discarded.
me = returnTorusMesh(2,0.3,16,16)   # Get a new mesh to link to this object.
me.name = "me_torus"                # Name this mesh.
ob.data = me                        # Assign the new mesh to the old Cube object.

This code takes an object and converts it’s existing mesh to a single point, then adds a new mesh and links that new mesh back to the object. So even though I have discarded a mesh in memory, I have taken all the steps I could to make that discarded mesh have the lowest memory footprint possible.

As you might have guessed, I have a new AddOn in the works that is really going to waste memory.:wink:

Atom, this solution have solved the memory problem?

Ciao
VB

@ValterVB: It does not fix the problem but it does appear to slow the problem down.

I conducted a test using my Parametric Torus AddOn.

Here was the test:
Set an animated torus in motion and make the timeline loop.
This begins to waste memory.
Observe the memory usage at the top of the screen.

When I ran the code without the remove doubles code after 10 timeline loops my scene had used up to 70MB.
When I ran the code with the remove doubles code after 10 timeline loops my scene had use 48Mb.

It only delays the crash the looms on the horizon. But that might get you an extra 100-500 frames rendered…

You can gain a lot of frame if you uncheck Global undo and keep the steps of undo =0

what the command for this
i tried it yesterday and it did not work

so can you regive it again

thanks

Here are the solutions I came up with.


def fetchIfObject (passedName= ""):
    try:
        result = bpy.data.objects[passedName]
    except:
        result = None
    return result

def reduceMeshToOneVertex(passedObjectName):
    ob = fetchIfObject(passedObjectName)
    if ob != None:
        #selected_objects = bpy.context.selected_objects
        bpy.ops.object.select_all(action='DESELECT')            # Deselect all other objects.
        bpy.ops.object.select_name(name=passedObjectName,extend=True )    # Select the object.
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.remove_doubles(limit=65534)                # Try to make the existing mesh a single vertex mesh.
        bpy.ops.object.mode_set(mode='OBJECT')
        #bpy.context.selected_objects = selected_objects
    else:
        pass

But my real goal was to simply remove the mesh from memory. And here is that code.(Thanks to TrumanBlending)


def removeMeshFromMemory (passedMeshName):
    mesh = bpy.data.meshes[passedMeshName]
    mesh.user_clear()
    bpy.data.meshes.remove(mesh) 
    return 

nice to kow it can be remove from memory!

but what is the command for histoty off

uncheck Global undo ?

thanks

Very interesting discussion, and thanks Atom for the code. However, for some reason removeMeshFromMemory doesn’t seem to be freeing up all the memory associated with a mesh.

Here was my test:

For the simple starting scene (cube, camera, lamp), Blender shows ~5 MB of memory use. I added a UV sphere and subdivided it a few times to create a large mesh; memory usage went up to ~20 MB. I then called:

Obj = bpy.data.objects[‘Sphere’]
Me =Obj.data
Scn = bpy.data.scenes[‘Scene’]
Scn.objects.unlink(Obj)
removeMeshFromMemory(Me.name)

… and memory usage only goes down ~2 MB (to 18 MB total) instead of down to ~5 MB as it was for the starting scene.
What am I doing wrong?

(not read all) saw only your first try:
bpy.ops.mesh.merge(type=‘CURSOR’, uvs=False)
Makes a one vertex mesh :wink:

Answered my own question - the memory usage was all in the Undo settings. Removed global undo and set undo steps to 0 in user preferences, and all memory usage went down to original level. Now, if only I could figure out how to temporarily change those settings in a script…