Project hierarchy variables as environment variables inside houdini

Hi,

image

Can I read the (annotated in image) as an environment variable inside Houdini? I need it to create a path and save my caches in the file caches node.

You can get the asset sh_headexplosion but not the hierarchy Teaser atm. Here are some environment variables that might be interesting;

AVALON_PROJECT = toke_testing
AVALON_ASSET = OP_5265_custom_staging_dir
AVALON_TASK = animation
AVALON_APP_NAME = maya/2023
AVALON_APP = maya
AVALON_WORKDIR = P:\PROJECTS\toke_testing\OP_5265_custom_staging_dir\work\animation

You could also make a pre-launch hook and fetch the hierarchy and do any custom manipulation of the hierarchy, but since the hierarchy is dynamic it would be very tricky to isolate something like a sequence without it being studio specific code.

@fabiaserra Didn’t you set up a prelaunch hook and task change callback to track the hierarchy?

1 Like

I did! I never created a PR for it as I was told it wasn’t going to be merged but I can create one if there’s interest? I basically added this function on pipeline.context_tools:

def get_hierarchy_env(project_doc, asset_doc, skip_empty=True):
    """Returns an environment dictionary based on the hierarchy of an asset in a project

    The environment dictionary contains keys representing the different levels of the
    visual hierarchy (e.g. "SHOW", "SEASON", "EPISODE", etc.) and their corresponding
    values, if available.

    Args:
        project_doc (dict): A dictionary containing metadata about the project.
        asset_doc (dict): A dictionary containing metadata about the asset.
        skip_empty (bool): Whether to skip env entries that we don't have a value for.

    Returns:
        dict: An environment dictionary with keys "SHOW", "SEASON", "EPISODE", "SEQ",
            "SHOT", and "ASSET_TYPE". The values of the keys are the names of the
            corresponding entities in the hierarchy. If an entity is not present in the
            hierarchy, its corresponding key will not be present or have a value of None
            if 'skip_empty' is set to False.

    """
    visual_hierarchy = [asset_doc]
    current_doc = asset_doc
    project_name = project_doc["name"]
    while True:
        visual_parent_id = current_doc["data"]["visualParent"]
        visual_parent = None
        if visual_parent_id:
            visual_parent = get_asset_by_id(project_name, visual_parent_id)

        if not visual_parent:
            break

        visual_hierarchy.append(visual_parent)
        current_doc = visual_parent

    # Dictionary that maps the SG entity names from SG-leecher to their corresponding
    # environment variables
    sg_to_env_map = {
        "Project": "SHOW",
        "Season": "SEASON",
        "Episode": "EPISODE",
        "Sequence": "SEQ",
        "Shot": "SHOT",
    }

    # We create a default env with None values so when we switch context, we can remove
    # the environment variables that aren't defined
    env = {
        "SHOW": project_doc["data"]["code"],
        "SEASON": None,
        "EPISODE": None,
        "SEQ": None,
        "SHOT": None,
        "ASSET_TYPE": None,
    }

    # For each entity on the hierarchy, we set its environment variable
    for parent in visual_hierarchy:
        sg_entity_type = parent["data"]["sgEntityType"]
        env_key = sg_to_env_map.get(sg_entity_type)
        if env_key:
            env[env_key] = parent["name"]

    # Remove empty values from env if 'skip_empty' is set to True
    if skip_empty:
        env = {key: value for key, value in env.items() if value is not None}

    return env

And I use it in:

  • applications.prepare_context_environments:
...
    app = data["app"]
    context_env = {
        "AVALON_PROJECT": project_doc["name"],
        "AVALON_ASSET": asset_doc["name"],
        "AVALON_TASK": task_name,
        "AVALON_APP_NAME": app.full_name
    }

    ### Starts Alkemy-X Override ###
    # Get hierarchy environment variables (i.e., SEASON, SHOW, SEQ...)
    context_env.update(get_hierarchy_env(project_doc, asset_doc))
    ### Ends Alkemy-X Override ###
  • context_tools.change_current_context:
...
    # Update the Session and environments. Pop from environments all keys with
    # value set to None.
    for key, value in changes.items():
        legacy_io.Session[key] = value
        if value is None:
            os.environ.pop(key, None)
        else:
            os.environ[key] = value

    ### Starts Alkemy-X Override ###
    # Calculate the hierarchy environment and update
    project_doc = get_project(legacy_io.Session["AVALON_PROJECT"])
    hierarchy_env = get_hierarchy_env(project_doc, asset_doc, skip_empty=False)
    for key, value in hierarchy_env.items():
        if value is None:
            os.environ.pop(key, None)
        else:
            os.environ[key] = value
    ### Ends Alkemy-X Override ###
1 Like

Oh of course and I’m realizing now that that contains some things most studios won’t have, we are adding sgEntityType to our OP assets (that are always coming from Shotgrid) to clearly distinguish what type of entity it is. Before having that field I was inferring the entities based on the number of nested levels but this is way more robust

Just adding another opinion here: If we can get the resolutions from project settings as an env variable, we can lock that directly inside ROP’s nodes. So it always renders correctly through the pipeline. I’ve seen this trick in one of the big studios in Los Angeles.

I like the idea, but I’m a bit worried that potentially on the farm the value might evaluate to something else (potentially mid-render in a sequence) than intended if the resolution of the asset gets updated in the meantime.

I understand. We can ‘submit a scene file’ for rendering, so the value doesn’t change when we change the value, even during the render time. Correct me If I’m wrong.

It’s becoming tough to change the camera resolutions for all shots; the camera resolution values also change when updating the asset. Every change is manual work; sometimes, artists forget and launch renders. It’s one of the significant problems we face in our studio.

IMO we can make it possible to export as a variable and bind inside the Houdini node. I think no one will change the resolution of the project. We initially lock the values when creating shots in OP.

Was this MPC/Mill ? :slight_smile: But yeah we did that there and to @BigRoy’s point on the farm worries we submitted the env var values on the farm job so it wouldn’t be live

I think I’ve seen it at Zoic. It would be great and easy to handle If we could get camera resolutions as environment variables.