Yes, material parameters can be completely different and unfortunately arbitrary many among MDL materials and it’s much more complicated for arbitrarily layered BSDFs.
What I’ve implemented as MaterialParameter structure is an array of 64 floats which was plenty enough to hold all parameters I’ve ever encountered.
All different material parameters structs in a scene were simply held in a single context global buffer (user format with element size sizeof(MaterialParameter)) and a single material index is all I need to combine shaders and material parameter blocks.
The bindless callable programs implementing the material hierarchy traversal (some call that material configuration) knew where which parameter was stored in the MaterialParameter struct, because the description to tell the host where to put them and the macros in the device code where to fetch them from was all auto-generated.
That float array is implemented as a union, basically like this:
#define NUMBER_OF_SLOTS 64
unsigned int ui1[NUMBER_OF_SLOTS];
optix::int2 i2[NUMBER_OF_SLOTS >> 1];
optix::float2 f2[NUMBER_OF_SLOTS >> 1];
optix::float4 f4[NUMBER_OF_SLOTS >> 2];
Parameters were tightly packed according to their CUDA alignment requirements!
float3 parameters where put into the .xyz slots of a free float4.
The .w component could then be used for any of the int, uint, or float parameters.
Works the same way in my OptiX Introduction examples, just with a smaller hardcoded MaterialParameter struct. See second sticky post in this sub-forum for links to the source code.
“And does this closest hit program have enough-sized general purpose buffer to store various parameters?”
Yes, the single(!) closest hit program used another structure (“Traversal”) to hold the user defined material parameters (and some other results), copied from the global parameter block into that inside the getter functions on initial invocation of the bindless callable program traverser().
That handled different cases controlled by a flag, e.g the anyhit only needed to calculate the cutout opacity.
That array of Traversal structs was limited to 16 nodes in the material hierarchy and each of them could hold one set of whatever MDL bsdf, layer, mixer, modifier node was used. That was also defined as a union.
I’ve not encountered an MDL material which used more nodes at once. It was also just a simple compile time define to size that.
Note that I implemented an own MDL to CUDA translation at that time and that was hitting some MDL SDK limitations not actually providing some of the information I needed.
Newer MDL SDKs actually have a PTX backend implemented which can generate PTX code for OptiX. Have a look into the MDL SDK examples and the OptiX 5.1.0 SDK examples and the threads in the MDL SDK forum https://devtalk.nvidia.com/default/board/253/mdl-sdk/ for more information.
It should be possible to make that parameter handling more explicit per generated material shader, including lifting the limit of the number of parameters. Though, careful, that has a dependency on the OptiX stack size requirements then.
The init() function in the MDL SDK generated PTX code should do that one-time fetch of the parameters.
I have not used that method myself so far.