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

    Shader referencing

    Scheduled Pinned Locked Moved SDK Help
    10 Posts 0 Posters 904 Views
    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 Offline
      Helper
      last edited by

      THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

      On 25/11/2012 at 08:27, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:    
      Platform:      
      Language(s) :

      ---------
      When a Shader is referenced from another shader, the referenced shader must be a child of the
      referencing shader, is that correct?

      If so, how can I reference a shader multiple times? A single shader can technically not be child of
      more than one other shader.

      Thanks,
      Nik

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

        THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

        On 26/11/2012 at 11:39, xxxxxxxx wrote:

        Exactly, that's why you can't do it without risking to cause instability.
        You will have to clone the shader.

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

          THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

          On 26/11/2012 at 13:07, xxxxxxxx wrote:

          Thank you for the answer, Jack.

          I am already cloning the shader internally when InitRender() is called. I think this is
          necessary because it could happen that InitRender() is called multiple times on the
          referenced shader.

          I do not understand the mechanics behind the shader referencing. Inserting the cloned
          shader on InitRender() as a child does not work. When the referenced shader
          is from a custom channel on the material, it works.

              def InitRender(self, shader, irs) :  
                reference = shader[c4d.REFERENCESHADER_REFERENCE]  
                if reference:  
                    self.internal_reference = reference.GetClone()  
                    self.internal_reference.InsertUnder(shader)  
                    return self.internal_reference.InitRender(irs)  
                else:  
                    self.internal_reference = None  
                    return c4d.INITRENDERRESULT_OK  
            
            def FreeRender(self, shader) :  
                if self.internal_reference:  
                    self.internal_reference.FreeRender()  
                    self.internal_reference.Remove()  
                    self.internal_reference = None
          

          As mentioned, this does not work. But when inserting the referenced shader (not
          the clone of the referenced shader) as a child, it works.

          Can you please enlighten me about what I miss, or is this not possible?

          Thank you very much,
          Niklas

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

            THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

            On 30/11/2012 at 12:37, xxxxxxxx wrote:

            Bumb. Do you have an idea why it doesn't work using an internal clone of the shader?

            Thanks, 
            Nik

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

              THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

              On 01/12/2012 at 03:29, xxxxxxxx wrote:

              If anything then you would have to use SetParent() to define a parent node for the shader. Still I don't think it will work. You just have to use clones from the beginning.

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

                THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

                On 04/12/2012 at 14:00, xxxxxxxx wrote:

                Hi Jack,

                I've rewritten the plugin in C++. Using SetParent() does not work, assuming that I've
                done it correctly..? It not just crashes Cinema, but also makes my PC hang up completely.

                INITRENDERRESULT ShaderLinkData::InitRender(BaseShader* shader, const InitRenderStruct& irs) {  
                  if (!shader) {  
                      return INITRENDERRESULT_UNKNOWNERROR;  
                  }  
                  BaseDocument* doc = shader->GetDocument();  
                  if (!doc) {  
                      return INITRENDERRESULT_UNKNOWNERROR;  
                  }  
                  
                  // Grab the refernce from the container.  
                  BaseContainer* container = shader->GetDataInstance();  
                  BaseShader* reference = (BaseShader* ) container->GetLink(SHADERLINK_REFERENCE, doc);  
                  
                  if (reference) {  
                      // Clone the referenced shader and ensure it succeeded.  
                      this->internal_reference = (BaseShader* ) reference->GetClone(COPYFLAGS_0, NULL);  
                      if (!this->internal_reference) {  
                          return INITRENDERRESULT_OUTOFMEMORY;  
                      }  
                  
                      // Insert the cloned shader as child, which is necessary to render  
                      // the shader correctly.  
                      this->internal_reference->InsertUnder(shader);  
                      GeListHead* head = this->internal_reference->GetListHead();  
                      if (head) {  
                          head->SetParent(shader);  
                      }  
                  
                      // Initialize the rendering with the passed InitRenderStruct.  
                      return this->internal_reference->InitRender(irs);  
                  }  
                  else {  
                      this->internal_reference = NULL;  
                  }  
                  
                  return INITRENDERRESULT_OK;  
                }
                

                I'm not quite sure what you mean with saying "cloning from the beginning" ?

                Thank you very much,
                Niklas

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

                  THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

                  On 04/12/2012 at 14:33, xxxxxxxx wrote:

                  This looks somewhat better, I think. But it still does not work when the referenced shader
                  is not from the materials "custom channel".

                          // Insert the cloned shader as child, which is necessary to render  
                        // the shader correctly.  
                        this->internal_reference->InsertUnder(shader);  
                        GeListHead* head = reference->GetListHead();  
                        if (head) {  
                            GeListNode* parent = head->GetParent();  
                            GeListHead* refparent = this->internal_reference->GetListHead();  
                            refparent->SetParent(parent);  
                        }
                  

                  Thanks,
                  Nik

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

                    THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

                    On 05/12/2012 at 12:20, xxxxxxxx wrote:

                    Hello,

                    Can somebody please enlighten me about what exactly goes up when
                    GeListNode::InsertUnder() is called? Because, when I inserted the referenced
                    shader under my plugin shader, and clone the referenced shader internally
                    on ShaderData::InitRender() , but do not create any relationships with the clone
                    (i.e. I do not insert the cloned shader as child of my plugin shader), it works fine.
                    And it works fine, although the cloned shader, which is used for sampling, does,
                    or actually should not , know anything related to my plugin shader.

                    I could be satisfied with this, if it wouldn't scratch on Cinema's stability, but it
                    does. Almost always when the ShaderLink shader was used, closing Cinema 4D
                    will lead in undefined behavior and finally into a crash.

                    What I would like to do, is to find a way to build up the necessary relationships
                    without drowning Cinema's stability, by producing valid results. (I.e. inserting an
                    already inserted shader under my plugin shader, as I'm doing it, is not valid).
                    It seems like GeListNode::InsertUnder() does build up the relationships correctly,
                    but I am not able to reproduce it, since I do not know enough about the internals
                    or how the relationships must be built. The SDK documentation is leaking this
                    information.

                    In the following, you can find the code that results in satisfying results when
                    rendering (i.e. the referenced shader is always rendered and not just black,
                    the channel-preview is updated when the referenced shader is changed), but
                    involves easily crashing Cinema 4D.

                    // coding: utf-8  
                    //  
                    // Copyright (C) 2012, Niklas Rosenstein <[email protected]>  
                      
                    #include <c4d.h>  
                      
                    #include "ShaderLink.h"  
                    #include "res/c4d_symbols.h"  
                      
                    class ShaderLinkData : public ShaderData {  
                      
                      private:  
                      
                      typedef ShaderData super;  
                      
                      BaseShader* iref;  
                      
                      public:  
                      
                      static NodeData* Alloc();  
                      
                      ShaderLinkData() : super(), iref(NULL) {  
                      };  
                      
                      void AdjustShaderReference(BaseShader* shader);  
                      
                      // ShaderData  
                      
                      INITRENDERRESULT InitRender(BaseShader* shader, const InitRenderStruct& irs);  
                      
                      void FreeRender(BaseShader* shader);  
                      
                      Vector Output(BaseShader* shader, ChannelData* data);  
                      
                      // NodeData  
                      
                      Bool Init(GeListNode* node);  
                      
                      Bool Message(GeListNode* node, LONG type, void* data);  
                      
                    };  
                      
                    // ShaderLinkData  
                      
                    NodeData* ShaderLinkData::Alloc() {  
                      return gNew ShaderLinkData;  
                    }  
                      
                    void ShaderLinkData::AdjustShaderReference(BaseShader* shader) {  
                      BaseDocument* doc = shader->GetDocument();  
                      BaseContainer* container = shader->GetDataInstance();  
                      if (!container || !doc) return;  
                      
                      BaseShader* reference = (BaseShader* ) container->GetLink(SHADERLINK_REFERENCE, doc, Xbase);  
                      if (!reference) return;  
                      
                      // Check if the referenced shader is already a child of the plugin shader.  
                      BaseShader* child = shader->GetDown();  
                      Bool reference_ischild = FALSE;  
                      LONG childcount = 0;  
                      while (child) {  
                          if (child == reference) {  
                              reference_ischild = TRUE;  
                              break;  
                          }  
                          childcount++;  
                          child = child->GetNext();  
                      }  
                      
                      GePrint("The shader has " + LongToString(childcount) + " children.");  
                      
                      // Insert the referenced shader as child if it isn't already.  
                      if (!reference_ischild) {  
                     **         reference->InsertUnder(shader);**  
                      }  
                    }  
                      
                    // ShaderLinkData - ShaderData  
                      
                    INITRENDERRESULT ShaderLinkData::InitRender(BaseShader* shader, const InitRenderStruct& irs) {  
                      if (!shader) {  
                          return INITRENDERRESULT_UNKNOWNERROR;  
                      }  
                      BaseDocument* doc = shader->GetDocument();  
                      if (!doc) {  
                          return INITRENDERRESULT_UNKNOWNERROR;  
                      }  
                      BaseContainer* container = shader->GetDataInstance();  
                      if (!container) {  
                          return INITRENDERRESULT_UNKNOWNERROR;  
                      }  
                      
                      // Grab the reference from the container.  
                      BaseShader* reference = (BaseShader* ) container->GetLink(SHADERLINK_REFERENCE, doc, Xbase);  
                     **     if (reference) {  
                          this->iref = (BaseShader* ) reference->GetClone(COPYFLAGS_0, NULL);  
                          if (!this->iref) {  
                              return INITRENDERRESULT_OUTOFMEMORY;  
                          }  
                      
                          return this->iref->InitRender(irs);  
                      }**  
                      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();  
                          BaseShader::Free(this->iref);  
                          this->iref = NULL;  
                      }  
                    }  
                      
                    Vector ShaderLinkData::Output(BaseShader* shader, ChannelData* data) {  
                      // Redirect the ShaderData::Output() class to the reference shader or  
                      // return black color.  
                      if (this->iref) {  
                          return this->iref->Sample(data);  
                      }  
                      else {  
                          return Vector(0.0);  
                      }  
                    }  
                      
                    // ShaderLinkData - NodeData  
                      
                    Bool ShaderLinkData::Init(GeListNode* node) {  
                      if (!node) return FALSE;  
                      BaseShader* shader = (BaseShader* ) node;  
                      BaseContainer* container = shader->GetDataInstance();  
                      if (!container) return FALSE;  
                      
                      // Initialize the shaders parameters.  
                      container->SetLink(SHADERLINK_REFERENCE, NULL);  
                      return TRUE;  
                    }  
                      
                    Bool ShaderLinkData::Message(GeListNode* node, LONG type, void* data) {  
                      if (type == MSG_DESCRIPTION_POSTSETPARAMETER) {  
                          this->AdjustShaderReference((BaseShader* )node);  
                      }  
                      return super::Message(node, type, data);  
                    }
                    

                    The complete source code, including res-files, is located here. It does
                    not contain a Visual Studio project or similar, as I'm building from the
                    command-line.

                    The zip-file located at the link above contains prebuilt binaries for
                    Windows x86 and x64, built with Cinema 4D R14.025.

                    I appreciate any help and information regarding this topic.

                    Thanks,
                    Niklas

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

                      THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

                      On 05/12/2012 at 13:01, xxxxxxxx wrote:

                      I think it's still somewhat unclear.. The problems I'm having when commenting out the
                      this- >AdjustShaderReference((BaseShader* )node); line in ShaderLinkData::Message(),
                      is that the material preview is just black instead of rendered with the black shader. The
                      next thing is, that when parameters on the referenced shader have changed, the channel
                      preview and the texture in the editor does not change (is not re-rendered).

                      I've added three lines in InitRender() to show some states in the console.

                          // Grab the reference from the container.  
                        BaseShader* reference = (BaseShader* ) container->GetLink(SHADERLINK_REFERENCE, doc, Xbase);  
                       **     String docname = doc->GetDocumentName().GetString();**  
                        if (reference) {  
                       **         GePrint("InitRender() : Document(" + docname + "), reference available, cloning..");**  
                            this->iref = (BaseShader* ) reference->GetClone(COPYFLAGS_0, NULL);  
                            if (!this->iref) {  
                                return INITRENDERRESULT_OUTOFMEMORY;  
                            }  
                        
                            return this->iref->InitRender(irs);  
                        }  
                        else {  
                       **         GePrint("InitRender() : Document(" + docname + "), no reference available!");**  
                            this->iref = NULL;  
                        }
                      

                      The line mentioned above, which inserts the referenced shader under my plugin shader,
                      is commented out, therefore the referenced shader is not invalidly a child of it and
                      the results are "valid" in that manner.

                      You can find a little video showing what happens

                      (youtube link).

                      I can think of the reasons for this issues. The material preview is black because the
                      referenced shader from the link field can not be obtained from the material preview
                      document.
                      The channel preview and editor preview does not update because they do not get
                      informed about the change of the referenced shader.

                      But I don't know a solution to this. Both issues are solved when the referenced
                      shader is inserted under my plugin shader, but this makes Cinema instable.

                      Thanks in advance,
                      Niklas

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

                        THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

                        On 05/12/2012 at 13:17, xxxxxxxx wrote:

                        🙂

                        I was able to work arond the first issue (that the shader could not be referenced
                        and rendered from the material preview) by saving the address of the referenced
                        shader in the ShaderData itself, instead of retrieving it from the container on
                        InitRender(). I had to copy this value from the old to the new instance when it is
                        copied in NodeData::CopyTo().

                        I have fears that it could happen that the referenced shader becomes deallocated
                        and my shader plugin won't notice this, and therefore still owns the address to the
                        already deallocated shader. Could this happen?

                        // EDIT: There you go. Removing the referenced shader from the document crashes
                        Cinema..    .___.''

                        The important parts that have changed:

                        INITRENDERRESULT ShaderLinkData::InitRender(BaseShader* shader, const InitRenderStruct& irs) {  
                          // ...  
                          // Clone the reference if available.  
                         **     BaseShader* reference = this->lref;**  
                          if (reference) {  
                              this->iref = (BaseShader* ) reference->GetClone(COPYFLAGS_0, NULL);  
                              if (!this->iref) {  
                                  return INITRENDERRESULT_OUTOFMEMORY;  
                              }  
                          
                              return this->iref->InitRender(irs);  
                          }  
                          // ...  
                          return INITRENDERRESULT_OK;  
                        }  
                          
                        Bool ShaderLinkData::Message(GeListNode* node, LONG type, void* data) {  
                          BaseShader* shader = (BaseShader* ) node;  
                          if (!shader) {  
                              return FALSE;  
                          }  
                          if (type == MSG_DESCRIPTION_POSTSETPARAMETER) {  
                         **         BaseDocument* doc = shader->GetDocument();  
                              BaseContainer* container = shader->GetDataInstance();  
                              if (!doc || !container) return FALSE;  
                              this->lref = (BaseShader* ) container->GetLink(SHADERLINK_REFERENCE, doc, Xbase);**  
                          }  
                          return super::Message(node, type, data);  
                        }  
                          
                        Bool ShaderLinkData::CopyTo(NodeData* n_dest, GeListNode* source_node, GeListNode* dest_node, COPYFLAGS flags, AliasTrans* atrns) {  
                          if (!n_dest) {  
                              return FALSE;  
                          }  
                         **     ShaderLinkData* dest = (ShaderLinkData* ) n_dest;  
                          dest->lref = this->lref;**  
                          
                          return super::CopyTo(dest, source_node, dest_node, flags, atrns);  
                        }
                        

                        The problem with the update in the editor and the channel preview still remains. Is
                        there a way I can add a "dependency" to these, therefore telling them they should
                        update when the referenced shaders' parameters change?

                        Thanks,
                        Niklas

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