The function paradigm that I will use is for each entity to perform a 'pre' render function to prepare the material, and then call the actual render function when all of the pre-rendering for the current view is complete.
While considering how best to do this, I have come to a few conclusions:
1. The material system must be fully re-entrant, meaning that one material has to be able to perform its duties without depending on other materials. This works out OK since I use render views to encapsulate all of the rendering passes anyways, but I wanted to formalize the requirement.
2. The material preparation must be recursive in nature. Consider what happens when two reflective objects are next to each other - to make it correct, the environment maps for each object need to be recursively updated until an acceptable level of the 'mirrored elevator' look is achieved.
3. The recursive pre-rendering has to have a maximum limit to the number of recursions. The example from point #2 is a good way to crash unless you limit the amount of recursion allowed in the system. I think the way to handle it is to limit the number of times that a render view can be updated in a single frame, but I'll have to test it out to see how well it works out.
With these concepts in mind, I'll probably get started on an implementation in the coming week or so. I should be completely finished with all of the book material by then, and I'll be ready to jump in head first!!!
One example of this is that the diffuse color of a piece of world geometry or other object might be a blend of several textures, including decals. That material looks different on-screen when moved through the environment with different shadowing & lighting properties.
I like your 'render view' concept. It is similar to the 'RenderFrame' object I use in my enginge. The RenderFrame's constructor sets up basic render state needed, possibly set up viewports and switch rendertargets, clear buffers, then the renderframe() takes its view of the subset of objects it has and draws them to that rendertarget, then its destructor sets renderstates back.
Maybe it's just nomenclature, but to my mind the material is the 'Document' - it provides data, including some flags about rendering, like 'i don't cast shadows', etc. and the RenderView chooses some subset of material paramters and other info, maybe associated with the entity, to choose how to render this guy to the current render target.