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

Bugfix: houdini switching context doesnt update variables #5651

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a352a64
add JOB path houdini setting
MustafaJafar Sep 25, 2023
fef45ce
implement get_current_context_template_data function
MustafaJafar Sep 25, 2023
59a20fe
implement validate_job_path and register it in houdini callbacks
MustafaJafar Sep 25, 2023
fdea715
resolve hound
MustafaJafar Sep 25, 2023
d1395fe
update settings names
MustafaJafar Sep 26, 2023
30e2ecb
BigRoy's comment
MustafaJafar Sep 26, 2023
fd8daeb
update log message
MustafaJafar Sep 26, 2023
a349733
sync $JOB and [JOB]
MustafaJafar Sep 26, 2023
f15dcb3
create JOB folder if not exists
MustafaJafar Sep 27, 2023
edcaa8b
update docs
MustafaJafar Sep 27, 2023
ef785e7
update os.makedirs
MustafaJafar Sep 27, 2023
a3cb6c4
resolve hound
MustafaJafar Sep 27, 2023
05cef1e
Minikiu comments
MustafaJafar Sep 27, 2023
260650e
update docs
MustafaJafar Sep 27, 2023
346544d
update docs 2
MustafaJafar Sep 27, 2023
67964be
fix format
MustafaJafar Sep 27, 2023
61ce75f
BigRoy's comment
MustafaJafar Sep 27, 2023
7197134
Allow adding more Houdini vars
MustafaJafar Sep 27, 2023
d8715d5
allow values other than paths
MustafaJafar Sep 29, 2023
b93da3b
resolve hound
MustafaJafar Sep 29, 2023
a4d55b4
update docs and rename `isPath` to `is Dir Path`
MustafaJafar Sep 29, 2023
b45e8c3
update photo
MustafaJafar Sep 29, 2023
2af9783
avoid using nested if
MustafaJafar Sep 29, 2023
82b2bd4
update labels and add settings tips
MustafaJafar Sep 29, 2023
7816c03
Big Roy's comment
MustafaJafar Sep 29, 2023
336517a
Merge branch 'develop' into bugfix/OP-4326_Houdini-switching-context-…
MustafaJafar Sep 29, 2023
e6585e8
update docs
MustafaJafar Sep 29, 2023
e75dc71
update docs
MustafaJafar Sep 29, 2023
b1e77ac
Merge branch 'develop' into bugfix/OP-4326_Houdini-switching-context-…
MustafaJafar Oct 4, 2023
d7dcc38
display changes in menu, add menu button
MustafaJafar Oct 5, 2023
809b6df
resolve hound
MustafaJafar Oct 5, 2023
35194b5
resolve hound 2
MustafaJafar Oct 5, 2023
0af1b58
resolve hound 3
MustafaJafar Oct 5, 2023
31d7793
print message to user if nothing to change
MustafaJafar Oct 5, 2023
c6b370b
BigRoy's comments
MustafaJafar Oct 5, 2023
8f0b182
update printed message
MustafaJafar Oct 5, 2023
5b04af7
remove leading and trailing whitespaces from vars
MustafaJafar Oct 5, 2023
7c5d149
use different popup
MustafaJafar Oct 6, 2023
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
108 changes: 104 additions & 4 deletions openpype/hosts/houdini/api/lib.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import sys
import os
import errno
import re
import uuid
import logging
Expand All @@ -9,10 +10,15 @@

import six

from openpype.lib import StringTemplate
from openpype.client import get_asset_by_name
from openpype.settings import get_current_project_settings
from openpype.pipeline import get_current_project_name, get_current_asset_name
from openpype.pipeline.context_tools import get_current_project_asset

from openpype.pipeline.context_tools import (
get_current_context_template_data,
get_current_project_asset
)
from openpype.widgets import popup
import hou


Expand Down Expand Up @@ -160,8 +166,6 @@ def validate_fps():

if current_fps != fps:

from openpype.widgets import popup

# Find main window
parent = hou.ui.mainQtWindow()
if parent is None:
Expand Down Expand Up @@ -747,3 +751,99 @@ def get_camera_from_container(container):

assert len(cameras) == 1, "Camera instance must have only one camera"
return cameras[0]


def get_context_var_changes():
"""get context var changes."""

houdini_vars_to_update = {}

project_settings = get_current_project_settings()
houdini_vars_settings = \
project_settings["houdini"]["general"]["update_houdini_var_context"]

