Content Cache Updated Guide

Note : This guide requires the Release Candidate 8.8 in Rhino. This is a release candidate meaning that it is meant for testing and should not be used for project critical production work. To get it, subscribe to the Release Candidate update stream on Windows or on Mac This is a big change to the Content Cache component and we welcome any feedback.

We updated the Content Cache component, which lets you drive objects in Rhino with Grasshopper. Grasshopper now has a Content Cache component, which lets you update objects in different caches by replacing the objects and not duplicating them.

The Content Cache component can be used to

  1. Push Grasshopper objects into Rhino without creating duplicates.
  2. Pull Rhino objects into Grasshopper that can be updated later back in Rhino.
  3. Automate the traditional Bake of the geometry from Grasshopper into Rhino.

Content Cache Getting Started:

The Content Cache component is found in the Rhino Toolbar.

By default, the Content Cache component takes Grasshopper content as input and outputs a reference to the Rhino objects as a Result:

The Push into Rhino is activated by pressing the button on the component.

Notice in the example above the input geometry is simply Grasshopper Geometry Breps and the cache is outputting Model Breps which now exist in Rhino. Referenced Objects be identified by the Unique ID attached to each object (i.e. {651b081f...})

Action Types:

The component runs the default action each time the Action button is pushed. Different default actions may be set to fit the desired behavior between Grasshopper and Rhino objects. The default action can be set by right-clicking in the center of the component and using the Button Action menu:

The list of action types:

  1. Purge - Removes the referenced objects from the Rhino document. This can include normal Rhino objects, but also document level objects such as block definitions, layer definitions, annotation styles, and material definitions. Like Rhino, only elements that are not “in use” can be purged. For instance, if a layer contains objects it cannot be purged until those objects are deleted or moved to another layer.
  2. Pull - Pull Rhino objects into Grasshopper. Included in the Pull is the object’s ID, which can be used to edit, replace, or update the specific object later by Grasshopper.
  3. Push- This takes the object and pushes it into Rhino. For instance, a classic geometry type will be placed in the Rhino document. By default, Grasshopper will continue to track this object, so any future updates will replace the object instead of duplicating it.
  4. Bake - This will take the Grasshopper contents and create them in Rhino, but then forget about the objects. This can be used to create new Rhino objects each cycle. This differs from Push in that Bake will also create duplicate objects in Rhino.

An important behavior to understand is that if an Object is input into the Content Cache and has an existing ID, a Push or Bake will replace that object and will not duplicate that object. This applies to Model Objects, Layers, Block Definitions, Materials, etc.

As an example the definition below will only replace the existing object because Model Objects input an ID:

But with a simple change, by using only the Geometry of the Model Object, essentially stripping it of its ID, now Bake will create a new object with a new ID each solution cycle:

There are many ways to work with the new Model Object data types in Rhino 8. See the Model Objects Guide for more details.

Anytime the Result output is showing the component will always Pull. This output can be used later in this Grasshopper definition. For instance, the example below, after an initial button Push, will allow the Cached Brep to be moved around in Rhino with the Gumball. Grasshopper will constantly keep the Mass Centroid point drawn in the center of the object:

For large models, if performance becomes a concern, the Result input can be hidden which will help the Content Cache faster as it will not need to Pull the Rhino objects.

Controlling Models Objects, Layers and Attributes:

In cases where Content Cache needs to Push or Bake objects into Rhino and has no additional attribute information, the Content Cache will put the objects on a Grasshopper layer with sub-layers denoting the object type (Curve, BREP, Mesh, etc.)

If the Objects have Attributes such as a Layer, Color, Material. etc, then the attached Attributes will be used. This attribute information is already present on model objects that come from Rhino (have an ID). For other objects normally the Model Object component is used to add those attributes:

Automating Actions:

The Content Cache component action can be automated by exposing the Action input:

Zoom in on the component, click on the “+” to expose the Action input.

A True and False boolean value can be sent to the input to initiate the default action set in the component through the Button Action menu:

Advanced Options and Workflows:

The Content Cache component can be configured in many different ways. This allows flexibility in content creation that fits specific advanced workflows. This section looks at all the inputs and outputs of the Content Cache component. Inputs and outputs can be expanded by zooming in on the component.

