3

I am trying to convert all the curves in a blendfile to meshes - like this, as explained here:

import bpy

for obj in [ obj for obj in bpy.data.objects ]: if obj.type == "CURVE": print(obj, obj.type, obj.parent.type) print([ o.type for o in getChildren(obj.parent) ])

    dg  = bpy.context.evaluated_depsgraph_get()
    obj = dg.objects.get(obj.name)

    me = obj.to_mesh()
    print(len(me.vertices))
    try:
        o = bpy.data.objects.new(obj.name + "Mesh", me)
    except Exception as e:     
        print(e)

However it throws an error:

 Error: Can not create object in main database with an evaluated data data-block

I've also tried using:

 obj = obj.evaluated_get(dg) 

like explained here but this fails too.

What am I doing wrong?

simone
  • 745
  • 4
  • 14
  • I don't understand why you're trying to use the depsgraph, but you have a Python issue: You are using obj both as the loop variable and as a variable within the loop. Try changing the internal name to something else. – Marty Fouts Jun 01 '22 at 15:20

3 Answers3

4

The docs of bpy.types.Object.to_mesh state :

The result is temporary and can not be used by objects from the main database

Which means you can't use this evaluated mesh as data for an actual object in the scene. It will be thrown to the garbage collector once the scope it was created in completes.

As the other answer suggest, you may want to use the bpy.ops.object.convert operator to do it. I would add the optional keep_original argument since your code seems to hint that you want to keep the original curves.

As I discovered in my endeavour to document all operator overrides, this operator can't be overriden. So you'll have to select objects by code.

import bpy

bpy.ops.object.select_all(action='DESELECT')

for obj in bpy.data.objects: if obj.type == 'CURVE': obj.select_set(True) bpy.ops.object.convert(target='MESH', keep_original=True)

You can also use lower-level functions :

import bpy

for obj in bpy.data.objects: if obj.type == "CURVE": mesh = bpy.data.meshes.new_from_object(obj) new_obj = bpy.data.objects.new(obj.name, mesh) new_obj.matrix_world = obj.matrix_world bpy.context.collection.objects.link(new_obj)

Credit https://blender.stackexchange.com/a/277424/86891 and https://docs.blender.org/api/current/bpy.types.BlendDataMeshes.html#bpy.types.BlendDataMeshes.new_from_object

Gorgious
  • 30,723
  • 2
  • 44
  • 101
1

Turns out there is an even simpler solution, if you copy the evaluated mesh, it will create a mesh datablock you can use for real.

import bpy

for obj in bpy.data.objects[:]: if obj.type == "CURVE": me = obj.to_mesh() o = bpy.data.objects.new(obj.name + "Mesh", me.copy()) o.matrix_world = obj.matrix_world bpy.context.collection.objects.link(o)

Gorgious
  • 30,723
  • 2
  • 44
  • 101
0

AFAIK to convert a curve to an object you have to select it. So I guess you can do something like this:

obj.select_set(True)
bpy.ops.object.convert(target='MESH')
Iván
  • 171
  • 5