I’ve been using ops.export_scene.obj() for exporting .obj’s for simple scenarios - exporting out to Ivy Generator, MeshLab, etc., but I realized that to export to xNormal I really need to export a mesh that looks like it would if I rendered it: smoothed, with modifiers applied.
Can somebody dumb down “C.object.to_mesh()” for me? What would be the simplest procedure for using this method effectively?
I guess what I mean is, what would you do to the new mesh datablock? ie., what would be the difference between using to_mesh() and working with that mesh, and simply calling export_scene.obj()?
And another question pops up - how do I export the mesh created with to_mesh() to an external file?
so you wanna use to_mesh() to apply modifiers, than export as OBJ using the existing IO addon, right?
But should this be automated, or do you want a file selector?
Lets say you wanna export to OBJ, then you might use a context override to call the obj exporter to make it export just that mesh (you would need to bind it to an object still i guess). Maybe you could use the actual obj export instead of its operator, that might give you more control and doesn’t involve context…
Actually, I would like to add a file selector, but I don’t know how to do that yet.
Lets say you wanna export to OBJ, then you might use a context override to call the obj exporter to make it export just that mesh (you would need to bind it to an object still i guess).
n00b question - what is a context override, and how does one use it?
Maybe you could use the actual obj export instead of its operator, that might give you more control and doesn’t involve context…
What is the ‘actual obj export’ if I’m not using the operator?
operators rely on context, but it’s not always possible to provide a suitable one (poll error etc.). By overriding the context you can make couple operators work without changing the actual context (e.g. change mode and select different object types). The override is constructed with a dict.
Simple example:
Imagine an operator that iterates over bpy.context.selected_objects, you wanna export the not selected objects but don’t wanna invert selection (not change selection states at all).
override = {“selected_objects”: [ob for ob in bpy.context.visible_objects if not ob.select]}
Selected objects will remain selected, but for the operator it looks like the not-selected objects were the selected ones and it will use them instead (bpy.context.selected_objects becomes a list of unselected objects)
What is the ‘actual obj export’ if I’m not using the operator?
I mean the actual export code, which is called by the export operator, but isn’t an operator itself. You could call that function directly if needed.
You’re a veritable fountain of knowledge! Thanks for all this. I’ve got some studying to do
Edit: I tried your example with some simple operators (delete(), duplicate(), etc.) but I’m not seeing it work the way I’m expecting it to. The operator returns {‘FINISHED’} but nothing happens.
it’s a good idea to call an operator with an empty dict as override to see what it needs:
bpy.ops.object.delete({})
PyContext ‘window’ not foundPyContext ‘scene’ not found
PyContext ‘active_object’ not found
PyContext ‘edit_object’ not found
PyContext ‘window’ not found
PyContext ‘scene’ not found
PyContext ‘active_object’ not found
PyContext ‘edit_object’ not found
PyContext ‘blend_data’ not found
PyContext ‘scene’ not found
PyContext ‘edit_object’ not found
PyContext ‘selected_bases’ not found
PyContext ‘window’ not found
PyContext ‘region’ not found
PyContext ‘window’ not found
PyContext ‘region’ not found
If you group these context objects, you can make a list like this:
If you experiment with overrides, you will get blender crashed often. The underlying problem seems to originate from a missing “selected_bases” key in the dict. Objects aren’t associated with scenes they are in, but there are rather “bases” linked to scenes, and one property of a base is a reference to an object. So if you supply a scene and an object, the bases will be missing and crash blender.
A possible solution is to copy the current content and just override key-values as needed - but you should test thoroughly if it makes the operator work like you desire. It might be easier to not copy the context and construct an override yourself until it works rather than experimenting with key-value changes until the op does what it should.
import bpyfrom bpy import context as C
for area in C.screen.areas:
if area.type == 'VIEW_3D':
for region in area.regions:
if region.type == 'WINDOW':
override = {
'window': C.window,
'area': area,
'region': region,
'scene': C.scene,
'selected_bases': [obb for obb in C.scene.object_bases if obb.object.name == "Cube"],
}
bpy.ops.object.delete(override)
break
That will delete the object “Cube” even if it’s not selected.
There are still PyContext warnings in console, but you usually ignore them. You could even strip down the override dict as long as the actual operator still works:
import bpy
from bpy import context as C
override = {
'selected_bases': [obb for obb in C.scene.object_bases if obb.object.name == "Cube"],
}
bpy.ops.object.delete(override)
Hey by the way, thank you for this explanation. It was way over my head at first, so I just got around to really wrapping my head around it, and this explanation helped me understand. So thanks!