6

I have a script that allows to import and export .obj files which is working fine. However, I'd like to perform some operations in between these calls, for example select the mesh and recalculate the normals (outside). If I try that, I get a context error and I'm not sure why...?

RuntimeError: Operator bpy.ops.object.mode_set.poll() failed, context is incorrect

    bpy.ops.import_scene.obj(filepath=source_to_file)
print("Starting--------------------------------------------")
for obj in bpy.data.objects:
    bpy.context.scene.objects.active = obj
    # go edit mode
    bpy.ops.object.mode_set(mode='EDIT')
    # select al faces
    bpy.ops.mesh.select_all(action='SELECT')
    # recalculate outside normals 
    bpy.ops.mesh.normals_make_consistent(inside=False)
    # go object mode again
    bpy.ops.object.editmode_toggle()
print("Ending--------------------------------------------")

bpy.ops.export_scene.obj(filepath=target_to_file,use_materials=True)

How is it possible to know the object imported by any operator (there is no return value) and how can I recalculate the normals per object that is triggered by a button?

brockmann
  • 12,613
  • 4
  • 50
  • 93
D.Giunchi
  • 163
  • 1
  • 6

2 Answers2

13

Making normals outside can also be done with the bmesh module operator recalc_face_normals(bm, faces)

Sample script

import bpy
import bmesh

from bpy import context

#bpy.ops.import_scene.obj(filepath=source_to_file) bm = bmesh.new() meshes = set(o.data for o in context.selected_objects if o.type == 'MESH') for mesh in meshes: bm.from_mesh(mesh) bmesh.ops.recalc_face_normals(bm, faces=bm.faces) bm.to_mesh(mesh) bm.clear() mesh.update()

bm.free() #bpy.ops.export_scene.obj(filepath=target_to_file, use_materials=True)

Saves the need to flip mode and context object.

brockmann
  • 12,613
  • 4
  • 50
  • 93
batFINGER
  • 84,216
  • 10
  • 108
  • 233
8

You can use bpy.context.selected_objects[:] to get all imported objects. Iterate through the list, set the select state of each object to True and make it the active object as well in order to call operators like mesh.normals_make_consistent():

Blender 2.8+

import bpy

bpy.ops.import_scene.obj(filepath=source_to_file) obj_objects = bpy.context.selected_objects[:]

for obj in obj_objects: bpy.ops.object.select_all(action='DESELECT') obj.select_set(True) bpy.context.view_layer.objects.active = obj # go edit mode bpy.ops.object.mode_set(mode='EDIT') # select al faces bpy.ops.mesh.select_all(action='SELECT') # recalculate outside normals bpy.ops.mesh.normals_make_consistent(inside=False) # go object mode again bpy.ops.object.editmode_toggle()

Blender 2.7x

import bpy

bpy.ops.import_scene.obj(filepath=source_to_file) obj_objects = bpy.context.selected_objects[:]

for obj in obj_objects: bpy.ops.object.select_all(action='DESELECT') obj.select = True bpy.context.scene.objects.active = obj # go edit mode bpy.ops.object.mode_set(mode='EDIT') # select al faces bpy.ops.mesh.select_all(action='SELECT') # recalculate outside normals bpy.ops.mesh.normals_make_consistent(inside=False) # go object mode again bpy.ops.object.editmode_toggle()

Updated .blend file can be found here:

brockmann
  • 12,613
  • 4
  • 50
  • 93
Tak
  • 6,293
  • 7
  • 43
  • 85
  • I have this error: AttributeError: 'Context' object has no attribute 'selected_objects' (I use 2.78a) – D.Giunchi Feb 01 '17 at 00:01
  • @D.Giunchi Could you provide your whole script to be able to debug it – Tak Feb 01 '17 at 00:02
  • http://pastebin.com/vpyi29Nq , I also used obj_objects = [ o for o in bpy.context.scene.objects if o.select ] but I got the first error. – D.Giunchi Feb 01 '17 at 00:08
  • @D.Giunchi I tried this http://pasteall.org/225375 and it's working totally fine with no errors – Tak Feb 01 '17 at 00:20
  • in the console I can see this: location: :-1 Error: Traceback (most recent call last): File "\fix.py", line 73, in File "\fixpy", line 52, in main File "C:\Program Files\Blender Foundation\Blender\2.78\scripts\modules\bpy\ops.py", line 189, in call ret = op_call(self.idname_py(), None, kw) RuntimeError: Operator bpy.ops.object.mode_set.poll() failed, context is incorrect

    location: :-1

    Error: Python script fail, look in the console for now...

    <!> event has invalid window

    – D.Giunchi Feb 01 '17 at 00:53
  • @D.Giunchi what are the lines 73 in 52 in your script? – Tak Feb 01 '17 at 01:20
  • 52 is bpy.ops.object.mode_set(mode='EDIT') , the other is the main that call. I discover that using another obj it seems to work. The weird thing is that when I run the script I see in blender that the obj that is loaded and selected and I can change the mode to edit with the combo. I uploaded the obj here http://filebin.ca/3AqCDhS3JUuI – D.Giunchi Feb 01 '17 at 01:36
  • @D.Giunchi as shown here http://pasteall.org/pic/index.php?id=111981 it's working perfect with me. – Tak Feb 01 '17 at 02:08
  • really don't know what to think, if I used the script with your change I get this error: AttributeError: 'Context' object has no attribute 'selected_objects' , I have a windows 10, 64 bit...maybe should I try in a Virtual Machine, don't know what;s going on. – D.Giunchi Feb 01 '17 at 02:42
  • @D.Giunchi send me your .blend file – Tak Feb 01 '17 at 02:45
  • @D.Giunchi the file you sent doesn't include the script. Please provide the complete file with script and everything causing the error. – Tak Feb 01 '17 at 03:08
  • actually you don't need the blend, since I open blender and simply run the script but I put everything here: http://filebin.ca/3AsCCCCsBnJu – D.Giunchi Feb 01 '17 at 08:26
  • I tried also in virtual box (linux mint) and I force my friend to run it and he got the same error :( – D.Giunchi Feb 01 '17 at 09:20
  • @D.Giunchi check this file http://pasteall.org/blend/index.php?id=45346 – Tak Feb 01 '17 at 11:49
  • it works this one, I did several tries... like removing the model and run the script. But what I miss to do to have a blend like this? My workflow was, open blender, open the script ,run it. – D.Giunchi Feb 01 '17 at 12:00
  • @D.Giunchi It looks like the problem is in the .blend file. I'll update my answer and provide the .blend file if you can accept and upvote. – Tak Feb 01 '17 at 12:03
  • works for me, but probably I miss something to do for let blender knows the context or something like this – D.Giunchi Feb 01 '17 at 12:13
  • @D.Giunchi Obviously, The problem is in your .blend file – Tak Feb 01 '17 at 12:14
  • maybe I got it, it was the reset_blend function, it cleared too much and lost the context. Many Thanks – D.Giunchi Feb 01 '17 at 14:57