The complete list of inputs and outputs:

  1. Cache Name input - Objects pushed or baked to Rhino carry this cache name. This can be used for versions, options and organization of Rhino objects. See Cache Name section for details.
  2. Content input - The geometry and attributes to be processed. See Content section for details.
  3. Action input - A way to automate and change the action type (Push, Pull, Bake, Purge) with Grasshopper. See Actions section for details.
  4. Cache Name output - The Cache names completed in the component. See Cache Name section for details.
  5. Content output - The objects processed in the component. This is more of a passthrough from the Content input. See Content section for details.
  6. Result output - This will Pull the results of the component after its action. See Results section for details.

Cache Name:

Each cache operation can be named. The Cache Name on cached objects can be used to specify different adoptions, variations or groups of objects backed by the same component. This Cache Name can be later used to reference the objects.

The Cache Name used on existing objects in Rhino can be recovered by using the Content Details component

If the Cache Name is known, then the Content Cache component can be used tp Pull the Rhino objects with that name:

Branch Name modifier:

The Branch Name modifier can be activated on the Content Cache component. Branch Names option affects how the component pushes or bakes objects into Rhino. Many times Branch Names might be activated to create multiple Options or versions of objects organized by the Cache Names.

With Branch Names activated, the cache objects will have the Object Name set to the Cache Name if no other information is supplied.

In addition, the Branch Names option will create a Parent Layer of the Cache Name and place all other layers and objects on sublayers of that layer. This is a quick way to create multiple options and keep the results separated.

Content:

The Content input takes the Grasshopper GH Geometry types and Model Objects with attributes and will process them according to the Action in the component.

Simple Grasshopper Geometry type will work, but since they do not have any other attributes, the Content Cache will process them with the default behaviors. If Model Objects are input with Attributes such as Layer, Color, etc. then those attributes will be respected.

An important concept to keep in mind is that if the Content input objects have an ID with them, the Content Cache component will replace those objects, not create a duplicate new object. This is true for both a Push and a Bake.

The Content output is meant to be a passthrough output that will pass the objects from the input directly across to the output.

Actions:

The Action is how the Content Cache should process each object from Grasshopper into Rhino and back. The four Action types are:

  1. Purge - Removes the referenced objects from the Rhino document. This can include normal Rhino objects, but also document level objects such as block definitions, layer definitions, annotation styles, and material definitions. Like Rhino, only elements that are not “in use” can be purged. For instance, if a layer contains objects it cannot be purged until those objects are deleted or moved to another layer.
  2. Pull - Pull Rhino objects into Grasshopper. Included in the Pull is the object’s ID, which can be used to edit, replace, or update the specific object later by Grasshopper.
  3. Push- This takes the object and pushes it into Rhino. For instance, a classic geometry type will be placed in the Rhino document. By default, Grasshopper will continue to track this object, so any future updates will replace the object instead of duplicating it.
  4. Bake - This will take the Grasshopper contents and create them in Rhino, but then forget about the objects. This can be used to create new Rhino objects each cycle. This differs from Push in that Bake will also create duplicate objects in Rhino.

The Action input is used to automate the Content Cache component from within Grasshopper. There are a few ways it can be used.

By sending a Boolean (True/False) the default Action set in the component will be run:

  1. True - The default action is run. (Push, Pull, Bake, Purge)
  2. False - The default action is not run, but if Result is showing, the component will continue to pull.

Beyond True/False the Action input, the Action type can be input so that each object may be processed accordingly:

Action String Input Index Value Value List
Pull “Pull” 0 Pull
Push “Push” 1 Push
Bake “Bake” 2 Bake
Purge “Purge” -1 Purge

An easy way to scroll through these options is to attach a Value List component to the Action input and the selections will automatically populate:

Results:

The Results output is the objects that have been pulled out of the Rhino document after the elements have been pushed, baked or purged with the Content Cache. Because the objects exist in Rhino all the Result objects will have an ID with them.

No matter what the Action being used, as long as Result is visible, the Content Cache will be pulling those elements from Rhino. Objects can be used later in the Grasshopper definition by processing the Result output.

There is a slight performance penalty when Result is visible as Grasshopper is constantly pulling the contents. Hiding the Result output will stop the Pull process and potentially could improve performance.

Content Details Component:

