-
Notifications
You must be signed in to change notification settings - Fork 129
Maya looks: support for native Redshift texture format #2971
Maya looks: support for native Redshift texture format #2971
Conversation
cmd = [ | ||
texture_processor_path, | ||
escape_space(source), | ||
|
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.
He's right
str: Output of `redshiftTextureProcessor` command. | ||
|
||
""" | ||
if "REDSHIFT_COREDATAPATH" not in os.environ: |
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.
Note: I think we should validate this environment during validation, only when is needed if it's possible to know.
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.
Ah, I see! Thank you, I'll take a look about moving that
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.
That's something I don't know. Maybe it's not needed or impossible to validate before this plugin, can't tell.
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.
I see, thank you!
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.
This is more complex as this is set only if studio is using and has configured Redshift. So I think the logic should be - add option make redshift texture
on the same place as we have with make tx (look instance) and then probably have validator that will run on look family and will validate this env var.
|
||
cmd.extend(args) | ||
|
||
cmd = " ".join(cmd) |
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.
Few notes that are connected to each other:
- I would recommend to implement function that will return path to redshift tool (single function job, easy to check what it does)
- also would recommend to use
run_subprocess
fromopenpype.lib
which would do what you do here with subprocess - when those 2 above would be implemented this function would have 2 lines and is not needed at all...
- if you know what the arguments will be, it is always better to pass launch arguments as list instead of string to subprocess function
- more safe for multiplatform support
escape_space
will not be needed in that case- but it has few disadvantages
# This will work (arg is just for example) args = [texture_processor_path, source_path, "-arg", "value"] # This will not work args = [texture_processor_path, source_path, "-arg value"]
At this stage are these notes just recommendation because I don't know how it will be used.
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.
Thank you! This is helpful, makes me think whether we should consider refactoring the maketx
function as well to simplify a little bit.
Will hop on to something else in the meantime. I appreciate your time!
openpype/lib/vendor_bin_utils.py
Outdated
def get_redshift_tool(tool_name): | ||
"""Path to redshift texture processor. | ||
|
||
On Windows it adds .exe extension if missing from tool argument. | ||
|
||
Args: | ||
tool (string): Tool name. | ||
|
||
Returns: | ||
str: Full path to redshift texture processor executable. | ||
""" | ||
redshift_tool_path = os.path.join( | ||
os.environ["REDSHIFT_COREDATAPATH"], | ||
"bin", | ||
tool_name | ||
) | ||
|
||
return find_executable(redshift_tool_path) |
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.
Not a huge issue - but this does feel off here since unlike the rest of the methods here this Redshift binary isn't actually vendorized? I do like that there's unison in the function itself however - nonetheless it's not perfect.
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.
Thank you @BigRoy, you bring up a good point. I wonder where it would be good to place the function then @antirotor @iLLiCiTiT would love your take on where I should be placing this
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.
I would probably define separate ENV var for the tool that should be defined in the tool itself to use it.
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.
I would probably define separate ENV var for the tool that should be defined in the tool itself to use it.
is it necessary? why can't we use the mandatory {REDSHIFT_COREDATAPATH}/bin/redshiftTextureProcessor.exe
(and the appropriate lnx and mac variant)
@@ -317,7 +363,8 @@ def process_resources(self, instance, staging_dir): | |||
# be the input file to multiple nodes. | |||
resources = instance.data["resources"] | |||
do_maketx = instance.data.get("maketx", False) | |||
|
|||
# Option to convert textures to native redshift textures | |||
do_rstex = instance.data.get("rstex", False) |
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.
Yes thank you I know :D
…tive-Redshift-texture-format
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.
@m-u-r-p-h-y - Shouldn't that produce Did you enable to |
if bool(processors): | ||
for processor in processors: | ||
if processor is MakeTX: | ||
processed_path = processor().process(filepath, | ||
converted, | ||
"--sattrib", | ||
"sourceHash", | ||
escape_space(texture_hash), # noqa | ||
colorconvert, | ||
color_config, | ||
) | ||
self.log.info("Generating texture file for %s .." % filepath) # noqa | ||
self.log.info(converted) | ||
if processed_path: | ||
return processed_path, COPY, texture_hash | ||
else: | ||
self.log.info("maketx has returned nothing") | ||
elif processor is MakeRSTexBin: | ||
processed_path = processor().process(filepath) | ||
self.log.info("Generating texture file for %s .." % filepath) # noqa | ||
if processed_path: | ||
return processed_path, COPY, texture_hash | ||
else: | ||
self.log.info("redshift texture converter has returned nothing") # noqa |
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.
Isn't it odd that we define something like a TextureProcessor
base class but then end up needing to pass different types of input variables for the conversion - shouldn't those at least have the same method signatures so that when adding an extra type of processor it's just a means of implementing that base class?
I'd have expected this logic to just be:
for processor in texture_processors:
processor.process(src_filepath,
dest_filepath,
source_hash=texture_hash,
ocio_config=color_config,
color_conversion=color_convert)
No?
Also,
self.log.info("redshift texture converter has returned nothing")
That doesn't seem like "info" but sounds more like a warning or error even.
Ohh you are completely right. I had old look instance in my scene. Redid the test and it is correctly producing rstexbin files. my question is, do we really need to specify the format in the instance? Isn't it clear that we should do arnold -> tx this way it opens a space for human error as I already demonstrated . . . |
Actually I'd say yes. I believe Redshift can actually render both Check the Render Time Considerations
🙉 🙈 🙊 |
I agree that we need to specify format, but we'll need to add in the future validators to deal with unsupported features enabled on existing render instance - for example arnold/vray/renderman won't understand .rstexbin, renderman will not understand .tx/.rstexbin but will read .tex and so on. |
…tive-Redshift-texture-format
the toggle in render instance could only state
and we should know, depending on renderer, which format to use . . . |
Would that be ideal? To have that toggle on the instance? |
def validate_renderer(cls, instance): | ||
|
||
renderer = cmds.getAttr( | ||
'defaultRenderGlobals.currentRenderer').lower() |
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.
Okay hound I'll fix it buddy, and get you a treat, too
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.
return converted, COPY, texture_hash | ||
|
||
return filepath, COPY, texture_hash | ||
config_path = get_ocio_config_path("nuke-default") |
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.
I have to say few notes regarding subprocess arguments. If it is possible (and here it is possible) arguments should be passed to subprocess functions as list of strings so you don't have to call anything like escape_space
.
Also I agree with @BigRoy about those explicit arguments for TextureProcessor
. If one has different arguments then other then what is the reason of having them in abstract class... They should not be prepared for specific processor before they're passed to their processing method and all of the methods should expect the same arguments.
colorconvert
variable should be split tosrc_colorspace
anddst_colorspace
which are passed to process method- the same for
color_config
which is just path to config file where colorspaces can be found - the same for
texture_hash
- the same for
staging_dir
(handlingconverted
varible probably should not happen if MakeTX is not executed?)
In that case eash processor'sprocess
method arguments should expect these arguments:
def process(
self,
src_filepath,
staging_dir,
texture_hash,
color_config_path,
src_colorspace,
dst_colorspace
):
pass
So process
method of MakeTX
can be changed to:
def process(
self,
src_filepath,
staging_dir,
texture_hash,
color_config_path,
src_colorspace,
dst_colorspace
):
"""Make `.tx` using `maketx` with some default settings.
The settings are based on default as used in Arnold's
txManager in the scene.
This function requires the `maketx` executable to be
on the `PATH`.
Args:
...fill
Returns:
str: Output filepath/s.
"""
from openpype.lib import get_oiio_tools_path
maketx_path = get_oiio_tools_path("maketx")
if not os.path.exists(maketx_path):
print(
"OIIO tool not found in {}".format(maketx_path))
raise AssertionError("OIIO tool not found")
dirpath, filename = os.path.split(src_filepath)
fname, ext = os.path.splitext(filename)
dst_filepath = os.path.join(staging_dir, "resources", fname + ".tx")
if not os.path.exists(os.path.dirname(dst_filepath)):
os.makedirs(os.path.dirname(dst_filepath))
subprocess_args = [
maketx_path,
"-v", # verbose
"-u", # update mode
# unpremultiply before conversion (recommended when alpha present)
"--unpremult",
"--checknan",
# use oiio-optimized settings for tile-size, planarconfig, metadata
"--oiio",
"--filter", "lanczos3",
src_filepath,
]
additional_args = []
if src_colorspace and dst_colorspace and color_config_path:
additional_args.extend([
"--colorconfig", color_config_path,
"--colorconvert", src_colorspace, dst_colorspace
])
if texture_hash:
additional_args.extend([
"--sattrib",
"sourceHash",
texture_hash
])
subprocess_args.extend(additional_args)
subprocess_args.extend(["-o", dst_filepath])
kwargs = {}
if hasattr(subprocess, "CREATE_NO_WINDOW"):
kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
subprocess.call(
subprocess_args,
stderr=subprocess.STDOUT,
**kwargs
)
return dst_filepath
if "REDSHIFT_COREDATAPATH" not in os.environ: | ||
raise RuntimeError("Must have Redshift available.") | ||
|
||
texture_processor_path = get_redshift_tool("redshiftTextureProcessor") |
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.
This relates on comment above that get_redshift_tool()
should be static member of MakeRSTexbin
class.
Also I would check for the tool presence, not only REDSHIFT_COREDATAPATH
as that is already done in get_redshift_tool()
And last - lets use the new PublishValidationError
available and compatible with with the old publisher.
if "REDSHIFT_COREDATAPATH" not in os.environ: | |
raise RuntimeError("Must have Redshift available.") | |
texture_processor_path = get_redshift_tool("redshiftTextureProcessor") | |
texture_processor_path = get_redshift_tool("redshiftTextureProcessor") | |
if not texture_processor_path: | |
raise PublishValidationError("Must have Redshift available.", title="Make RSTexBin texture") |
This will ofc require from openpype.pipeline import PublishValidationError
import.
print(exc) | ||
import traceback | ||
|
||
traceback.print_exc() | ||
raise |
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.
Again, this exception should re-raise PublishValidationError
and pass some info there, prints will get lost.
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.
We should not be raising PublishValidationError
in extractors. That is too late and should be standard error exception. validation error is reserved for things that the artist can affect and fix and should be caught in the validation step.
print(exc) | ||
import traceback | ||
|
||
traceback.print_exc() | ||
print(exc.returncode) | ||
print(exc.output) | ||
raise |
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.
I guess this is the same problem and should be handled with PublishValidationError
and not prints.
for processor in processors: | ||
if processor is MakeTX: | ||
destinations[source] = self.resource_destination( | ||
instance, source, MakeTX | ||
) | ||
elif processor is MakeRSTexBin: | ||
destinations[source] = self.resource_destination( | ||
instance, source, MakeRSTexBin | ||
) |
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.
This could be simplified:
for processor in processors: | |
if processor is MakeTX: | |
destinations[source] = self.resource_destination( | |
instance, source, MakeTX | |
) | |
elif processor is MakeRSTexBin: | |
destinations[source] = self.resource_destination( | |
instance, source, MakeRSTexBin | |
) | |
for processor in processors: | |
destinations[source] = self.resource_destination( | |
instance, source, processor | |
) |
if processor == MakeTX: | ||
ext = ".tx" | ||
elif processor == MakeRSTexBin: | ||
ext = ".rstexbin" |
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.
What about moving those to the processor class, because I have a feeling that the extension is defined by the processor. Because you could then do:
if processor == MakeTX: | |
ext = ".tx" | |
elif processor == MakeRSTexBin: | |
ext = ".rstexbin" | |
ext = processor.ext |
Provided there's something like:
class MakeTX(TextureProcessor):
ext = ".tx"
...
…ya-looks-support-for-native-Redshift-texture-format
Brief description
Add support for native Redshift textures handling. Closes #2599
Description
Uses Redshift's Texture Processor executable to convert textures being used in renders to the Redshift ".rstexbin" format.
Additional info
Essentially emulating what
maketx
does by passing a number of arguments to asubprocess
and returning a status code to indicate whether the operation was successful or not.