Render material preview in custom renderer



  • On 04/08/2016 at 07:07, xxxxxxxx wrote:

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

    ---------
    Hello everybody!

    I am currently working on my own custom renderer which only supports my custom material (let's call it MyMaterial).
    What I'm trying to do is to render the material preview of MyMaterial with my custom renderer.
    My first attempt was to set RDATA_RENDERENGINE to the plugin id of my renderer in MyMaterial's Message method as described here: https://developers.maxon.net/docs/Cinema4DCOFFEESDK/help/pages/RenderData/class_RenderData204.html

    Bool MyMaterial::Message(GeListNode* node, Int32 type, void* data)
    {
      
    ...
      
        if (type == MATPREVIEW_GENERATE_IMAGE)
        {
            MatPreviewGenerateImage* image = (MatPreviewGenerateImage* )data;
      
            if (image->pDoc)
            {
                BaseContainer bcRender = image->pDoc->GetActiveRenderData()->GetData();
    			
                bcRender.SetFloat(RDATA_XRES, image->pDest->GetBw());
                bcRender.SetFloat(RDATA_YRES, image->pDest->GetBh());
                bcRender.SetInt32(RDATA_ANTIALIASING, ANTI_GEOMETRY);
                 **bcRender.SetInt32(RDATA_RENDERENGINE, MY_RENDERER_ID);**
      
                image->pDest->Clear(0, 0, 0);
                image->lResult = RenderDocument(image->pDoc, bcRender, nullptr, nullptr, image->pDest, RENDERFLAGS_EXTERNAL | RENDERFLAGS_PREVIEWRENDER, image->pThread);
            }
      
            return true;
        }
      
    ...
      
    }
    

    I thought this would be enough to tell Cinema to use my renderer but apparently I was wrong.
    In fact it seems to ignore RDATA_RENDERENGINE completely as I can assign any long value to it and it will still use the default renderer.

    What am I doing wrong here?



  • On 04/08/2016 at 08:37, xxxxxxxx wrote:

    Hi Rico,

    here's how I do it:

      
      
         case MATPREVIEW_MODIFY_CACHE_SCENE:   
              {   
                   MatPreviewModifyCacheScene* scene = (MatPreviewModifyCacheScene* )data;   
      
                   // Just checking if the preview scene alread has the VP enabled   
                   if(GetCustomEngineVPData(scene->pDoc) != NULL)   
                   {   
                        return TRUE;   
                   }   
      
                   RenderData* rd = scene->pDoc->GetFirstRenderData();   
      
                   if(rd)   
                   {   
                        BaseVideoPost* customenginevp = BaseVideoPost::Alloc(CUSTOMENGINEVP);   
      
                        if(customenginevp)   
                        {   
                             rd->InsertVideoPost(customenginevp);   
      
                             customenginevp->DelBit(BIT_VPDISABLED);   
                        }   
                   }   
      
    


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

    Thank you for your answer fused!

    I tried the

    MATPREVIEW_MODIFY_CACHE_SCENE
    

    message you mentioned but it doesn't get called at all.

    Just to clarify what I want to do: Each time I change a setting of MyMaterial (eg. the Albedo Color) it should automatically render the new material with my renderer.



  • On 05/08/2016 at 01:30, xxxxxxxx wrote:

    Hello,

    as fused showed in his code you have to create the needed VideoPost yourself when you change the render engine. This is also discussed in the RenderData manual. (Please also make sure to use the C++ documentation and not the COFFEE documentation).

    The message MATPREVIEW_MODIFY_CACHE_SCENE is only sent if you set MatPreviewObjectInfo::bNoStandardScene to true when you react to MATPREVIEW_GET_OBJECT_INFO.

    Best wishes,
    Sebastian



  • On 05/08/2016 at 07:40, xxxxxxxx wrote:

    Hello,

    I just mentioned the COFFEE documentation link because i couldn't find this special thing in the C++ documentation.

    I have now set MatPreviewObjectInfo::bNoStandardScene and MatPreviewObjectInfo::bNeedsOwnScene to true. The MATPREVIEW_MODIFY_CACHE_SCENE gets called now but only once directly after i start Cinema and MATPREVIEW_GENERATE_IMAGE is never called. Fused's code however is still not rendering my material..
    (Note: I have not included the first if-statement from his code because I just wanted to test if my renderer gets called at all)

    I am quite new to this topic and I just cannot find what I need in the documentations so please be patient with me 🙂



  • On 05/08/2016 at 09:09, xxxxxxxx wrote:

    Hello,

    could you please post your code? Without seeing what you are doing it is hard to make any statement.

    Best wishes,
    Sebastian



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

    I am not quite sure which part of my code you need but here is another excerpt of MyMaterial's Message method:

    case MATPREVIEW_GET_OBJECT_INFO:
    {
        MatPreviewObjectInfo* info = (MatPreviewObjectInfo* )data;
        
        info->bHandlePreview = true;
        info->bNeedsOwnScene = true;
        info->bNoStandardScene = true;
        info->lFlags = 0;
      
        return true;
    }
      
    case MATPREVIEW_MODIFY_CACHE_SCENE:
    {	
        MatPreviewModifyCacheScene* scene = (MatPreviewModifyCacheScene* )data;
      
        RenderData* rd = scene->pDoc->GetFirstRenderData();
      
        if (rd)
        {
            BaseVideoPost* post= BaseVideoPost::Alloc(MY_RENDERER_ID);
      
            if (post)
            {
                rd->InsertVideoPost(post);
      
                post->DelBit(BIT_VPDISABLED);
            }
        }
      
        break;
    }
      
    case MATPREVIEW_GENERATE_IMAGE:
    {
        MatPreviewGenerateImage* image = (MatPreviewGenerateImage* )data;
      
        if (image->pDoc)
        {
            BaseContainer bcRender = image->pDoc->GetActiveRenderData()->GetData();
    	
            bcRender.SetFloat(RDATA_XRES, image->pDest->GetBw());
            bcRender.SetFloat(RDATA_YRES, image->pDest->GetBh());
            bcRender.SetInt32(RDATA_ANTIALIASING, ANTI_GEOMETRY);
            bcRender.SetInt32(RDATA_RENDERENGINE, MY_RENDERER_ID);
      
            image->pDest->Clear(0, 0, 0);
            image->lResult = RenderDocument(image->pDoc, bcRender, nullptr, nullptr, image->pDest, RENDERFLAGS_EXTERNAL | RENDERFLAGS_PREVIEWRENDER, image->pThread);
        }
      
        return true;
    }
    

    As a test i set a breakpoint in my render engine's Execute method but the breakpoint is never hit.

    All the best, Rico



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

    Hello Rico,

    I'm replacing Sebastian this week, unfortunately he's way more knowing on this topic than I am.
    But if I read the docs correctly, when setting bNoStandardScene to true, you are expected to deliver a scene in MATPREVIEW_MODIFY_CACHE_SCENE, which you are not doing. And actually it seems to me, as if this is all you should be doing in this message.

    And then in MATPREVIEW_GENERATE_IMAGE merge your current MATPREVIEW_MODIFY_CACHE_SCENE and MATPREVIEW_GENERATE_IMAGE, roughly like this:

    case MATPREVIEW_GENERATE_IMAGE:
    {
        MatPreviewGenerateImage* image = (MatPreviewGenerateImage* )data;
      
        if (image->pDoc)
        {
            RenderData* rd = image->pDoc->GetActiveRenderData();
            if (!rd)
                // handle error
      
            BaseVideoPost* post = BaseVideoPost::Alloc(MY_RENDERER_ID);
            if (post)
            {
                rd->InsertVideoPost(post);
                post->DelBit(BIT_VPDISABLED);
            }
      
            BaseContainer bcRender = rd->GetData();
    	
            bcRender.SetFloat(RDATA_XRES, image->pDest->GetBw());
            bcRender.SetFloat(RDATA_YRES, image->pDest->GetBh());
            bcRender.SetInt32(RDATA_ANTIALIASING, ANTI_GEOMETRY);
            bcRender.SetInt32(RDATA_RENDERENGINE, MY_RENDERER_ID);
      
            image->pDest->Clear(0, 0, 0);  // probably redundant
            image->lResult = RenderDocument(image->pDoc, bcRender, nullptr, nullptr, image->pDest, RENDERFLAGS_EXTERNAL | RENDERFLAGS_PREVIEWRENDER, image->pThread);
        }
    }
    


  • On 29/09/2016 at 06:47, xxxxxxxx wrote:

    Hello Andreas,

    sorry for my late response..

    We were finally able to solve the problem using the code you've provided.

    Thanks to everyone!


Log in to reply