if not houdini_vars_settings["enabled"]:
return houdini_vars_to_update

houdini_vars = houdini_vars_settings["houdini_vars"]

# No vars specified - nothing to do
if not houdini_vars:
return houdini_vars_to_update

# Get Template data
template_data = get_current_context_template_data()

# Set Houdini Vars
for item in houdini_vars:
# For consistency reasons we always force all vars to be uppercase
# Also remove any leading, and trailing whitespaces.
var = item["var"].strip().upper()

# get and resolve template in value
item_value = StringTemplate.format_template(
item["value"],
template_data
)

if var == "JOB" and item_value == "":
# sync $JOB to $HIP if $JOB is empty
item_value = os.environ["HIP"]

if item["is_directory"]:
item_value = item_value.replace("\\", "/")

current_value = hou.hscript("echo -n `${}`".format(var))[0]

if current_value != item_value:
houdini_vars_to_update[var] = (
current_value, item_value, item["is_directory"]
)

return houdini_vars_to_update


def update_houdini_vars_context():
"""Update asset context variables"""

for var, (_old, new, is_directory) in get_context_var_changes().items():
if is_directory:
try:
os.makedirs(new)
except OSError as e:
if e.errno != errno.EEXIST:
print(
"Failed to create ${} dir. Maybe due to "
"insufficient permissions.".format(var)
)

hou.hscript("set {}={}".format(var, new))
os.environ[var] = new
print("Updated ${} to {}".format(var, new))


def update_houdini_vars_context_dialog():
"""Show pop-up to update asset context variables"""
update_vars = get_context_var_changes()
if not update_vars:
# Nothing to change
print("Nothing to change, Houdini vars are already up to date.")
return

message = "\n".join(
"${}: {} -> {}".format(var, old or "None", new or "None")
for var, (old, new, _is_directory) in update_vars.items()
)

# TODO: Use better UI!
parent = hou.ui.mainQtWindow()
dialog = popup.Popup(parent=parent)
dialog.setModal(True)
dialog.setWindowTitle("Houdini scene has outdated asset variables")
dialog.setMessage(message)
dialog.setButtonText("Fix")

# on_show is the Fix button clicked callback
dialog.on_clicked.connect(update_houdini_vars_context)

dialog.show()
7 changes: 7 additions & 0 deletions openpype/hosts/houdini/api/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ def on_save():

log.info("Running callback on save..")

# update houdini vars
lib.update_houdini_vars_context_dialog()

nodes = lib.get_id_required_nodes()
for node, new_id in lib.generate_ids(nodes):
lib.set_id(node, new_id, overwrite=False)
Expand Down Expand Up @@ -335,6 +338,9 @@ def on_open():

log.info("Running callback on open..")

# update houdini vars
lib.update_houdini_vars_context_dialog()

# Validate FPS after update_task_from_path to
# ensure it is using correct FPS for the asset
lib.validate_fps()
Expand Down Expand Up @@ -399,6 +405,7 @@ def _set_context_settings():
"""

lib.reset_framerange()
lib.update_houdini_vars_context()


def on_pyblish_instance_toggled(instance, new_value, old_value):
Expand Down
8 changes: 8 additions & 0 deletions openpype/hosts/houdini/startup/MainMenuCommon.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ openpype.hosts.houdini.api.lib.reset_framerange()
]]></scriptCode>
</scriptItem>

<scriptItem id="update_context_vars">
<label>Update Houdini Vars</label>
<scriptCode><![CDATA[
import openpype.hosts.houdini.api.lib
openpype.hosts.houdini.api.lib.update_houdini_vars_context_dialog()
]]></scriptCode>
</scriptItem>

<separatorItem/>
<scriptItem id="experimental_tools">
<label>Experimental tools...</label>
Expand Down
72 changes: 71 additions & 1 deletion openpype/pipeline/context_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@

from .publish.lib import filter_pyblish_plugins
from .anatomy import Anatomy
from .template_data import get_template_data_with_names
from .template_data import (
get_template_data_with_names,
get_template_data
)
from .workfile import (
get_workfile_template_key,
get_custom_workfile_template_by_string_context,
Expand Down Expand Up @@ -658,3 +661,70 @@ def get_process_id():
if _process_id is None:
_process_id = str(uuid.uuid4())
return _process_id


def get_current_context_template_data():
"""Template data for template fill from current context

