Blender to Arnold Export - Part II: Cameras
Jan Walter June 19, 2023 [DCC] #blender #arnold #pythonThe last part (Blender to Arnold Export - Part I: The
Addon) introduced the Blender
addon without talking really about the
Python code behind it. The Python code
already supported exporting polymesh
nodes to Arnold (using the
Python API of Blender and
Arnold). The splash screen scene for
Blender 3.5.1 contains 2012
such nodes:
|
But to be able to render something we need at least a camera node. Arnold knows several of those camera nodes:
|
But for now lets start with just a ortho_camera
node (needed for the
splash screen scene), and a persp_camera
node (for most other
scenes). Lets first look at the resulting image:
At that point I was still using an Arnold persp_camera
node and
zoomed in a bit to match the Blender viewport, but I fixed that later
by providing the Arnold ortho_camera
node:
So the code I added to the already existing Python code can be seen
here in the output of git diff
:
diff --git a/blender/io_scene_ass/export_ass.py b/blender/io_scene_ass/export_ass.py
index d57f389..ef11aaf 100644
+# Python modules
+import math
import os
-import sys
import platform
+import sys
+# Blender modules
import bpy
from mathutils import Matrix #, Vector, Color
#from bpy_extras import io_utils, node_shader_utils
arnold.AiBegin()
# we need an arnold universe below
universe = arnold.AiUniverse()
+ # options
+ options = arnold.AiUniverseGetOptions(universe)
+ # get camera (used for rendering) from scene
+ scene = bpy.context.scene
+ camera_name = scene.camera.name
# Blender objects
EXPORT_GLOBAL_MATRIX = Matrix()
depsgraph = context.evaluated_depsgraph_get()
except RuntimeError:
me = None
if me is None:
- print('WARNING: ignore "%s" ...' % ob.name)
+ if ob.type == 'CAMERA':
+ if ob.name == camera_name:
+ percent = scene.render.resolution_percentage / 100.0
+ xresolution = int(scene.render.resolution_x * percent)
+ yresolution = int(scene.render.resolution_y * percent)
+ # xres
+ arnold.AiNodeSetInt(options, "xres", xresolution)
+ # yres
+ arnold.AiNodeSetInt(options, "yres", yresolution)
+ if ob.data.type == 'ORTHO':
+ # ortho_camera
+ camera = arnold.AiNode(universe,
+ "ortho_camera",
+ camera_name)
+ # screen_window
+ ortho_scale = ob.data.ortho_scale / 2.0
+ arnold.AiNodeSetVec2(camera,
+ "screen_window_min",
+ -ortho_scale, -ortho_scale)
+ arnold.AiNodeSetVec2(camera,
+ "screen_window_max",
+ ortho_scale, ortho_scale)
+ else:
+ # persp_camera
+ camera = arnold.AiNode(universe,
+ "persp_camera",
+ camera_name)
+ # fov
+ aspect = xresolution / float(yresolution)
+ if aspect >= 1.0:
+ fov = math.degrees(ob.data.angle)
+ else:
+ fov = 2 * math.degrees(math.atan((aspect * 16.0) / lens))
+ arnold.AiNodeSetFlt(camera, "fov", fov)
+ # options needs a link to camera
+ arnold.AiNodeSetPtr(options, "camera", camera)
+ # matrix
+ am = arnold.AtMatrix()
+ arnold.AiM4Identity(am)
+ am[0][0] = ob_mat[0][0]
+ am[0][1] = ob_mat[1][0]
+ am[0][2] = ob_mat[2][0]
+ am[0][3] = ob_mat[3][0]
+ am[1][0] = ob_mat[0][1]
+ am[1][1] = ob_mat[1][1]
+ am[1][2] = ob_mat[2][1]
+ am[1][3] = ob_mat[3][1]
+ am[2][0] = ob_mat[0][2]
+ am[2][1] = ob_mat[1][2]
+ am[2][2] = ob_mat[2][2]
+ am[2][3] = ob_mat[3][2]
+ am[3][0] = ob_mat[0][3]
+ am[3][1] = ob_mat[1][3]
+ am[3][2] = ob_mat[2][3]
+ am[3][3] = ob_mat[3][3]
+ arnold.AiNodeSetMatrix(camera, "matrix", am)
+ else:
+ print('WARNING: ignore "%s" ...' % ob.name)
+ else:
+ print('WARNING: ignore "%s" ...' % ob.name)
continue
# _must_ do this first since it re-allocs arrays
mesh_triangulate(me)
##print('DEBUG: obnamestring = %s' % obnamestring)
# arnold
polymesh = arnold.AiNode(universe, "polymesh", obnamestring)
+ arnold.AiNodeSetBool(polymesh, "smoothing", False)
vlist = arnold.AiArrayAllocate(len(me_verts), 1,
arnold.AI_TYPE_VECTOR)
numVertexIndices = 0
# SPDX-License-Identifier: GPL-2.0-or-later
The first couple of lines just give access to the Arnold options
node, which later will link back to the camera node we will create
(and set the render resolution, which we get from Blender).
{
}
If we just search for camera
we see how that link works, it mentions
the name
of a node, which in this case has a type of ortho_camera
:
The node itself and it's name can be seen here:
{
}
So we also export the matrix
and four values (two VECTOR2
parameters) to define the screen_window
settings of the Arnold
ortho_camera
node:
)
)
)
For now we do not care about the other parameters. Let's check what else is missing right now instead:
|
|
| )
|
|
|
|
|
|
|
|
|
Most of the ignored Blender nodes are lights, which we would need next, so we can render using shaders.
...
= None
=
# AiBegin
...
continue
=
# ignore dupli children
continue
=
=
+=
=
=
= None
...
continue
...
# AiSceneWrite
=
=
# AiEnd
...
The Arnold image above was rendered using the -is
option:
|
Like this (omitting other options used to render the .ass
file):