Point cache package

Another common task of todays pipelines is point caching. This package would be a foundation for other packages, that takes care of the data extraction in multiple hosts.

Selection

I’m going from my Maya knowledge here, so I would expect the initial support would be for object sets, display layers and transform tagging.

@marcus has a good start in the Napoleon package here; https://github.com/pyblish/pyblish-napoleon/blob/master/napoleon/plugins/extract_napoleon_pointcache.py

1 Like

If it’s mostly in Selection then I don’t think a Point Cache package would be the right place?
But a good Extractor that can easily be re-used sounds like a good start! :wink: Are you looking for something pure Alembic? Or rather a package that contains a range of export formats?

If it’s mostly in Selection then I don’t think a Point Cache package would be the right place?
But a good Extractor that can easily be re-used sounds like a good start! wink

Thats a good point, a universal point cache extractor would be better.

Are you looking for something pure Alembic? Or rather a package that contains a range of export formats?

Initially I was thinking Alembic, as that is all we are using here. Don’t know what other formats people are using, but off the top of my head maybe some openVDB?

Maybe point cache is not the best description as I would like to see this package support caching of cameras etc. Basically what ever Alembic is supporting, so “Caching” might be a better name for it.

How about pyblish-alembic?

sure, that would work.

It’s an interesting proposition, there are just a few gray areas that needs ironing out.

Theoretically, it would be nice if the package consisted purely of Extractors. Extractors that folks could plug in to their existing Selectors and Conformers. But considering how different an Instance may be formatted, there would first have to be a convention/schema.

For example, the package could define a number of families.

alembic.model
alembic.camera
alembic.points

That a Selector could then implement.

# My Selector
instance = context.create_instance("MyInstance")
instance.set_data("family", "alembic.model")
for node in cmds.ls(type="mesh"):
  instance.append(node)

Each family would then define it’s own interface/convention/schema for how the internals of an Instance is to be laid out. In this case, every node must be appended to the Instance, and the corresponding family assigned.

Any Instance adhering to this schema would then be made extractable by the family it implements. This way, integrating the package would mean customising your Selectors.

On the other hand, the package could also include Selectors. But I’m a bit skeptical to this, since it would mean less interoperability, but primarily that you would be forced to define families on your end that may not align with the end user. For example, they may already have their own family for models and cameras. Now they would have two.

Thoughts?

Maybe I’m missing something, but do we need to separate model from camera etc.?

Could it not just be an “alembic” family and the name of the instance is where you describe what’s in that instance?

You tell me.

As you’re in the midst of using Alembic in production right now, consider whether there is any special treatment for cameras versus pointcaches etc. If not, then it might make sense as you say to supply only a single family.

I would definitely go for a single family and if required to differentiate between objects separate it within the instance in some other data format. (Or maybe use a process_context()?) From Maya the alembic command (if i’m correct) can process multiple extractions to multiple files with a single evaluation.

I’ve seen in the arguments that you can provide multiple time ranges with multiple file outputs in a single run. I assume this would also process in a single go. If so, this can be a heavy optimization for processing time of the data.

Maybe this will be confusing to users but how about using the families as an export type?

So say I wanted to export to Alembic format, I would create and instance with a family of “alembic”. But if I wanted to export to obj format, I would create an instance with a family of “obj”.

It’s an interesting thought for sure, and probably very doable.

You’ll have to be the judge on this one. I think just implement one or two and try to document how they are to be used. It will probably get obvious really fast what works and what doesn’t.

The next release will have pyblish.api.register_plugin that you could use and post your implementation here directly.

import pyblish.api as pyblish

class ExtractAlembic(pyblish.Extractor):
  families = ["alembic"]
  def process_instance(self, instance):
    # extract it

pyblish.register_plugin(ExtractAlembic)

import pyblish_qml
pyblish_qml.show()

Here’s an alternative.

class Extract(pyblish.Extractor):
  families = ["alembic", "obj", "ma"]
  def process_instance(self, instance):

    if instance.data("family") == "alembic":
      # extract alembic

    if instance.data("family") == "obj":
      # extract obj

Now, how would I use this extractor in my studio?

I wouldn’t go for that. I would separate them in two separate Extractors. That way it’s much clearer that two files are created for the instance.

By the way, is it possible to have one Instance to be of multiple families so it triggers both the Extractors, even though of different family? Or would that be Extractors like model.alembic and model.obj where the Instance is model?

Because we might rather change our Selector to fit with an Extractor than the other way around? (So that the Extractor can become plug ‘n’ play from an extension?)

There isn’t a way to do that currently. Neither assigning multiple families or cascading them via parent.child, but it is on the roadmap.

I’d imagine this too.

Eureka!

Got an idea of how to solve the issue of using third-party plug-ins in an already established publishing pipeline. Rather than providing a fixed family, allow the end-user to indicate what families a plug-in is meant to process!

Example Usage

This is what a user might do after having installed Pyblish Alembic.

import pyblish_alembic
pyblish_alembic.register_family("ExtractModel", "character.model")
pyblish_alembic.register_family("ExtractPointcache", "character.rig")

Example Implementation

And this is how Pyblish Alembic could be implemented.

import pyblish_alembic
import pyblish.api as pyblish

class ExtractModel(pyblish.Extractor):
  families = pyblish_alembic.registered_families("ExtractModel")
  def process(self, instance):
    # extract instances of registered families

Your comment struck a chord with me, @BigRoy, in that it makes more sense to associate instances with standalone Extractors than the inverse. This way, a studio can have associate their existing asset families with plug-ins provided by a Pyblish package, without much effort.

The package would define an interface for each of it’s plug-ins that their Instance's would need to align with, similar to what we talked about above.

For example, an extractor could start off like this.

class ExtractModel(pyblish.Extractor):
  families = pyblish_alembic.registered_families("ExtractModel")
  def process(self, instance):
    # 1. Validate interface
    assert instance.has_data("pyblishAlembicSpecficAttribute"),
           "%s is not compatible with %s" % (instance, self)

    # 2. Instance is compatible, carry on.

For which documentation can specify how to make your instances compatible.

Example Documentation

  1. Instances must contain the data-member pyblishAlembicSpecificAttribute
  2. The data-member must have a value of True