Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Nuke: Publishing, loading and updating alembic cameras #575

Merged
merged 15 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions pype/plugins/nuke/create/create_camera

This file was deleted.

53 changes: 53 additions & 0 deletions pype/plugins/nuke/create/create_camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import avalon.nuke
from avalon.nuke import lib as anlib
import nuke


class CreateCamera(avalon.nuke.Creator):
"""Add Publishable Backdrop"""

name = "camera"
label = "Create 3d Camera"
family = "camera"
icon = "camera"
defaults = ["Main"]

def __init__(self, *args, **kwargs):
super(CreateCamera, self).__init__(*args, **kwargs)
self.nodes = nuke.selectedNodes()
self.node_color = "0xff9100ff"
return

def process(self):
nodes = list()
if (self.options or {}).get("useSelection"):
nodes = self.nodes

if len(nodes) >= 1:
# loop selected nodes
for n in nodes:
data = self.data.copy()
if len(nodes) > 1:
# rename subset name only if more
# then one node are selected
subset = self.family + n["name"].value().capitalize()
data["subset"] = subset

# change node color
n["tile_color"].setValue(int(self.node_color, 16))
# add avalon knobs
anlib.imprint(n, data)
return True
else:
msg = str("Please select nodes you "
"wish to add to a container")
self.log.error(msg)
nuke.message(msg)
return
else:
# if selected is off then create one node
camera_node = nuke.createNode("Camera2")
camera_node["tile_color"].setValue(int(self.node_color, 16))
# add avalon knobs
instance = anlib.imprint(camera_node, self.data)
return instance
66 changes: 66 additions & 0 deletions pype/plugins/nuke/load/load_camera_abc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from avalon import api
import nuke
from pprint import pformat

class AlembicCameraLoader(api.Loader):
"""
This will load alembic camera into script.
"""

families = ["camera"]
representations = ["abc"]

label = "Load Alembic Camera"
icon = "camera"
color = "orange"

def load(self, context, name, namespace, data):

# import dependencies
from avalon.nuke import containerise

# get main variables
version = context['version']
version_data = version.get("data", {})
vname = version.get("name", None)
first = version_data.get("frameStart", None)
last = version_data.get("frameEnd", None)
fps = version_data.get("fps") or nuke.root()["fps"].getValue()
namespace = namespace or context['asset']['name']
object_name = "{}_{}".format(name, namespace)

# prepare data for imprinting
# add additional metadata from the version to imprint to Avalon knob
add_keys = ["source", "author", "fps"]

data_imprint = {"frameStart": first,
"frameEnd": last,
"version": vname,
"objectName": object_name}

for k in add_keys:
data_imprint.update({k: version_data[k]})

# getting file path
file = self.fname.replace("\\", "/")

camera_node = nuke.createNode(
"Camera2",
"file {} read_from_file True".format(file),
inpanel=False
)
camera_node.forceValidate()
# camera_node["read_from_file"].setValue(True)
# camera_node["file"].setValue(file)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if these lines are not needed let's remove them.

camera_node["frame_rate"].setValue(float(fps))
camera_node["tile_color"].setValue(int("0x3469ffff", 16))

camera_node["reload"].execute()

return containerise(
node=camera_node,
name=name,
namespace=namespace,
context=context,
loader=self.__class__.__name__,
data=data_imprint)
1 change: 0 additions & 1 deletion pype/plugins/nuke/publish/collect_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ def process(self, context):

families.append(family)


# except disabled nodes but exclude backdrops in test
if ("nukenodes" not in family) and (node["disable"].value()):
continue
Expand Down
185 changes: 185 additions & 0 deletions pype/plugins/nuke/publish/extract_camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import nuke
import os
import math
import pyblish.api
import pype.api
from avalon.nuke import lib as anlib
from pprint import pformat


class ExtractCamera(pype.api.Extractor):
""" 3D camera exctractor
"""
label = 'Exctract Camera'
order = pyblish.api.ExtractorOrder
families = ["camera"]
hosts = ["nuke"]

# presets
write_geo_knobs = [
("file_type", "abc"),
("storageFormat", "Ogawa"),
("writeGeometries", False),
("writePointClouds", False),
("writeAxes", False)
]

def process(self, instance):
handle_start = instance.context.data["handleStart"]
handle_end = instance.context.data["handleEnd"]
first_frame = int(nuke.root()["first_frame"].getValue())
last_frame = int(nuke.root()["last_frame"].getValue())
step = 1
output_range = str(nuke.FrameRange(first_frame, last_frame, step))

self.log.info("instance.data: `{}`".format(
pformat(instance.data)))

rm_nodes = list()
self.log.info("Crating additional nodes")
subset = instance.data["subset"]
staging_dir = self.staging_dir(instance)

