If you want to add some extra parameters with custom logic, you have to implement your own translator in a C4DtoA module (which is basically a normal C4D plugin with some extra functions).

Let's add a custom checkbox above param2. Enable and export param2 only if the checkbox is checked, otherwise, the color should be a default red.

 

To achieve this you must create your own C4D plugin, which will be a module of C4DtoA. First , you have to setup your project.

  1. Compile the C4D API. Project files are located in $C4D_INSTALL/resource/_api_lib in R15 or $C4D_INSTALL/frameworks/cinema.framework/project in R16.
  2. Create a new project (e.g. in Visual Studio or Xcode), include the C4D API headers and link with the compiled API lib. You can check the $C4D_INSTALL/plugins/cinema4dsdk example project.
  3. Include the C4DtoA API headers from $C4D_INSTALL/plugins/C4DtoA/api/include and link the c4dtoa_api.lib from $C4D_INSTALL/plugins/C4DtoA/api/lib.
  4. Create your main plugin file (MyPlugin.cpp) where you register your C4DtoA module in MSG_C4DTOA_MODULE_START.

    #include "c4d.h"
    #include "c4d_symbols.h"
    
    #include "c4dtoa_api.h"
    
    Bool PluginStart(void)
    {
       return TRUE;
    }
    
    void PluginEnd(void)
    {
    }
    
    Bool PluginMessage(Int32 id, void *data)
    {
       switch (id)
       {   
          case C4DPL_INIT_SYS:
          {
             if (!resource.Init()) return FALSE; // don't start plugin without resource
             return TRUE;
          }
          case C4DMSG_PRIORITY: 
          {
             return TRUE;
          }
          case C4DPL_BUILDMENU:
          {
             break;
          }
          case C4DPL_STARTACTIVITY:
          {
             break;
          }
    
          case MSG_C4DTOA_MODULE_START:
          {
             const char* myModuleName = "mymodule";
    
             // C4DtoA module manager and API version number is passed as the argument
             ModuleManagerData* moduleManagerData = (ModuleManagerData*)data;
             ModuleManager* moduleManager = moduleManagerData->moduleManager;
             
             // check compatibility
             if (moduleManagerData->apiVersion != C4DTOA_API_VERSION)
             {
                GePrintF("[c4dtoa] %s module is incompatible (API version is %d, current is %d)", 
                   myModuleName, moduleManagerData->apiVersion, C4DTOA_API_VERSION);
                return TRUE;
             }
    
             Module* module = new Module(myModuleName);
    
             // add your Arnold plugins to the plugin path
             Filename myShadersFolder = GeGetPluginPath() + "shaders";
             char myShadersPath[256]; myShadersFolder .GetString().GetCString(myShadersPath, 256);
             module->RegisterPlugins(myShadersPath);
    
             // register the module to C4DtoA
             moduleManager->RegisterModule(module);
    
             break;
          }
          case MSG_C4DTOA_MODULE_END:
          {
             break;
          }
       }
    
       return FALSE;
    }

