This repository has been archived by the owner on Sep 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 129
Nuke: Publishing, loading and updating alembic cameras #575
Merged
Merged
Changes from 9 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
0ac12df
feat(nuke): loader plugin for alembic camera
jakubjezek001 9661ece
Merge branch 'feature/565-Nuke_Camera_Loader' into feature/567-Nuke_P…
jakubjezek001 984f815
feat(nuke): remove placeholder file
jakubjezek001 2df5999
feat(nuke): create camera wip
jakubjezek001 8169498
feat(nuke): 3d camera creator
jakubjezek001 7c71db8
feat(nuke): create camera plugin final
jakubjezek001 9be1039
feat(nuke): exctractor plugin for camera abs (presets can do fbx)
jakubjezek001 dce6ab4
fix(nuke): loader was too strict for properties frame start/and
jakubjezek001 2c693dc
Merge branch 'feature/565-Nuke_Camera_Loader' into feature/567-Nuke_P…
jakubjezek001 d6c6f49
Merge branch '2.x/develop' into feature/567-Nuke_Publish_Camera
jakubjezek001 e435b96
fix(nuke): nukes bug workaround animation keys
jakubjezek001 922ec77
fix(nuke): repair workaround node position and name
jakubjezek001 b6388d3
feat(nuke): adding update and remove actions
jakubjezek001 dc81f5d
fix(nuke): missing arguments to data imprint
jakubjezek001 ac0ef2a
clean(nuke): spaces
jakubjezek001 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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.