Skip to content

Conversation

@rhdutta
Copy link

@rhdutta rhdutta commented Sep 4, 2025

Changelog Description

Add project-level default for render farm submission with per-publish override. A new Render on Farm project setting controls the default (True by default). Artists can override on publish via a new farm creator attribute to choose local vs farm rendering.

Additional review information

  • Files changed:
    • ayon-blender/server/settings/render_settings.py
      • Added RenderSettingsModel.farm_default: bool (default True ).
      • UI label updated to “Render on Farm”; description clarifies default behavior.
    • ayon-blender/client/ayon_blender/plugins/create/create_render.py
      • Added creator attribute farm (BoolDef) to instance attributes.
      • Default derives from project_settings["RenderSettings"]["farm_default"].
    • ayon-blender/client/ayon_blender/plugins/publish/collect_render.py
      • Reads creator_attributes.farm → sets instance.data["farm"].
      • families: always includes render; includes render.farm only when farm is True.
  • Behavior:
    • Managers set default render mode per project: local (False) or farm (True).
    • Artists can override per publish by toggling farm.
    • ExtractLocalRender already skips when instance.data["farm"] is True; runs when False.
  • Backward compatibility:
    • Default remains Farm rendering (True) if no setting present.
    • Existing scenes benefit automatically; no schema breaks.

Testing notes:

  1. In AYON Server settings, navigate to Blender → Render Settings and toggle Render on Farm (default True ).
  2. In Blender, create a new Render instance.
    • Verify the creator UI shows a farm toggle defaulting to the project setting.
  3. Publish with farm=False:
    • Expect local frames to render; ExtractLocalRender logs “Rendering animation locally…”.
    • instance.data["farm"] is False; families contains ["render"] only.
  4. Publish with farm=True (override in the creator UI):
    • Local extractor is skipped; log shows “Instance marked farm=True; skipping local render.”
    • instance.data["farm"] is True; families contains ["render", "render.farm"].

@rhdutta rhdutta changed the title Blender: Add project render mode (Local vs Farm, default Local) & per-publish toggle Blender: Add project render mode (Local vs Farm, default Farm) & per-publish toggle Sep 4, 2025
@BigRoy BigRoy requested review from BigRoy and moonyuet September 4, 2025 20:55
@BigRoy BigRoy self-assigned this Sep 4, 2025
@BigRoy BigRoy added type: enhancement Improvement of existing functionality or minor addition community Issues and PRs coming from the community members labels Sep 4, 2025
@BigRoy BigRoy requested a review from LiborBatek September 4, 2025 20:56
rdutta added 2 commits September 4, 2025 22:02
…locally' into feature/ENG-3087/blender_render_locally

# Conflicts:
#	client/ayon_blender/plugins/create/create_render.py

label = "Extract Local Render"
hosts = ["blender"]
families = ["render"]
Copy link
Member

Choose a reason for hiding this comment

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

maybe we can add a collector for this families, and this can be changed to:

Suggested change
families = ["render"]
families = ["render.local"]

Comment on lines +65 to +70
representations.append({
"name": ext,
"ext": ext,
"files": [os.path.basename(f) for f in files],
"stagingDir": dirpath,
})
Copy link
Member

Choose a reason for hiding this comment

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

Do you have some specific templates for this local rendering implementation? Asking this, as it would probably just take the last set of the representations transmitted into the published folder.