You have to create resource files, a node for your shader and a custom translator. Best way is to use the resource_generator tool.

  1. Generate default resource and source files using the resource_generator tool of the API. Note that your shader library should be added to the ARNOLD_PLUGIN_PATH.

    $C4D_INSTALL/plugins/C4DtoA/api/bin/resource_generator myshader

    Resource files are generated at the 'output' folder by default You can specify any folder as the last parameter of the command.

  2. Edit description/ainode_myshader.h and add an id to the new checkbox parameter. If you need a unique id in the application you can use the paramid_generator tool of the API. Note that a unique id is necessary if you want to use the description in a generic node (like the Arnold Material). In our case it's not necessary, but let's see how to use the tool.

    $C4D_INSTALL/plugins/C4DtoA/api/bin/paramid_generator myshader.c4toa_param2_checkbox
        C4DAI_MYSHADER_PARAM2_CHECKBOX                     = 649714697,
  3. Edit the layout in description/ainode_myshader.res.

    CONTAINER AINODE_MYSHADER
    {
       NAME ainode_myshader;
    
       // includes
       INCLUDE Mpreview;
       INCLUDE Mbase;
    
       // parameters
       GROUP C4DAI_MYSHADER_MAIN_GRP
       {
          DEFAULT 1;
    
          AIPARAM C4DAIP_MYSHADER_PARAM1 {}
          SEPARATOR {LINE;}
          BOOL C4DAI_MYSHADER_PARAM2_CHECKBOX {}
          AIPARAM C4DAIP_MYSHADER_PARAM2 {}
       }
    }
  4. Add a label to the checkbox in strings_us/description/ainode_myshader.str.

       C4DAI_MYSHADER_PARAM2_CHECKBOX  "Enable parameter 2";
  5. Set the default value of the checkbox (ArnoldMyshader.cpp).

    Bool ArnoldMyshader::Init(GeListNode *node)
    {
       // use GetDataInstance() because GvNode has a special container
       BaseContainer* data = GetDataInstance((BaseList2D*)node);
    
       data->SetBool(C4DAI_MYSHADER_PARAM2_CHECKBOX, TRUE);
    
       return ArnoldShaderGvOperatorData::Init(node);
    }
  6. Add logic to the Material node of enable / disable param2 by the checkbox value. 

    ArnoldMyshader.h
       // Enables / disabled parameters on the interface.
       virtual Bool GetDEnabling(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_ENABLE flags, const BaseContainer* itemdesc);
    ArnoldMyshader.cpp
    Bool ArnoldMyshader::GetDEnabling(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_ENABLE flags, const BaseContainer* itemdesc)
    {
       Int32 cid = id[0].id;
    
       // use GetDataInstance() because GvNode has a special container
       BaseContainer* data = GetDataInstance((BaseList2D*)node);
    
       if (id == C4DAIP_MYSHADER_PARAM2)
       {
          return data->GetBool(C4DAI_MYSHADER_PARAM2_CHECKBOX);
       }
    
       return ArnoldShaderGvOperatorData::GetDEnabling(node, id, t_data, flags, itemdesc);
    }
  7. Obtain a unique id from Plugin Café and add this id to the ArnoldMyShader.h header.

    #define MYSHADER_ID {id}
  8. Register your C4D material node in the main plugin file (MyPlugin.cpp).

    #include "ArnoldMyshader.h"
    
    Bool PluginStart(void)
    {
       RegisterArnoldMyshader();
    
       return TRUE;
    }

    To use the description defined with your node you have to add your node id to the meta data file (myshader.mtd).

    [node myshader]
      c4d.node_id    INT   {id}
    
  9. Register your custom translator in the main plugin file (MyPlugin.cpp), as in the previous example.

    #include "ArnoldMyshaderTranslator.h"
    
    AbstractTranslator* createTranslator(BaseList2D* node, RenderContext* context)
    {
       if (node->GetType() == GVbase)
       {
          GvNode* gvnode = (GvNode*)node;
          if (gvnode->GetOperatorID() == MYSHADER_ID)
             return new ArnoldMyshaderTranslator(node, context);
       }
    
       return 0;
    }
    
    Bool PluginMessage(Int32 id, void *data)
    {
       ...
          case MSG_C4DTOA_MODULE_START:
          {
             ...
             
             // translators
             module->RegisterTranslatorCreator(createTranslator);
    
             ...
             break;
          }
       ...
    }
  10. Add export logic to the translator (ArnoldMyshaderTranslator.cpp).

    void ArnoldMyshaderTranslator::Export(int step)
    {
       // super
       AbstractGvShaderTranslator::Export(step);
    
       BaseList2D* node = (BaseList2D*)GetC4DNode();
       if (!m_aiNode || !node) return;
    
       // use GetDataInstance() because GvNode has a special container
       BaseContainer* data = GetDataInstance(node);
    
       // first motion step
       if (step == 0)
       {
          if (data->GetBool(C4DAI_MYSHADER_PARAM2_CHECKBOX) == TRUE)
          {
             Vector param2 = data->GetVector(C4DAIP_MYSHADER_PARAM2);
             AiNodeSetRGB(m_aiNode, "param2", param2.x, param2.y, param2.z);
          }
          else
          {
             AiNodeSetRGB(m_aiNode, "param2", 1.0f, 0.0f, 0.0f);
          }
       }
    }
  11. Compile your project and copy the res folder and the plugin binary (cdl64 on Windows, dylib on OSX) to $C4D_INSTALL/plugins/MyPlugin folder.

 

The source code for the example is attached here.

On Windows you just have to copy the folder to your C4D plugins folder and open the Visual Studio solution (myshader_example.sln) to build. Select the configuration of your C4Dd version (R15, R16 or R17). You can also change the path of your C4D folder in projectsettings.props.

  • No labels