Hello, I’m currently trying to fix a script/addon that was made in ~2.7 that’s just been updated to work with 2.8 and above. In it, the script is saving the image of the active view layer
to a specific folder based on what action
and view layer
is being rendered.
The problem is when multiple view layers
are enabled, it only saves the active view layer
, and it doesn’t save the other enabled view layers
even though they are also being rendered.
I know there are some ways of going about this:
rewrite the script to work with
File Output
nodes and work inside the compositor instead
not ideal, I have next to no idea regarding scripting, and I’ve tried reading about the documentation regarding class and types and whatnot and I couldn’t follow
edit the script so that it also saves the other layers, also making it so that the other layers are saved in their respective folder
not sure if this is even possible without the File Output
node
save the enabled view layers as some sort of list then disable all of them then only activate one at a time upon rendering, that way, time won’t be wasted rendering other layers that aren’t getting saved anyway
might be the easiest solution though might not be as optimized
Anyway, here’s the script. If anyone could point me in the right direction or suggest another way of approaching the problem, that would be great. Thanks
import bpy
from math import radians, floor, ceil, sqrt
from os.path import join
import sys
from PIL import Image
class RenderAllActions(bpy.types.Operator):
bl_idname = "scene.render_allactions"
bl_label = "Vingar Renderer"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scn = context.scene
S = bpy.context.scene
renderFolderInitial = scn.save_path
startFrame = 0
endFrame = 0 # frames
numAngles = scn.camera_angles
rotAngle = 360 / numAngles
all_render_layers = S.view_layers
render_layers = []
for layer in all_render_layers:
if layer.use == True:
render_layers.append(layer)
selection_names = bpy.context.selected_objects
all_actions = bpy.data.actions
render_actions = []
for action in all_actions:
if action.use_fake_user == True:
render_actions.append(action)
for action in render_actions:
bpy.context.view_layer.objects.active = bpy.data.objects[scn.rig_name]
rig = bpy.data.objects[scn.rig_name]
bpy.context.view_layer.objects.active = bpy.data.objects[scn.rig_name]
rig.animation_data.action = bpy.data.actions.get(action.name)
from bpy import context as C, data as D # just useful aliases same as in console
scene_objects = [o for o in D.objects if C.scene in o.users_scene]
render_platform = next(o for o in scene_objects if o.name.startswith('RenderPlatform'))
camParent = render_platform
if not scn.renderLastFrame:
endFrame = int(action.frame_range[1])
else:
endFrame = int(action.frame_range[1])-1
renderFolderAction = "{}/{}/".format(renderFolderInitial, action.name)
for layer in render_layers:
layer.use = True
for i in range(numAngles):
angle = i * rotAngle
camParent.rotation_euler.z = radians( angle )
renderFolder = "{0}{1}/{2}".format(renderFolderAction, layer.name, i+1)
fileNames = []
for f in range(startFrame,endFrame + 1):
S.frame_set( f )
frmNum = str( f-startFrame ).zfill(3)
fileName = "{f}".format(f = frmNum)
fileName += S.render.file_extension
S.render.filepath = join( renderFolder, fileName )
fileNames.append(bpy.path.abspath(S.render.filepath))
bpy.ops.render.render(write_still = True)
print("Combining rendered images...")
images = [Image.open(x) for x in fileNames]
widths, heights = zip(*(i.size for i in images))
# we can assume all images have the same width and height
maxWidth, maxHeight = getSquareSize(len(images))
maxWidth *= widths[0]
maxHeight *= heights[0]
maxWidth = int(maxWidth)
maxHeight = int(maxHeight)
new_im = Image.new('RGBA', (maxWidth, maxHeight), (255, 0, 0, 0))
x = 0
y = 0
for im in images:
new_im.paste(im, (x, y))
x += im.size[0]
if x >= maxWidth:
x = 0
y += im.size[1]
renderFolder = renderFolder.rsplit('/', 1)[0]
outFile = renderFolder + "/" + str(i + 1) + "-"
if scn.model_desc != "":
outFile += scn.model_desc + "-"
outFile += layer.name + "-" + action.name + S.render.file_extension
outFile = bpy.path.abspath(outFile)
print("Combined rendered images to: " + outFile)
new_im.save(outFile)
layer.use = False
camParent.rotation_euler.z = 0
return {'FINISHED'}
def getSquareSize(n):
root = sqrt(n)
if root.is_integer():
return (root, root)
minval = floor(root)
maxval = ceil(root)
if minval * maxval >= n:
return (maxval, minval)
else:
return (maxval, maxval)