0
$\begingroup$

I'm trying to create a panorama image/video from around the outside of the scene for cylindrical video wall.

Have read How to render an "inverse" panorama but doesn't generate the back side of the scene in its output.

found https://developer.blender.org/T29266 as a starting point but it was for having the observer at the centre of the scene.

I've come up with the below code so far but seem to be missing something or not slicing/maping each camera view correctly as it comes out with visual artefacts around the seems of each render slice, reducing numScreens will increase the visual issue.

import bpy
from bpy.props import IntProperty
from bpy.props import BoolProperty
import mathutils
from math import pi
import re

CAMERA_ORIGIN_NAME = "CameraOrigin"
start_pos = (250,0,0)

scene_base = bpy.context.scene
sceneName = scene_base.name
renderpath = scene_base.render.filepath
numScreens = 360
scene_base.use_nodes = True
bpy.context.scene.node_tree.nodes.clear()

for o in bpy.data.scenes:
    if (o.name != "Scene"):
        bpy.data.scenes.remove(o, do_unlink=True)

for o in bpy.data.cameras:
    bpy.data.cameras.remove(o, do_unlink=True)

obj_origin = scene_base.objects.get(CAMERA_ORIGIN_NAME)
if obj_origin:
    bpy.data.objects[CAMERA_ORIGIN_NAME].select = True
    for child in bpy.data.objects[CAMERA_ORIGIN_NAME].children:
        child.select = True
    bpy.ops.object.delete()

def rotate_object(obj, angle, direction, point):
    R = mathutils.Matrix.Rotation(angle, 4, direction)
    T = mathutils.Matrix.Translation(point)
    M = T * R * T.inverted()
    obj.location = M * obj.location
    obj.rotation_euler.rotate(M)


# add an empty for the camera origin if not already present
obj_origin = scene_base.objects.get(CAMERA_ORIGIN_NAME)
if not obj_origin:
    bpy.ops.object.add()
    obj_origin = bpy.context.active_object
    obj_origin.name = CAMERA_ORIGIN_NAME
    obj_origin.location = 0,0,0

for i in range(0,numScreens):

    # add a new camer
    bpy.ops.object.camera_add()

    # get the current camera
    cam = bpy.context.active_object

    # name the camera
    cameraName = "Camera" + str(i)
    cam.name = cameraName
    cam.data.name = cameraName
    bpy.data.cameras[cameraName].clip_end  = (start_pos[0]+5)

    # position camera
    cam.location = start_pos
    cam.rotation_euler = (pi/2), 0, (pi/2)
    rotate_object(cam,(((-2*pi)/numScreens)*i) ,(00,0,10),(0,0,0))


    # set the field of view angle
    cam.data.angle = (2*pi)/numScreens

    # make the parent of the camera the origin
    cam.parent = obj_origin
    print("Camera" + str(i))

# sel/activate origin
bpy.ops.object.select_all(action='DESELECT')
obj_origin.select = True
scene_base.objects.active = obj_origin

for i in range(0, numScreens):

    thisScene = sceneName + "-Camera" + str(i)

    bpy.ops.scene.new(type='LINK_OBJECTS')
    scene_new = bpy.context.scene
    scene_new.name = thisScene

    camera_object = bpy.data.objects["Camera" + str(i)]
    scene_new.camera = camera_object

    scene_new.render.filepath = renderpath + thisScene
    print(sceneName + "-Camera" + str(i))

bpy.context.screen.scene = scene_base
last_node = None
tree = scene_base.node_tree
j = 1
for i in range(0, numScreens):
    thisScene = sceneName + "-Camera" + str(i)
    new_render_layer_node = tree.nodes.new("CompositorNodeRLayers")
    new_crop_node = tree.nodes.new("CompositorNodeCrop")
    new_render_layer_node.scene = bpy.data.scenes[sceneName + "-Camera" + str(i)]
    new_render_layer_node.location.x = 200*i
    new_render_layer_node.location.y = 400*j
    new_render_layer_node.name='rl_X_'+ str(i)+'_Y_'+str(j)
    tree.links.new(new_render_layer_node.outputs['Image'],new_crop_node.inputs['Image'])
    #new_crop_node.inputs['X'].default_value = 1/numScreens
    new_crop_node.hide=True
    new_crop_node.min_y=bpy.context.scene.render.resolution_y
    new_crop_node.max_y=0
    new_crop_node.min_x=(bpy.context.scene.render.resolution_x/2)-((bpy.context.scene.render.resolution_x/numScreens)/2)
    new_crop_node.max_x=(bpy.context.scene.render.resolution_x/2)+((bpy.context.scene.render.resolution_x/numScreens)/2)

    new_crop_node.location.x = 200*i
    new_crop_node.location.y = 500*j
    new_transf_node = tree.nodes.new(type = 'CompositorNodeTranslate')

    tree.links.new(new_crop_node.outputs['Image'], new_transf_node.inputs['Image'])
    new_transf_node.inputs['X'].default_value=(bpy.context.scene.render.resolution_x/numScreens)*(i-(numScreens-1)/2.0)
    new_transf_node.inputs['Y'].default_value=0
    new_transf_node.hide=True
    new_transf_node.location.x = 200*i+100
    new_transf_node.location.y = 500*j

    if last_node is None:
        last_node=new_transf_node
    else:
        alphanode=tree.nodes.new(type = 'CompositorNodeAlphaOver')
        tree.links.new(new_transf_node.outputs[0], alphanode.inputs[2])
        tree.links.new(last_node.outputs[0], alphanode.inputs[1])
        alphanode.location.x = 200*i
        alphanode.location.y = 200*j
        last_node=alphanode
    print("Node-Scene" + str(i))

comp_node = tree.nodes.new('CompositorNodeComposite')
comp_node.location = 100,600
tree.links.new(last_node.outputs[0], comp_node.inputs[0])
comp_node = tree.nodes.new('Comp[![enter image description here][1]][1]ositorNodeViewer')
comp_node.location = 150,600
tree.links.new(last_node.outputs[0], comp_node.inputs[0])

code works in blender 2.78c but 2.80 doesn't like

M = T * R * T.inverted()

numScreens=36: numScreens=36 numScreens=360: numScreens=360

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.