Returns:
Dict[str, Any] of the following tokens and their values
Supported Tokens:
- Regular Tokens
- app
- user
- asset
- parent
- hierarchy
- folder[name]
- root[work, ...]
- studio[code, name]
- project[code, name]
- task[type, name, short]

- Context Specific Tokens
- assetData[frameStart]
- assetData[frameEnd]
- assetData[handleStart]
- assetData[handleEnd]
- assetData[frameStartHandle]
- assetData[frameEndHandle]
- assetData[resolutionHeight]
- assetData[resolutionWidth]

"""

# pre-prepare get_template_data args
current_context = get_current_context()
project_name = current_context["project_name"]
asset_name = current_context["asset_name"]
anatomy = Anatomy(project_name)

# prepare get_template_data args
project_doc = get_project(project_name)
asset_doc = get_asset_by_name(project_name, asset_name)
task_name = current_context["task_name"]
host_name = get_current_host_name()

# get regular template data
template_data = get_template_data(
project_doc, asset_doc, task_name, host_name
)

template_data["root"] = anatomy.roots

# get context specific vars
asset_data = asset_doc["data"].copy()
Minkiu marked this conversation as resolved.
Show resolved Hide resolved

# compute `frameStartHandle` and `frameEndHandle`
if "frameStart" in asset_data and "handleStart" in asset_data:
MustafaJafar marked this conversation as resolved.
Show resolved Hide resolved
asset_data["frameStartHandle"] = \
asset_data["frameStart"] - asset_data["handleStart"]

if "frameEnd" in asset_data and "handleEnd" in asset_data:
asset_data["frameEndHandle"] = \
asset_data["frameEnd"] + asset_data["handleEnd"]

# add assetData
template_data["assetData"] = asset_data

return template_data
12 changes: 12 additions & 0 deletions openpype/settings/defaults/project_settings/houdini.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
{
"general": {
"update_houdini_var_context": {
"enabled": true,
"houdini_vars":[
{
"var": "JOB",
"value": "{root[work]}/{project[name]}/{hierarchy}/{asset}/work/{task[name]}",
"is_directory": true
}
]
}
},
"imageio": {
"activate_host_color_management": true,
"ocio_config": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"label": "Houdini",
"is_file": true,
"children": [
{
"type": "schema",
"name": "schema_houdini_general"
},
{
"key": "imageio",
"type": "dict",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"type": "dict",
"key": "general",
"label": "General",
"collapsible": true,
"is_group": true,
"children": [
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "update_houdini_var_context",
"label": "Update Houdini Vars on context change",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "label",
"label": "Sync vars with context changes.<br>If a value is treated as a directory on update it will be ensured the folder exists"
},
{
"type": "list",
"key": "houdini_vars",
"label": "Houdini Vars",
"collapsible": false,
"object_type": {
"type": "dict",
"children": [
{
"type": "text",
"key": "var",
"label": "Var"
},
{
"type": "text",
"key": "value",
"label": "Value"
},
{
"type": "boolean",
"key": "is_directory",
"label": "Treat as directory"
}
]
}
}
]
}
]
}
45 changes: 45 additions & 0 deletions server_addon/houdini/server/settings/general.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from pydantic import Field
from ayon_server.settings import BaseSettingsModel


class HoudiniVarModel(BaseSettingsModel):
_layout = "expanded"
var: str = Field("", title="Var")
value: str = Field("", title="Value")
is_directory: bool = Field(False, title="Treat as directory")


class UpdateHoudiniVarcontextModel(BaseSettingsModel):
"""Sync vars with context changes.

If a value is treated as a directory on update
it will be ensured the folder exists.
"""

enabled: bool = Field(title="Enabled")
# TODO this was dynamic dictionary '{var: path}'
houdini_vars: list[HoudiniVarModel] = Field(
default_factory=list,
title="Houdini Vars"
)


class GeneralSettingsModel(BaseSettingsModel):
update_houdini_var_context: UpdateHoudiniVarcontextModel = Field(
default_factory=UpdateHoudiniVarcontextModel,
title="Update Houdini Vars on context change"
)


DEFAULT_GENERAL_SETTINGS = {
"update_houdini_var_context": {
"enabled": True,
"houdini_vars": [
{
"var": "JOB",
"value": "{root[work]}/{project[name]}/{hierarchy}/{asset}/work/{task[name]}", # noqa
"is_directory": True
}
]
}
}
Loading
Loading