[Bf-extensions-cvs] [ad66193] master: Render Cube Maps addon
Dalai Felinto
noreply at git.blender.org
Fri Nov 11 10:49:45 CET 2016
Commit: ad66193aa09e00596108e6e92646d986156c7541
Author: Dalai Felinto
Date: Fri Nov 11 10:47:29 2016 +0100
Branches: master
https://developer.blender.org/rBACad66193aa09e00596108e6e92646d986156c7541
Render Cube Maps addon
This addon is originally aimed at VR artists wanting to make cubemaps
for VR rendering. A cubemap is supposed to have a considerable lower
rendertime compared to a panorama. It also fix poles artifact issues.
Thanks BlendFX for funding the development of this addon.
===================================================================
A render_cube_map.py
===================================================================
diff --git a/render_cube_map.py b/render_cube_map.py
new file mode 100644
index 0000000..d12c5c6
--- /dev/null
+++ b/render_cube_map.py
@@ -0,0 +1,613 @@
+# ====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+# ########################################
+# Render Cube Map
+#
+# Dalai Felinto
+# --
+# blendernetwork.org/dalai-felinto
+# www.dalaifelinto.com
+#
+# Original code:
+# Rio de Janeiro, September 2015
+#
+# Latest update:
+# Rio de Janeiro, July 2016
+# ########################################
+
+import bpy
+
+from bpy.app.handlers import persistent
+
+from bpy.types import (
+ Operator,
+ Panel,
+ )
+
+from bpy.props import (
+ BoolProperty,
+ )
+
+bl_info = {
+ "name": "Cube Map",
+ "author": "Dalai Felinto",
+ "version": (1, 0),
+ "blender": (2, 7, 7),
+ "location": "Render Panel",
+ "description": "",
+ "warning": "",
+ "wiki_url": "https://github.com/dfelinto/render_cube_map",
+ "tracker_url": "",
+ "category": "Render"}
+
+
+# ############################################################
+# Global Check
+# ############################################################
+
+def do_run(cube_map, use_force):
+ if not (cube_map.use_cube_map or use_force):
+ return False
+
+ if cube_map.is_enabled and not use_force:
+ return False
+
+ return True
+
+
+# ############################################################
+# Callbacks
+# ############################################################
+
+class NodeTree:
+ def __init__(self, scene):
+ self._use_nodes = scene.use_nodes
+ self._use_compositing = scene.render.use_compositing
+
+ self._nodes_mute = {}
+ self._scene = scene
+
+ self._scene.render.use_compositing = True
+
+ if not self._use_nodes:
+ scene.use_nodes = True
+ self._muteNodes()
+ else:
+ self._storeNodes()
+ self._muteNodes()
+
+ def _storeNodes(self):
+ """
+ store the existent nodes and if they are muted
+ """
+ nodes = self._scene.node_tree.nodes
+ for node in nodes:
+ self._nodes_mute[hash(node)] = node.mute
+
+ def _muteNodes(self):
+ """
+ mute all the existent nodes
+ """
+ nodes = self._scene.node_tree.nodes
+ for node in nodes:
+ node.mute = True
+
+ def cleanupScene(self):
+ """
+ remove all the new nodes, and unmute original ones
+ """
+ scene = self._scene
+ scene.use_nodes = self._use_nodes
+ scene.render.use_compositing = self._use_compositing
+
+ self._cleanNodes()
+ self._unMuteNodes()
+
+ def _cleanNodes(self):
+ """
+ remove all the nodes created temporarily
+ """
+ nodes = self._scene.node_tree.nodes
+ to_del = []
+ keys = self._nodes_mute.keys()
+
+ for node in nodes:
+ if hash(node) not in keys:
+ to_del.append(node)
+
+ for node in to_del:
+ nodes.remove(node)
+
+ def _unMuteNodes(self):
+ """
+ unmute all the existent nodes
+ """
+ nodes = self._scene.node_tree.nodes
+ for node in nodes:
+ node.mute = self._nodes_mute[hash(node)]
+
+
+class View:
+ def __init__(self, name, euler_rotation):
+ self._name = name
+ self._scene = None
+ self._scene_camera = None
+ self._node = None
+ self._camera = None
+ self._euler_rotation = euler_rotation
+
+ def setScene(self, scene):
+ scene.name = self._name
+ self._scene = scene
+
+ scene.cube_map.use_cube_map = False
+ scene.render.use_compositing = False
+
+ self._setFilepath()
+
+ def _setFilepath(self):
+ import os
+
+ filepath = self._scene.render.filepath
+
+ dirname = os.path.dirname(filepath)
+ basename = os.path.basename(filepath)
+
+ path = os.path.join(dirname, "{0}{1}".format(self._name, basename))
+ self._scene.render.filepath = path
+
+ def setNode(self, node, links, node_output):
+ node.name = self._name
+ node.label = self._name
+ node.scene = self._scene
+ self._node = node
+
+ # TODO if there were nodetrees, duplicate them here
+
+ # connect to output
+ _input = node_output.layer_slots.new(self._name)
+ links.new(node.outputs[0], _input)
+
+ def setCamera(self, data, loc, zed):
+ self._scene_camera = self._scene.camera
+
+ self._camera = bpy.data.objects.new(self._name, data)
+ self._scene.objects.link(self._camera)
+
+ rotation = self._euler_rotation.copy()
+ rotation.z += zed
+
+ self._camera.rotation_euler = rotation
+ self._camera.location = loc
+
+ # change scene camera
+ self._scene.camera = self._camera
+
+ def resetCamera(self):
+ self._scene.objects.unlink(self._camera)
+ bpy.data.objects.remove(self._camera)
+ self._camera = None
+
+ @property
+ def scene(self):
+ return self._scene
+
+ @property
+ def name(self):
+ return self._name
+
+
+ at persistent
+def cube_map_render_init(scene, use_force=False):
+ """
+ setup the cube map settings for all the render frames
+ """
+ from mathutils import Euler
+ from math import pi
+ half_pi = pi * 0.5
+
+ cube_map = scene.cube_map
+
+ if not do_run(cube_map, use_force):
+ return
+
+ main_scene = scene
+ hashes = [hash(scene) for scene in bpy.data.scenes]
+
+ views_raw = (
+ (
+ 'NORTH_',
+ Euler((half_pi, 0.0, 0.0)),
+ cube_map.use_view_north,
+ ),
+ (
+ 'SOUTH_',
+ Euler((half_pi, 0.0, pi)),
+ cube_map.use_view_south,
+ ),
+ (
+ 'WEST_',
+ Euler((half_pi, 0.0, half_pi)),
+ cube_map.use_view_west,
+ ),
+ (
+ 'EAST_',
+ Euler((half_pi, 0.0, -half_pi)),
+ cube_map.use_view_east,
+ ),
+ (
+ 'ZENITH_',
+ Euler((pi, 0.0, 0.0)),
+ cube_map.use_view_zenith,
+ ),
+ (
+ 'NADIR_',
+ Euler((0.0, 0.0, 0.0)),
+ cube_map.use_view_nadir,
+ ),
+ )
+
+ views = [
+ View(name, euler) for (name, euler, use) in views_raw
+ if use or not cube_map.is_advanced]
+
+ for view in views:
+ # create a scene per view
+ bpy.ops.scene.new(type='LINK_OBJECTS')
+ scene = [
+ scene for scene in bpy.data.scenes if
+ hash(scene) not in hashes][0]
+
+ # mark the scene to remove it afterwards
+ scene.cube_map.is_temporary = True
+
+ hashes.append(hash(scene))
+ view.setScene(scene)
+
+ # create a scene from scratch
+ node_tree_data = NodeTree(main_scene)
+
+ # created the necessary nodetrees there
+ node_tree = main_scene.node_tree
+
+ # output node
+ node_output = node_tree.nodes.new('CompositorNodeOutputFile')
+ node_output.inputs.clear()
+
+ for view in views:
+ node = node_tree.nodes.new('CompositorNodeRLayers')
+ view.setNode(node, node_tree.links, node_output)
+
+ # globals
+ bpy.cube_map_node_tree_data = node_tree_data
+ bpy.cube_map_views = views
+
+
+# ############################################################
+# Cameras Setup
+# ############################################################
+
+ at persistent
+def cube_map_render_pre(scene, use_force=False):
+
+ if not do_run(scene.cube_map, use_force):
+ return
+
+ from math import radians
+
+ camera = scene.camera
+ data = camera.data.copy()
+
+ data.lens_unit = 'FOV'
+ data.angle = radians(90)
+ data.type = 'PERSP'
+
+ mat = camera.matrix_world
+
+ loc = mat.to_translation()
+ rot = mat.to_euler()
+ zed = rot.z
+
+ views = bpy.cube_map_views
+
+ for view in views:
+ view.setCamera(data, loc, zed)
+
+
+ at persistent
+def cube_map_render_post(scene, use_force=False):
+
+ if not do_run(scene.cube_map, use_force):
+ return
+
+ views = bpy.cube_map_views
+
+ for view in views:
+ view.resetCamera()
+
+
+# ############################################################
+# Clean-Up
+# ############################################################
+
+ at persistent
+def cube_map_render_cancel(scene):
+ cube_map_cleanup(scene)
+
+
+ at persistent
+def cube_map_render_complete(scene):
+ cube_map_cleanup(scene)
+
+
+def cube_map_cleanup(scene, use_force=False):
+ """
+ remove all the temporary data created for the cube map
+ """
+
+ if not do_run(scene.cube_map, use_force):
+ return
+
+ bpy.cube_map_node_tree_data.cleanupScene()
+ del bpy.cube_map_node_tree_data
+ del bpy.cube_map_views
+
+ bpy.app.handlers.scene_update_post.append(cube_map_post_update_cleanup)
+
+
+def cube_map_post_update_cleanup(scene):
+ """
+ delay removal of scenes (otherwise we get a crash)
+ """
+ scenes_temp = [
+ scene for scene in bpy.data.scenes if
+ scene.cub
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list