Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Cloned layer shader, InitRender() missing assets

    SDK Help
    0
    12
    854
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 10/01/2013 at 11:55, xxxxxxxx wrote:

      I may be quite wrong but I don't think that will work. IIRC, you can't have two materials or two shaders pointing at the same shader. In other words, you initially have a layer shader with a link to a second shader. When you clone the layer shader the clone (this is where I'm guessing BTW) still points to the original second shader. So you now have two layer shaders pointing at the same sub-shader, for want of a better word, and I don't think that's allowed.

      I think this is one of the reasons no-one has yet developed a node-based material system in Cinema, because you would need to be able to do that.

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 10/01/2013 at 12:15, xxxxxxxx wrote:

        Hello spedler,
        I do think the sub-shaders are cloned as well, because they actually are children of the Layer
        shader (layerShader->GetDown() returns one of the sub-shaders). Anyway, I'll check this to be sure,
        thanks!

        Edit: Unfortunately your guess is not right. 😞 I've tested it with a Layer shader containg a single
        sub-shader. Thank you anyway!

          
        BaseShader* child_src = reference->GetDown();  
        BaseShader* child_ref = this->iref->GetDown();  
        if (child_src == child_ref) {  
        GePrint("WARNING: Children were NOT cloned!");  
        }  
        else {  
        GePrint("OK: Children were cloned!");  
        }
        

        -Nik

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 11/01/2013 at 01:24, xxxxxxxx wrote:

          That's interesting, I didn't think the sub-shader would be cloned. Useful to know for the future but doesn't help you much at the moment, sorry.

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 15/01/2013 at 09:25, xxxxxxxx wrote:

            Bump. :nerd:

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 28/01/2013 at 04:57, xxxxxxxx wrote:

              I'm still searching for a solution to this..

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 28/01/2013 at 07:48, xxxxxxxx wrote:

                Hi Niklas,

                I can't reproduce this behavior. I've been able to clone a layer shader and init it for render from a CommandData::Execute().

                In what type of plugin data and method are you cloning layer shaders?
                If I understand it always fails with layer shaders but works with any other type of shader, right?

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 28/01/2013 at 08:43, xxxxxxxx wrote:

                  Hello Yannick,

                  >>>  I've been able to clone a layer shader and init it for render from a CommandData::Execute().

                  Interesting. Thanks for checking this. I am doing this operation in my ShaderData subclass on
                  InitRender(). More specifically, the InitRenderStruct that is passed there is passed through to the
                  layer shader.

                  This is the complete InitRender() function:

                  INITRENDERRESULT ShaderLinkData::InitRender(BaseShader\* shader, const InitRenderStruct& irs) {
                      if (!shader) return INITRENDERRESULT_UNKNOWNERROR;
                      BaseDocument\* doc = shader->GetDocument();
                      BaseContainer\* container = shader->GetDataInstance();
                      if (!container || !doc) return INITRENDERRESULT_UNKNOWNERROR;
                  
                      // Clone the reference if available.
                      BaseShader\* reference = this->GetReferenceShaderInstance(shader, container, doc);
                      if (reference) {
                          this->iref = (BaseShader\*) reference->GetClone(COPYFLAGS_0, NULL);
                          if (!this->iref) {
                              return INITRENDERRESULT_OUTOFMEMORY;
                          }
                  
                          INITRENDERRESULT result = this->iref->InitRender(irs);
                          if (result != INITRENDERRESULT_OK) {
                              GePrint("ERROR, this->iref->InitRender() returned " + LongToString(result));
                          }
                          return result;
                      }
                      else {
                          this->iref = NULL;
                      }
                  
                      return INITRENDERRESULT_OK;
                  }
                  

                  The GetReferenceShaderInstance() method basically just grabs a shader from a linkfield in the
                  shaders description. Later in ShaderData::Output(), I use iref->Sample() to output what the
                  cloned shader would output, but that is just yellow when a layer shader is used as reference
                  (and the error message  from the code above is printed to the console).

                  Would you like to take a look at the complete source-code? I'd prefer to make it not public, yet.

                  Thanks!
                  -Niklas

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 28/01/2013 at 09:00, xxxxxxxx wrote:

                    Yes, you can send the complete source code to [email protected].
                    It will help me reproduce the issue.

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 30/01/2013 at 02:35, xxxxxxxx wrote:

                      I see two issues in your code:

                      First, you don't pass an alias translator to GetClone(), so even though the children get cloned, too, all the child links will be broken. The Layer Shader returns INITRENDERRESULT_ASSETMISSING if a child link is dead.
                      Therefore, you have to allocate and initialize an AliasTrans first, and use it in GetClone().

                      Second, to successfully initialize and use a shader in a document, you have to insert it into the document's node structure, too. Otherwise, the renderer might be unable to find it.
                      To do that, allocate a GeListHead, initialize it with the render document and insert your shader clone.

                      Don't forget to remove and free all the cloned stuff after the rendering has finished.

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 30/01/2013 at 03:44, xxxxxxxx wrote:

                        Hello Frank,

                        thanks for your answer. Your explanation makes sense to me.

                        I didn't pass an AliasTrans, because I didn't insert the cloned shader into the document. I
                        concluded that the established links would be invalid anyway in this case.

                        AWESOME! It works!
                        First, I was a little-bit irritated when you said "initialize the GeListHead with the document". But I
                        think you were talking of the GeListHead::SetParent() method, is that correct?

                        Here's the working code:

                            INITRENDERRESULT ShaderLinkData::InitRender(BaseShader\* shader, const InitRenderStruct& irs) {
                                if (!shader) return INITRENDERRESULT_UNKNOWNERROR;
                                BaseDocument\* doc = shader->GetDocument();
                                BaseContainer\* container = shader->GetDataInstance();
                                if (!container || !doc) return INITRENDERRESULT_UNKNOWNERROR;
                        
                                // Clone the reference if available.
                                BaseShader\* reference = this->GetReferenceShaderInstance(shader, container, doc);
                                if (reference) {
                        **AutoAlloc <AliasTrans> aliastrans;
                                    if (!aliastrans) return INITRENDERRESULT_OUTOFMEMORY;
                                    if (!aliastrans->Init(doc)) return INITRENDERRESULT_UNKNOWNERROR;**
                        
                                    this->iref = (BaseShader\* ) reference->GetClone(COPYFLAGS_0, **aliastrans** );
                                    if (!this->iref) {
                                        return INITRENDERRESULT_OUTOFMEMORY;
                                    }
                                    **aliastrans- >Translate(TRUE);**
                        
                                    **this- >irefHead = GeListHead::Alloc();
                                    if (!this->irefHead) {
                                        BaseShader::Free(this->iref);
                                        return INITRENDERRESULT_OUTOFMEMORY;
                                    }
                                    this->irefHead->InsertFirst(this->iref);
                                    this->irefHead->SetParent(doc);**
                        
                                    INITRENDERRESULT result = this->iref->InitRender(irs);
                                    String name = reference->GetName();
                                    if (result != INITRENDERRESULT_OK) {
                                        GeDebugOut("Shader '" + name + "' was not initialized. Error-code: " + LongToString(result));
                                    }
                                    else {
                                        GeDebugOut("Shader '" + name + "' was initialized.");
                                    }
                                    return result;
                                }
                                else {
                                    this->iref = NULL;
                                }
                        
                                return INITRENDERRESULT_OK;
                            }
                        
                            void ShaderLinkData::FreeRender(BaseShader\* shader) {
                                // Free the internal reference when it was allocated.
                                if (this->iref) {
                                    this->iref->FreeRender();
                                    **this- >iref->Remove();**
                                    BaseShader::Free(this->iref);
                                    this->iref = NULL;
                                }
                        **if (this- >irefHead) {
                                    GeListHead::Free(this->irefHead);
                                    this->irefHead = NULL;
                                }**
                            }
                        

                        Thank you very much! This has given me some new insight into how Cinema internally works. 🙂
                        -Niklas

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post