Fix T56413: Setup Tracking Scene not working in 2.8

Patch by Sebastian Koenig and me, with review and suggestions by Sergey Sharybin.

https://developer.blender.org/D3626
This commit is contained in:
Dalai Felinto 2018-08-21 11:30:15 -03:00
parent 91ff41bbda
commit 17c245e294
Notes: blender-bot 2023-02-14 08:33:26 +01:00
Referenced by commit e9182a0f5d, Fixup for Setup Tracking Scene
Referenced by issue #56413, Setup Tracking Scene not working in 2.8
1 changed files with 105 additions and 122 deletions

View File

@ -524,6 +524,7 @@ class CLIP_OT_constraint_to_fcurve(Operator):
class CLIP_OT_setup_tracking_scene(Operator):
"""Prepare scene for compositing 3D objects into this footage"""
# TODO: it will be great to integrate with other engines (other than Cycles)
bl_idname = "clip.setup_tracking_scene"
bl_label = "Setup Tracking Scene"
@ -544,6 +545,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
def _setupScene(context):
scene = context.scene
scene.active_clip = context.space_data.clip
scene.render.use_motion_blur = True
@staticmethod
def _setupWorld(context):
@ -554,16 +556,9 @@ class CLIP_OT_setup_tracking_scene(Operator):
world = bpy.data.worlds.new(name="World")
scene.world = world
# Having AO enabled is nice for shadow catcher.
world.light_settings.use_ambient_occlusion = True
world.light_settings.ao_blend_type = 'MULTIPLY'
world.light_settings.use_environment_light = True
world.light_settings.environment_energy = 0.1
world.light_settings.distance = 1.0
world.light_settings.sample_method = 'ADAPTIVE_QMC'
world.light_settings.samples = 7
world.light_settings.threshold = 0.005
if hasattr(scene, "cycles"):
world.light_settings.ao_factor = 0.05
@ -576,7 +571,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
cam = bpy.data.cameras.new(name="Camera")
camob = bpy.data.objects.new(name="Camera", object_data=cam)
scene.objects.link(camob)
scene.collection.objects.link(camob)
scene.camera = camob
@ -598,10 +593,10 @@ class CLIP_OT_setup_tracking_scene(Operator):
camob = CLIP_OT_setup_tracking_scene._findOrCreateCamera(context)
cam = camob.data
# Remove all constraints to be sure motion is fine
# Remove all constraints to be sure motion is fine.
camob.constraints.clear()
# Append camera solver constraint
# Append camera solver constraint.
con = camob.constraints.new(type='CAMERA_SOLVER')
con.use_active_clip = True
con.influence = 1.0
@ -627,15 +622,66 @@ class CLIP_OT_setup_tracking_scene(Operator):
fg = view_layers.new("Foreground")
fg.use_sky = True
fg.layers = [True] + [False] * 19
fg.layers_zmask = [False] * 10 + [True] + [False] * 9
fg.use_pass_vector = True
if not view_layers.get("Background"):
bg = view_layers.new("Background")
bg.use_pass_shadow = True
bg.use_pass_ambient_occlusion = True
bg.layers = [False] * 10 + [True] + [False] * 9
@staticmethod
def createCollection(context, collection_name):
def collection_in_collection(collection, collection_to_query):
"""Return true if collection is in any of the children or """
"""grandchildren of collection_to_query"""
for child in collection_to_query.children:
if collection == child:
return True
if collection_in_collection(collection, child):
return True
master_collection = context.scene.collection
collection = bpy.data.collections.get(collection_name)
if collection.library:
# We need a local collection instead.
collection = None
if not collection:
collection = bpy.data.collections.new(name=collection_name)
master_collection.children.link(collection)
else:
# see if collection is in the scene
if not collection_in_collection(collection, master_collection):
master_collection.children.link(collection)
def _setupCollections(self, context):
def setup_collection_recursively(collections, collection_name, attr_name):
for collection in collections:
if collection.collection.name == collection_name:
setattr(collection, attr_name, True)
break
else:
setup_collection_recursively(collection.children, collection_name, attr_name)
collection = context.collection
collections = context.scene.collection.children
vlayers = context.scene.view_layers
if len(collections) == 1:
collections[0].name = "foreground"
self.createCollection(context, "foreground")
self.createCollection(context, "background")
# rendersettings
setup_collection_recursively(
vlayers["Foreground"].collections[0].children,
"background",
"holdout")
setup_collection_recursively(
vlayers["Background"].collections[0].children,
"foreground",
"indirect_only")
@staticmethod
def _wipeDefaultNodes(tree):
@ -689,11 +735,11 @@ class CLIP_OT_setup_tracking_scene(Operator):
def _setupNodes(self, context):
if not self._needSetupNodes(context):
# compositor nodes were already setup or even changes already
# do nothing to prevent nodes damage
# Compositor nodes were already setup or even changes already
# do nothing to prevent nodes damage.
return
# Enable backdrop for all compositor spaces
# Enable backdrop for all compositor spaces.
def setup_space(space):
space.show_backdrop = True
@ -709,11 +755,10 @@ class CLIP_OT_setup_tracking_scene(Operator):
need_stabilization = False
# Remove all the nodes if they came from default node setup.
# This is simplest way to make it so final node setup is
# is correct.
# This is simplest way to make it so final node setup is correct.
self._wipeDefaultNodes(tree)
# create nodes
# Create nodes.
rlayer_fg = self._findOrCreateNode(tree, 'CompositorNodeRLayers')
rlayer_bg = tree.nodes.new(type='CompositorNodeRLayers')
composite = self._findOrCreateNode(tree, 'CompositorNodeComposite')
@ -725,16 +770,11 @@ class CLIP_OT_setup_tracking_scene(Operator):
stabilize = tree.nodes.new(type='CompositorNodeStabilize2D')
scale = tree.nodes.new(type='CompositorNodeScale')
invert = tree.nodes.new(type='CompositorNodeInvert')
add_ao = tree.nodes.new(type='CompositorNodeMixRGB')
add_shadow = tree.nodes.new(type='CompositorNodeMixRGB')
mul_shadow = tree.nodes.new(type='CompositorNodeMixRGB')
mul_image = tree.nodes.new(type='CompositorNodeMixRGB')
vector_blur = tree.nodes.new(type='CompositorNodeVecBlur')
shadowcatcher = tree.nodes.new(type='CompositorNodeAlphaOver')
alphaover = tree.nodes.new(type='CompositorNodeAlphaOver')
viewer = tree.nodes.new(type='CompositorNodeViewer')
# setup nodes
# Setup nodes.
movieclip.clip = clip
distortion.clip = clip
@ -751,22 +791,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
rlayer_fg.scene = scene
rlayer_fg.layer = "Foreground"
add_ao.blend_type = 'ADD'
add_ao.show_preview = False
add_shadow.blend_type = 'ADD'
add_shadow.show_preview = False
mul_shadow.blend_type = 'MULTIPLY'
mul_shadow.inputs["Fac"].default_value = 0.8
mul_shadow.show_preview = False
mul_image.blend_type = 'MULTIPLY'
mul_image.inputs["Fac"].default_value = 0.8
mul_image.show_preview = False
vector_blur.factor = 0.75
# create links
# Create links.
tree.links.new(movieclip.outputs["Image"], distortion.inputs["Image"])
if need_stabilization:
@ -776,31 +801,18 @@ class CLIP_OT_setup_tracking_scene(Operator):
else:
tree.links.new(distortion.outputs["Image"], scale.inputs["Image"])
tree.links.new(rlayer_bg.outputs["Alpha"], invert.inputs["Color"])
tree.links.new(scale.outputs["Image"], shadowcatcher.inputs[1])
tree.links.new(invert.outputs["Color"], add_shadow.inputs[1])
tree.links.new(rlayer_bg.outputs["Shadow"], add_shadow.inputs[2])
tree.links.new(rlayer_bg.outputs["Image"], shadowcatcher.inputs[2])
tree.links.new(invert.outputs["Color"], add_ao.inputs[1])
tree.links.new(rlayer_bg.outputs["AO"], add_ao.inputs[2])
tree.links.new(rlayer_fg.outputs["Image"], alphaover.inputs[2])
tree.links.new(add_ao.outputs["Image"], mul_shadow.inputs[1])
tree.links.new(add_shadow.outputs["Image"], mul_shadow.inputs[2])
tree.links.new(scale.outputs["Image"], mul_image.inputs[1])
tree.links.new(mul_shadow.outputs["Image"], mul_image.inputs[2])
tree.links.new(rlayer_fg.outputs["Image"], vector_blur.inputs["Image"])
tree.links.new(rlayer_fg.outputs["Depth"], vector_blur.inputs["Z"])
tree.links.new(rlayer_fg.outputs["Vector"], vector_blur.inputs["Speed"])
tree.links.new(mul_image.outputs["Image"], alphaover.inputs[1])
tree.links.new(vector_blur.outputs["Image"], alphaover.inputs[2])
tree.links.new(shadowcatcher.outputs["Image"], alphaover.inputs[1])
tree.links.new(alphaover.outputs["Image"], composite.inputs["Image"])
tree.links.new(alphaover.outputs["Image"], viewer.inputs["Image"])
# place nodes
# Place nodes.
movieclip.location = Vector((-300.0, 350.0))
distortion.location = movieclip.location
@ -819,42 +831,24 @@ class CLIP_OT_setup_tracking_scene(Operator):
rlayer_bg.location = movieclip.location
rlayer_bg.location -= Vector((0.0, 350.0))
invert.location = rlayer_bg.location
invert.location += Vector((250.0, 50.0))
add_ao.location = invert.location
add_ao.location[0] += 200
add_ao.location[1] = rlayer_bg.location[1]
add_shadow.location = add_ao.location
add_shadow.location -= Vector((0.0, 250.0))
mul_shadow.location = add_ao.location
mul_shadow.location += Vector((200.0, -50.0))
mul_image.location = mul_shadow.location
mul_image.location += Vector((300.0, 200.0))
rlayer_fg.location = rlayer_bg.location
rlayer_fg.location -= Vector((0.0, 500.0))
vector_blur.location[0] = mul_image.location[0]
vector_blur.location[1] = rlayer_fg.location[1]
shadowcatcher.location = scale.location
shadowcatcher.location += Vector((250.0, 0.0))
alphaover.location[0] = vector_blur.location[0] + 350
alphaover.location[1] = \
(vector_blur.location[1] + mul_image.location[1]) / 2
alphaover.location = shadowcatcher.location
alphaover.location += Vector((250.0, -250.0))
composite.location = alphaover.location
composite.location += Vector((200.0, -100.0))
composite.location += Vector((300.0, -100.0))
viewer.location = composite.location
composite.location += Vector((0.0, 200.0))
# ensure no nodes were creates on position of existing node
# Ensure no nodes were created on the position of existing node.
self._offsetNodes(tree)
scene.render.alpha_mode = 'TRANSPARENT'
if hasattr(scene, "cycles"):
scene.cycles.film_transparent = True
@ -910,22 +904,13 @@ class CLIP_OT_setup_tracking_scene(Operator):
return None
@staticmethod
def _mergeLayers(layers_a, layers_b):
return [(layers_a[i] | layers_b[i]) for i in range(len(layers_a))]
@staticmethod
def _createLight(scene):
light = bpy.data.lights.new(name="Light", type='POINT')
lightob = bpy.data.objects.new(name="Light", object_data=light)
scene.objects.link(lightob)
lightob.matrix_local = Matrix.Translation((4.076, 1.005, 5.904))
light.distance = 30
light.shadow_method = 'RAY_SHADOW'
return lightob
def _createSampleObject(self, collection):
@ -941,45 +926,46 @@ class CLIP_OT_setup_tracking_scene(Operator):
return self._createMesh(collection, "Cube", vertices, faces)
def _setupObjects(self, context):
def setup_shadow_catcher_objects(collection):
"""Make all the newly created and the old objects of a collection """ \
"""to be properly setup for shadow catch"""
for ob in collection.objects:
ob.cycles.is_shadow_catcher = True
for child in collection.children:
setup_shadow_catcher_collection(child)
scene = context.scene
collection = context.collection
fg_coll = bpy.data.collections["foreground", None]
bg_coll = bpy.data.collections["background", None]
fg = scene.view_layers.get("Foreground")
bg = scene.view_layers.get("Background")
all_layers = self._mergeLayers(fg.layers, bg.layers)
# ensure all lights are active on foreground and background
# Ensure all lights are active on foreground and background.
has_light = False
has_mesh = False
for ob in scene.objects:
if ob.type == 'LIGHT':
ob.layers = all_layers
has_light = True
elif ob.type == 'MESH' and "is_ground" not in ob:
has_mesh = True
# create sample light if there's no lights in the scene
# Create sample light if there is no lights in the scene.
if not has_light:
light = self._createLight(scene)
light.layers = all_layers
fg_coll.objects.link(light)
bg_coll.objects.link(light)
# create sample object if there's no meshes in the scene
# Create sample object if there's no meshes in the scene.
if not has_mesh:
ob = self._createSampleObject(collection)
ob.layers = fg.layers
ob = self._createSampleObject(fg_coll)
# create ground object if needed
# Create ground object if needed.
ground = self._findGround(context)
if not ground:
ground = self._createGround(collection)
ground.layers = bg.layers
else:
# make sure ground is available on Background layer
ground.layers = self._mergeLayers(ground.layers, bg.layers)
ground = self._createGround(bg_coll)
# layers with background and foreground should be rendered
scene.layers = self._mergeLayers(scene.layers, all_layers)
# And set everything on background layer to shadow catcher.
if hasattr(scene, "cycles"):
self.setup_shadow_catcher_collection(bg_coll)
def execute(self, context):
scene = context.scene
@ -990,13 +976,10 @@ class CLIP_OT_setup_tracking_scene(Operator):
self._setupCamera(context)
self._setupViewport(context)
self._setupViewLayers(context)
self._setupCollections(context)
self._setupNodes(context)
self._setupObjects(context)
# Active layer has probably changed, set it back to the original value.
# NOTE: The active layer is always true.
scene.layers[current_active_layer] = True
return {'FINISHED'}