MaterialPreview Widget



  • On 23/11/2017 at 02:21, xxxxxxxx wrote:

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

    ---------
    Hello everybody,

    currently I am trying to get used to the C4D MATPREVIEW GUI Control. I am trying to connect a LinkBox which accepts materials with a MaterialPreview. As soon as I link a material to the LinkBox I want the material preview control to show the rendered preview image. Additionally I want to update the image as soon as the referenced material changed.

    Current attempt:
    * listening to the EVMSG_MATERIALPREVIEW event (emitted when a material is changed)
    * checking if the changed material is the material hold in the link box
    * problem: how to update/connect the preview control

    Could anyone give me some hints or some little explanation/examples how to use the MaterialPreview Control?

    Greetings
    Svente

      
      if (id == EVMSG_MATERIALPREVIEW)  
      {  
          //get material container  
          BaseObject* pMaterialContainer = (BaseObject* )msg.GetVoid(BFM_CORE_PAR1);  
          if (!pMaterialContainer)  
              return GeDialog::CoreMessage(id, msg);  
      
          //get the LinkBox from plugin dialog in order to get the linked material  
          LinkBoxGui* pLinkBox = (LinkBoxGui* )this->FindCustomGui(MATERIALCHANGE_LINK_BROWSER_LINK, CUSTOMGUI_LINKBOX);  
          if (!pLinkBox)  
              return GeDialog::CoreMessage(id, msg);  
      
          ////get the linked materials BaseObject  
          BaseObject* pLinkedMat = (BaseObject* )pLinkBox->GetLink(GetActiveDocument());  
          if (!pLinkedMat)  
              return GeDialog::CoreMessage(id, msg);  
      
          //check if linked material is the same as the one of the calling message and return otherwise  
          if (pMaterialContainer != pLinkedMat)  
              return GeDialog::CoreMessage(id, msg);  
      
          MaterialPreviewCustomGui* pPreview = (MaterialPreviewCustomGui* )this->FindCustomGui(MATERIALCHANGE_MATPREV_MAT, CUSTOMGUI_MATPREVIEW);  
      
          if (!pPreview)  
              return GeDialog::CoreMessage(id, msg);  
      
          //??? what to do?  
      
      }  
    


  • On 24/11/2017 at 09:13, xxxxxxxx wrote:

    Hello,

    like all GUI gadgets the MaterialPreviewCustomGui displays data of a given data type. The MaterialPreviewCustomGui displays MaterialPreviewData data. Such data can be created using a GeData object:

      
    _matData = GeData(CUSTOMDATATYPE_MATPREVIEW, DEFAULTVALUE);  
    _previewData = (MaterialPreviewData* )_matData.GetCustomDataType(CUSTOMDATATYPE_MATPREVIEW);  
    

    The data is then set to the GUI gadget:

      
    _previewData->Init(MatPrevDialog::RenderPreviewImage, nullptr, 450000100, dirtyState);  
    _matPreview->SetData(_matData);  
    

    As you can see, the Init() function requires a callback to a static function. This static function will receive messages from the MaterialPreviewCustomGui (see MATPREVIEW). This way is is possible to define the behaviour and content of the gadget:

      
    static Bool RenderPreviewImage(Int32 lMessage, void* pData, void* pUserData)  
    {  
     switch (lMessage)  
     {  
         case MATPREVIEW_GET_OBJECT_INFO:  
         {  
             MatPreviewObjectInfo* mpoi = (MatPreviewObjectInfo* )pData;  
             mpoi->bHandlePreview = true;  
             mpoi->bNoStandardScene = true;  
             mpoi->lFlags = MATPREVIEW_FLAG_HIDE_ROTATION | MATPREVIEW_FLAG_HIDE_SCENES | MATPREVIEW_FLAG_HIDE_SCENE_SETTINGS | MATPREVIEW_FLAG_HIDE_SIZE | MATPREVIEW_FLAG_HIDE_ANIMATE;  
      
             break;  
         }  
      
         case MATPREVIEW_GENERATE_IMAGE:  
         {  
             MatPreviewGenerateImage* mpgi = (MatPreviewGenerateImage* )pData;  
             BaseBitmap* pBmp = mpgi->pDest;  
             const Vector color = g_material->GetAverageColor();  
             pBmp->Clear(Int(color.x * 255), Int(color.y * 255), Int(color.z * 255));  
             mpgi->lResult = RENDERRESULT::RENDERRESULT_OK;  
      
             break;  
         }  
         case MATPREVIEW_PREPARE_SCENE:  
         {  
             MatPreviewPrepareScene* mpps = (MatPreviewPrepareScene* )pData;  
             mpps->bScenePrepared = true;  
         }  
         break;  
     }  
     return true;  
    }  
    

    You will find discussions on these messages in various threads like:

    You could use the existing preview scene or render your own scene/image to display the material.

    A few other notes on your code:

    • EVMSG_MATERIALPREVIEW is a private message. If you want to catch changes in the scene (including changes to the materials) you have to catch EVMSG_CHANGE, see Core Messages).

    • It seems that you want to access materials from msg.GetVoid() and pLinkBox->GetLink(). But instead you are using BaseObject pointers. The class for generic materials is BaseMaterial (see BaseMaterial Manual), the class for the C4D standard material is Material (see Material Manual).

    best wishes,
    Sebastian



  • On 01/12/2017 at 06:01, xxxxxxxx wrote:

    Hello,

    first I want to thank you for your help.
    You gave as a bunch of homework... But with these information we were able to reach a certain point, at which the MaterialPreviewCustomGui works as expected.

    The biggest problem was the implementation of the RenderPreviewImage method (and it's not implemented yet) because we use the MaterialPreview gadget in a dialog plugin. Therefore we weren't able to provide the needed data.

    In the end their is one question left: is it possible to get the stored data from the standard material preview of cinema itself? For shader plugins it seems to be no problem (because of the context?) but can dialog plugins "address" the standard preview too?

    Kind regards,
    Svente



  • On 01/12/2017 at 09:07, xxxxxxxx wrote:

    Hello,

    what exactly do you mean with "the stored data"?

    You could access the preview BaseBitmap image with BaseMaterial::GetPreview(), see BaseMaterial Manual.

    best wishes,
    Sebastian



  • On 04/12/2017 at 05:03, xxxxxxxx wrote:

    Hello,

    for me it seemed, that BaseMaterial::GetPreview() is delivering not the original BaseBitmap of the shown MatPreview. Instead I think it delivers the preview of the material shown in the "material browser". Therefore the resolution is smaller.

    Recalculating the BaseBitmap with ScaleIt is one possible way, but I guess it needs extra time and I don't know if the quality will match the MatPreview.

    With "stored data" I meant, if there's a way to clone all settings of the original MatPreview to a custom made one?

    Kind regards,
    Svente



  • On 04/12/2017 at 08:59, xxxxxxxx wrote:

    Hello,

    as said above, the GUI displays the data of a data type (MaterialPreviewData). This data type is stored in a parameter of the material. The parameter ID is MATERIAL_PREVIEW. So you could read this parameter from the material to get that data.

    best wishes,
    Sebastian


Log in to reply