0
$\begingroup$

I have defined a Blender class to help me abstract out details for rendering, object manipulation etc. I setup my scene using this class and put 12 cameras in it. Then I start rendering objects by switching between each of these cameras. A very strange thing that I noticed was no matter what the camera coordinates are, the last camera ALWAYS renders a black image as I had mentioned before, although my objects are all located at (0, 0, 0). I did some trial and error and found out that adding a "fake" camera would resolve the issue. However, what I then noticed was the rendering results of camera00 and camera04 are ALWAYS the same although the location of both cameras are completely different. This happens even if I change all of the camera coordinates. Another other strange fact is that all other cameras render the right images. Initially I was thinking the camera coordinates are the same but when I loaded the .blend file on my laptop I noticed that is not the case. I can render the objects correctly if I manually load the blend file and render with camera04. However I cannot do my rendering like that as I have many objects. The way I am currently doing my renderings is by compiling Blender as a Python module and loading it on my machine's Python.

This is a very strange issue. Does anyone know whether I am doing something wrong or how I can resolve it? Am I activating the cameras properly?

Below you can see the class I have defined and how I do the rendering:

#blenderClass.py
import importlib

class Blender(object):
    def __init__(self):
        self.bpy = importlib.import_module("bpy")
        self.scene = self.bpy.context.scene

    def setupScene(self, camPosList):
        self.cleanScene()
        self.addSun()

        self.numCams = len(camPosList)
        for i, coords in enumerate(camPosList):
            self.bpy.ops.object.camera_add(location=tuple(coords))
            self.activeObj = self.scene.objects.active
            self.activeObj.name = 'camera.0' + str(i)
            self.activeObj.data.name = 'camera.0' + str(i)
            self.pointObjTo(self.activeObj, (0.0, 0.0, 0.0))

        # Add a fake camera but never activate it
        self.bpy.ops.object.camera_add(location=tuple(coords)) # Use the last coords
        self.activeObj = self.scene.objects.active
        self.activeObj.name = 'camera.0' + str(i+1) # Use the last i from the for loop
        self.activeObj.data.name = 'camera.0' + str(i+1)
        self.pointObjTo(self.activeObj, (0.0, 0.0, 0.0))

   def render(self, objPath, renderPath):
        self.bpy.ops.import_scene.obj(filepath=objPath, split_mode="OFF")
        for i in range(self.numCams):
            self.scene.render.filepath =  renderPath + str(i) + '.png'
            self.activateCamera(i)
            self.bpy.ops.render.render(write_still=True)

   def pointObjTo(self, obj, xyzTarget):
        direction = Vector(xyzTarget) - obj.location
        obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()

   def activateCamera(self, camNo):
        self.scene.camera = self.scene.objects['camera.0' + str(camNo)]
        self.scene.update()

   def addSun(self, location=(0.0, 0.0, 1)):
        self.bpy.ops.object.lamp_add(type='SUN', location=location)
        self.activeObj = self.scene.objects.active
        self.activeObj.name = 'interiorIlluminator'
        self.activeObj.data.name = 'interiorIlluminator'
        self.activeObj.data.shadow_method = 'NOSHADOW'
        self.activeObj.data.energy = 0.8


    def cleanScene(self):
        self.removeLamps()
        self.removeMeshes(0)
        self.removeCameras()

    def removeMeshes(self, layer = -1):
        for obj in self.scene.objects:
            if obj.type == 'MESH' and obj.layers[layer != -1 and layer]:
                obj.select = True
            else:
                obj.select = False
        self.bpy.ops.object.delete()


    def removeCameras(self):
        for obj in self.scene.objects:
            if obj.type == 'CAMERA':
                obj.select = True
            else:
                obj.select = False
        self.bpy.ops.object.delete()


    def removeLamps(self):
        for obj in self.scene.objects:
            if obj.type == 'LAMP':
                obj.select = True
            else:
                obj.select = False
        self.bpy.ops.object.delete()

And here's how I do my renderings:

#main.py
import blenderClass import Blender
import numpy as np
camPosList = np.loadtxt('camPosList.txt')
blender = Blender()
blender.setupScene()
objPaths = ['obj1.obj', 'obj2.obj', 'obj3.obj', 'obj4.obj']

for objPath in objPaths:
     blender.render(objPath, 'somePath')

And here are the coordinates in camPosList::

1.106609463691711426e+00 -1.284419745206832886e-01 -4.973111748695373535e-01
2.114785015583038330e-01 -1.041638731956481934e+00 -5.988617539405822754e-01
6.345187127590179443e-02 7.305476069450378418e-02 -1.216143369674682617e+00
5.116637349128723145e-01 1.007419824600219727e+00 -4.601101875305175781e-01
9.366978406906127930e-01 4.701653420925140381e-01 6.244274377822875977e-01
7.511696219444274902e-01 -7.962130308151245117e-01 5.386640429496765137e-01
-9.366978406906127930e-01 -4.701653420925140381e-01 -6.244274377822875977e-01
-7.511696219444274902e-01 7.962130308151245117e-01 -5.386640429496765137e-01
-2.114785015583038330e-01 1.041638731956481934e+00 5.988617539405822754e-01
-6.345187127590179443e-02 -7.305476069450378418e-02 1.216143369674682617e+00
-5.116637349128723145e-01 -1.007419824600219727e+00 4.601101875305175781e-01
-1.106609463691711426e+00 1.284419745206832886e-01 4.973111748695373535e-01

You can download a set of rendering results from here: https://drive.google.com/open?id=1vqX_lLCFY7W3gll5CJ2hoaNzmhK8BLxp

And finally a .Blende file:

$\endgroup$
6
  • $\begingroup$ I notice that the “activateCamera(self, camNo)” function assigns self.scene.camera twice - firstly to self.scene.objects['camera.0' + str(camNo)] and secondly to self.activeObj. Why is that? Without understanding more about this assignment I can’t say if this would be a problem but it certainly looks suspicious. $\endgroup$ Commented May 8, 2018 at 13:25
  • $\begingroup$ @RichSedman Sorry that was a mistake. I don't use self.activeObj for that at all. Updated my post $\endgroup$
    – Amir
    Commented May 8, 2018 at 13:26
  • 6
    $\begingroup$ Does the guy who solves your issue get a credit in the paper? $\endgroup$
    – brockmann
    Commented May 8, 2018 at 15:03
  • $\begingroup$ @brockmann Yes; he/she will be acknowledged :) $\endgroup$
    – Amir
    Commented May 8, 2018 at 20:53
  • $\begingroup$ @RichSedman I resolved the issue in a hacky way. But do you think any part of my original code could be culprit for this problem? $\endgroup$
    – Amir
    Commented May 9, 2018 at 0:04

1 Answer 1

3
$\begingroup$

This is a very weird solution but adding another fake camera before adding camera.00 and doing the renderings from camera.00 to camera.11 resolves the issue! I'm not sure whether this is a bug or not but to me it certainly looks like a bug and I will report it.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .