I've made it to the Groups chapter and playing a bit with the hexagon.
It all worked fine until I tried to use patterns that are based on space coordinates, e.g. like if I want the hexagon to be carved out a single block of wood or marble.
With the standard worldToObject, each shape in the group has its own independent replica of the pattern, which works ok except in the case stated above. After some fiddling I managed to get the effect I wanted by skipping all "intermediate" parents and using only the last one, i.e. the top group.
But I need two versions of worldToObject and I am not sure at all if this is a good approach... is it viable? If so, what kind of object "property" would I declare?
Some pictures to show the case.
Standard worldToObject: each component looks identical (e.g. see pattern repeating over the cylinders).
Alternate worldToObject: it returns the transformation of the last parent only. The pattern is now consistent over the entire group.
Transformations (e.g. a rotation here) are followed correctly:
Good observation. I assume you've implemented the optional feature, mentioned at the end of that chapter, where you allow child shapes to inherit their texture from their parent?
What I suspect needs to happen in this case is that the material needs to be rendered in the object space of the shape that owns the material, rather than the space of the shape that was intersected. That would ensure that all parts of the group will be rendered in a consistent object space, and allow the textures to mesh more naturally. If you'd like, when I have some time this afternoon I can take a stab at this and see if I have any more concrete advice I can offer.
Yes, that's what I think should happen. I have found the following solution.
There is a special "proxy pattern" that forwards all messages to another pattern except for color_at(), where it replaces the object parameter with another object specified at construction time.
When set_material() is called on a group, the group replaces the material pattern with a proxy, setting itself as the destination object of color_at(). It then calls set_material() on all children. Now whenever an object is hit, the color_at() method is invoked on the proxy which replaces the object with the group and forward the call to the original pattern, so it all works the same except that the pattern space is now the group's.