# get extension form preset
extension = next((k[1] for k in self.write_geo_knobs
if k[0] == "file_type"), None)
if not extension:
raise RuntimeError(
"Bad config for extension in presets. "
"Talk to your supervisor or pipeline admin")

# create file name and path
filename = subset + ".{}".format(extension)
file_path = os.path.join(staging_dir, filename).replace("\\", "/")

with anlib.maintained_selection():
# bake camera with axeses onto word coordinate XYZ
rm_n = bakeCameraWithAxeses(
nuke.toNode(instance.data["name"]), output_range)
rm_nodes.append(rm_n)

# create scene node
rm_n = nuke.createNode("Scene")
rm_nodes.append(rm_n)

# create write geo node
wg_n = nuke.createNode("WriteGeo")
wg_n["file"].setValue(file_path)
# add path to write to
for k, v in self.write_geo_knobs:
wg_n[k].setValue(v)
rm_nodes.append(wg_n)

# write out camera
nuke.execute(
wg_n,
int(first_frame),
int(last_frame)
)
# erase additional nodes
for n in rm_nodes:
nuke.delete(n)

self.log.info(file_path)

# create representation data
if "representations" not in instance.data:
instance.data["representations"] = []

representation = {
'name': extension,
'ext': extension,
'files': filename,
"stagingDir": staging_dir,
"frameStart": first_frame,
"frameEnd": last_frame
}
instance.data["representations"].append(representation)

instance.data.update({
"path": file_path,
"outputDir": staging_dir,
"ext": extension,
"handleStart": handle_start,
"handleEnd": handle_end,
"frameStart": first_frame + handle_start,
"frameEnd": last_frame - handle_end,
"frameStartHandle": first_frame,
"frameEndHandle": last_frame,
})

self.log.info("Extracted instance '{0}' to: {1}".format(
instance.name, file_path))


def bakeCameraWithAxeses(camera_node, output_range):
""" Baking all perent hiearchy of axeses into camera
with transposition onto word XYZ coordinance
"""
bakeFocal = False
bakeHaperture = False
bakeVaperture = False

camera_matrix = camera_node['world_matrix']

new_cam_n = nuke.createNode("Camera2")
new_cam_n.setInput(0, None)
new_cam_n['rotate'].setAnimated()
new_cam_n['translate'].setAnimated()

old_focal = camera_node['focal']
if old_focal.isAnimated() and not (old_focal.animation(0).constant()):
new_cam_n['focal'].setAnimated()
bakeFocal = True
else:
new_cam_n['focal'].setValue(old_focal.value())

old_haperture = camera_node['haperture']
if old_haperture.isAnimated() and not (
old_haperture.animation(0).constant()):
new_cam_n['haperture'].setAnimated()
bakeHaperture = True
else:
new_cam_n['haperture'].setValue(old_haperture.value())

old_vaperture = camera_node['vaperture']
if old_vaperture.isAnimated() and not (
old_vaperture.animation(0).constant()):
new_cam_n['vaperture'].setAnimated()
bakeVaperture = True
else:
new_cam_n['vaperture'].setValue(old_vaperture.value())

new_cam_n['win_translate'].setValue(camera_node['win_translate'].value())
new_cam_n['win_scale'].setValue(camera_node['win_scale'].value())

for x in nuke.FrameRange(output_range):
math_matrix = nuke.math.Matrix4()
for y in range(camera_matrix.height()):
for z in range(camera_matrix.width()):
matrix_pointer = z + (y * camera_matrix.width())
math_matrix[matrix_pointer] = camera_matrix.getValueAt(
x, (y + (z * camera_matrix.width())))

rot_matrix = nuke.math.Matrix4(math_matrix)
rot_matrix.rotationOnly()
rot = rot_matrix.rotationsZXY()

new_cam_n['rotate'].setValueAt(math.degrees(rot[0]), x, 0)
new_cam_n['rotate'].setValueAt(math.degrees(rot[1]), x, 1)
new_cam_n['rotate'].setValueAt(math.degrees(rot[2]), x, 2)
new_cam_n['translate'].setValueAt(
camera_matrix.getValueAt(x, 3), x, 0)
new_cam_n['translate'].setValueAt(
camera_matrix.getValueAt(x, 7), x, 1)
new_cam_n['translate'].setValueAt(
camera_matrix.getValueAt(x, 11), x, 2)

if bakeFocal:
new_cam_n['focal'].setValueAt(old_focal.getValueAt(x), x)
if bakeHaperture:
new_cam_n['haperture'].setValueAt(old_haperture.getValueAt(x), x)
if bakeVaperture:
new_cam_n['vaperture'].setValueAt(old_vaperture.getValueAt(x), x)

return new_cam_n