The Content Details Component can be used to discover the state of any object in Rhino and what its current status is with the Cache. This is an advanced component to see the details of any Content Cache action.

The Content Cache above creates a cache named Option1. The Content Cache will then both Push and Bake a circle, resulting in two different circles. Using the Content Details we can investigate the results.

  • Cache Name output - The pushed circle results in the Cache Name. The baked circle does not include a Cache Name as baking will not carry cache information.
  • Cached output - This is a True/False bool if an object belongs to the Cache. The pushed circle does, the baked circle does not.
  • Content output - The resulting object referenced from the document. Two circles each with different IDs.
  • Referenced output - Tests if the objects are referenced from the Rhino document. In this case both are as they exist in the Rhino document. Another hint to this is that each object has an ID.
  • ID output - The full ID of each Object.
  • Path output - For complex nested objects the Path would contain the parents. For instance a sub-layer would have a Path which is its parent layer. Nested Blocks are something else that may have a path.
  • Attributes - A list of each of the object’s attributes.

Optimizing Performance:

  • Push and Bake are the most expensive processes, so be selective with what is Pushed or Baked.
  • Limiting the number of Content Cache components on the canvas will help with performance, especially if Pushing or Baking.
  • Pulling elements does some with a little overhead, so hiding Result if not needed can improve performance a little.
  • Enabling Automatic Content Cache can greatly affect performance as each change requires an update.
15 Likes

Great overview @scottd ,

Thanks for putting this together!

Does this mean if we have lots of different Query components/cache end results in a script currently, it will be more peformant to refactor the script to use as few Query and Cache components as possible, even if it means more complex data tree structures on the front and backend?

I have a current script approaching 10,000 components that still runs very well but I have about 10 or 12 query components and about 15-20 Content Cache components all set to automatic updating and synchronization.

If a more complexity data tree is fed into this, is it better to have the cache update Everytime a single branch is changed or better to break out the logic in separate caches so that if a branch is changed it’s not having to reevaluate the caching of all other branches in the “more complex data tree”

In less words, better to use 1 master Cache with many branches or multiple caches focused on the downstream output of whatever function is upstream

Not sure we exactly know what the best balance will be here. We will need to experiment together on all this to see what works best.

One way to think about it that only cache the contents when the objects/information needs to be stored in Rhino for later.

Along with the Manual Button and the continuous automation of the Action toggle, there is a third way using the timer to update on intervals:

1 Like

Sounds good, so far the only performance bottleneck I have hit with Caching is that when the viewport is in rendered display mode, the script takes longer to solve, up to 6 seconds, if the viewport is in wireframe display mode, it solves “instantly”.

This is difficult to repeat on a new file or small definition but it’s very obvious in large definitions.

I have created a workaround to set the display mode to wireframe, update the caches and set the display mode back to rendered mode. This is faster than just letting it update the caches if leaving it in rendered mode while the cache(s) executes.

Good advice, I’ve started offloading anything that I don’t need to select or store onto the Custom Preview component. I’m only using caches for geometry and user text on said geometry.

Interesting! Does this cause the cache to recompute if none of the data has changed though?

The delay in rendered mode is that the object added does not include a render mesh, so it must be generated when it is added. This can take a relatively long time. Wireframe is much faster. And that mesh generation time will be spent when going back into Render or shaded mode in the future. In normal scripts we turn off display updates while the script is running. But of course that mean objects are not live.

The timer simply disables the component for a set amount of time. It can be triggered by time or manually.

3 Likes

Thanks for clarifying @scottd , good things to know!

@scottd Thanks for the great write-up. This makes it a lot clearer without having tried it in 8.8 yet.

Since it was not mentioned anywhere, I want to ask: Can we also place Block Instances using Content-Cache? You only mention Block Definitions. We often have a large number of Block Instances all with a different transform, that we want to place/update.

Yes, there is a block instance component that locates a block definition on a certain layer, etc. essentially a block instance can be treated like any Model Object. Then it can be run thru the cache to push it into Rhino.

The key to block instance orientation is to use a plane to insert it with instead of a point. Then location and rotation can be controlled.

2 Likes

Great. So any non-uniform scaling would have to be done separately or is there a way to place the block instances using transform matrixes?

The component takes a Transform as an input so it should allow any kind of transform (scale, mirror, skew, …)
Point and plane cast to translate and orient Transforms.