I guess it would be safe by creating instances per Aov and published and then put each instance into the same product group(e.g. aov_instance.data["productGroup"]="YourRenderGroup", as if we did in substance painter.
The other ways I could think of is to add outputName being part of the representation data and that outputName could be Aov name or we can use aov name as "name" in the representation data except for the beauty. But these two ways are not as innovative as creating instance per aov. Thought? @BigRoy @antirotor

Copy link
Contributor

@BigRoy BigRoy Sep 5, 2025

Choose a reason for hiding this comment

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

Do you have some specific templates for this local rendering implementation? Asking this, as it would probably just take the last set of the representations transmitted into the published folder.

I guess it would be safe by creating instances per Aov and published and then put each instance into the same product group(e.g. aov_instance.data["productGroup"]="YourRenderGroup", as if we did in substance painter.

Each AOV would need its own instance and product - yes.
They should not become representations of the one instance, furthermore... they should behave exactly like a farm render.

Copy link
Author

@rhdutta rhdutta Sep 5, 2025

Choose a reason for hiding this comment

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

Forgive me as I'm quite new to Blender and Ayon, and I'm not entirely clear on this review. The usecase I implemented wasn't concerned with AOVs, but I agree support for them is a good idea. I tried looking at the Substance repo but did not see the AOV instance implementation there. Can i get some clarification on how to go about this? Is there an example I can reference, or is someone able to assist? @BigRoy @moonyuet @antirotor

Copy link
Member

Choose a reason for hiding this comment

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

@rhdutta you can take reference from this pesudo-code but it would be much safer to have implemented the collector(something like collect_render_local for creating all these instances.

import os
import ayon_api
from ayon_core.pipeline.create import get_product_name

context = instance.context
project_name = context.data["projectName"]
folder_entity = ayon_api.get_folder_by_path(
    project_name,
    instance.data["folderPath"]
)
task_name = instance.data.get("task")
task_entity = None
if folder_entity and task_name:
    task_entity = ayon_api.get_task_by_name(
        project_name, folder_entity["id"], task_name
    )
task_name = task_type = None
if task_entity:
    task_name = task_entity["name"]
    task_type = task_entity["taskType"]

# Collect expected files by AOV
expected = instance.data.get("expectedFiles", [])

for aov, files in expected.items():
    suffix = f"_{aov}"
    first = files[0]
    dirpath = os.path.dirname(first)
    ext = os.path.splitext(first)[1].lstrip(".").lower() or "exr"
    # TODO: The product type actually isn't 'texture' currently but
    #   for now this is only done so the product name starts with
    #   'texture'
    render_product_name = get_product_name(
        project_name=context.data["projectName"],
        task_name=task_name,
        task_type=task_type,
        host_name=context.data["hostName"],
        product_type="render",
        variant=instance.data["variant"] + suffix,
        project_settings=context.data["project_settings"]
    )
    render_product_group_name = get_product_name(
        project_name=context.data["projectName"],
        task_name=task_name,
        task_type=task_type,
        host_name=context.data["hostName"],
        product_type="render",
        variant=instance.data["variant"],
        project_settings=context.data["project_settings"]
    )

    # Prepare representation
    representation = {
        "name": ext.lstrip("."),
        "ext": ext.lstrip("."),
        "files": [os.path.basename(file) for file in files]
    }

    representation["tags"] = ["review"]
    representation["stagingDir"] = dirpath
    # Clone the instance
    product_type = "image"
    render_instance = context.create_instance(render_product_name)
    render_instance[:] = instance[:]
    render_instance.data.update(copy.deepcopy(dict(instance.data)))
    render_instance.data["name"] = render_product_name
    render_instance.data["label"] = render_product_name
    render_instance.data["productName"] = render_product_name
    render_instance.data["productType"] = product_type
    render_instance.data["family"] = product_type
    render_instance.data["families"] = [product_type]
    # add review as families when marked as reviewables enabled.
    if instance.data["creator_attributes"].get("review"):
        render_instance.data["families"].append("review")

    render_instance.data["representations"] = [representation]

    # Group the textures together in the loader
    render_instance.data["productGroup"] = render_product_group_name
    # colorspace data
    ocio_path: str = os.getenv("OCIO", "")
    display: str = bpy.context.scene.display_settings.display_device
    view: str = bpy.context.scene.view_settings.view_transform
    render_instance.data["colorspace"] = {
            "colorspaceConfig": ocio_path,
            "colorspaceDisplay": display,
            "colorspaceView": view,
        }

rdutta and others added 6 commits September 5, 2025 18:07
Co-authored-by: Kayla Man <64118225+moonyuet@users.noreply.github.com>
…Halon-Entertainment/ayon-blender into feature/ENG-3087/blender_render_locally

Change from ynput review
@LiborBatek
Copy link
Member

@rhdutta any news?
...would be actually nice to make this happen some time...pretty useful feature! cheers

@rhdutta
Copy link
Author

rhdutta commented Oct 27, 2025

@LiborBatek Unfortunately I've had to move on to other pressing matters and have not had the cycles to revisit this.

If there's any way to hand this off that would probably be best, otherwise I will try and get back to it in the weeks ahead.


families = ["render"]
if farm_enabled:
families.append("render.farm")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
families.append("render.farm")
families.append("render.farm")
else:
families.append("render.local")

@BigRoy
Copy link
Contributor

BigRoy commented Dec 10, 2025

Closing this in favor of #217

@BigRoy BigRoy closed this Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Issues and PRs coming from the community members type: enhancement Improvement of existing functionality or minor addition

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants