Getting BaseArray from RayObject [SOLVED]



  • On 16/08/2016 at 00:16, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   14+ 
    Platform:   Windows  ; Mac  ;  Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    Hi,

    I would like to get a basearray of vectors from rayobject->link and use it in a shader.
    Basically, say I have a generator plugin that generates 2 cubes (1 BaseObject and 1 instance of it) and inserts them under a null.

    In MyGenerator plugin, GetVirtualObjects goes like this (a very simplified version):

    BaseObject* groupNull = BaseObject::Alloc(Onull);
    BaseObject* cube = BaseObject::Alloc(Ocube);
      
    BaseObject* cubeInstance = BaseObject::Alloc(Oinstance); 
    BaseContainer* ibc = cubeInstance->GetDataInstance();
    ibc->SetLink(INSTANCEOBJECT_LINK, cube);
    ibc->SetBool(INSTANCEOBJECT_RENDERINSTANCE, TRUE);
      
    cube->InsertUnder(groupNull);
    cubeInstance->InsertUnder(groupNull);
      
    maxon::BaseArray<Vector> colors; 
    colors.Resize(2); 
    colors[0] = Vector(1,0,0);
    colors[1] = Vector(0,1,0);
      
    return groupNull;
    

    This works great. The problem is with the shader.

    MyShader plugin needs to get the rayobject, the colors basearray and assign the respective color to each cube. This is from Output(BaseShader *chn, ChannelData *cd) :

    Vector color = Vector(0); // defaults to black
    if (cd->vd)
    {
    	RayObject *rayObj = NULL;
    	rayObj = cd->vd->op;
    	if (!rayObj) return 0.0;
      
    	BaseObject* myObject=(BaseObject* )rayObj->link;  // or should I use: rayObj->link->GetCacheParent();
      
    	// now I need to set the color vector to read form the colors basearray
    	//....how do I proceed from here??
    	
    	return color;
      
    	}
    


  • On 16/08/2016 at 02:53, xxxxxxxx wrote:

    Hi,

    you have plenty of options here.
    First of all, note, that you will need to store the colors persistently. Currently you create the array in GVO just on the stack. So the array is gone as soon as the scope (in this case the GVO function) is left.
    So, that's not going to work.

    Instead try one of the following suggestions. The list is not thought to be complete, there are just too many ways to achieve this:

    a) Every object has a Display Color (ID_BASEOBJECT_COLOR) parameter on its Basic tab in Attribute Manager. You could "mis-use" this to store the color value on each object.

    b1) As you have your own generator plugin, why not store the colors in the BaseContainer of your generator object? Using GetCacheParent() and a type/ID check, you could then retrieve the colors from the container in Output().

    b2) Even a member variable (array) is possible. Then you'd implement additionally GetDParameter() and use GetParameter() to read it. Careful though, you may need to implement CopyTo(), Read() and Write() in this case as well, so your data contained in member variables is correctly copied, stored and loaded.

    c) Similar to b) you could also implement a hidden tag storing the properties you need.

    d) Add an access function to your generator object to retrieve the color values from it, but I'd rather go one of the b routes here.

    As said before, these are just a few of the options you have.
    Which way to choose depends on your needs and goals.



  • On 16/08/2016 at 07:11, xxxxxxxx wrote:

    Thank you for the reply Andreas. I am trying to implement your b1 solution.

    Please note that my actual plugin would contain a variable number of child objects, as in thousands. Think of clones inside a cloner object.

    1. Can you (or anyone else) provide a code snippet on how I can set IDs to each child object inside the basecontainer? 
    2. How do I store the color values inside the basecontainer?

    Obviously, if I do it like this it's wrong

    for (i=0; i<childCount; i++)
    {
    	bc->SetVector(15000+i, colors[i]);  // 15000 is an arbitrary ID
    }
    

    There should be a way where I create 2 parameters, called ID_CHILD and CHILD_COLOR, that are copied to each child, and then set the values of these parameters.
    That way I can retrieve those parameters from each child in Output.



  • On 17/08/2016 at 00:37, xxxxxxxx wrote:

    Implementing solution (a) works on regular child objects, but not on instances. So it's not a good solution for my problem. 
    I need to provide unique values to child objects, knowing that 99% of them are instances.



  • On 17/08/2016 at 06:17, xxxxxxxx wrote:

    Slowly, please ;)

    I have to admit I underestimated some of the problems you might run into. I was too much focused on attaching data and accessing it somewhere, not completely thinking the shader side through.

    Maybe we should discuss your setup a bit more, first.
    The main problem I see, is that your shader and the object generator are completely disconnected entities. What's supposed to happen, if the shader is assigned to another object? And what, if your generator object is used within other generators, like for example a Connect object?

    In the end the renderer doesn't really care about the object hierarchy anymore, but it works on caches. So, depending on the given scene hierarchy (e.g. your generator in a Connect object), the given RayObject may not necessarily directly connected to your generator anymore.
    Even worse, not all attributes of objects (like the Display Color) can be preserved by generators.
    And even, if you scanned the scene hierarchy in order to identify your generator, you wouldn't know how to correlate this information to the cache, as you'd need to know interna of the given generator.

    So depending on your needs and the freedom a user has with your object/shader, this probably also renders my suggestions somewhat useless in your case. Sorry!

    If, on the other hand, your setup is way simpler and no other generators are involved, then a) is probably still the simplest way to go. The reason it's not working with instances is, that these need a little extra handling.
    Like so:

    	// the real object
    	BaseObject* link = nullptr;
      
    	// check if render instance
    	RayObjectInstanceData* instanceData = sd->vd->op->instance;
      
    	if (instanceData != nullptr)
    	{
    		// link to the instance object as this object was created by the generator
    		link = instanceData->link;
    	}
    	else
    	{
    		link = sd->vd->op->link;
    	}
    


  • On 17/08/2016 at 06:57, xxxxxxxx wrote:

    Thank you for the snippet on handling instances Andreas. That was the missing link!

    The shader is only supposed to work exclusively with the generator, so I am good for the time being, and I will mark this thread as solved.

    On a related note, if I wanted to assign unique IDs to the child objects, should I be doing that with user data?



  • On 17/08/2016 at 08:42, xxxxxxxx wrote:

    Glad we found a solution for you.

    I hope you don't mind, if I ask you to open a new thread for the additional question. Please add some info there, what will be the purpose of these IDs and in which situations you want to make use of them.


Log in to reply