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

    Noise() function is very slowwwww

    SDK Help
    0
    18
    1.2k
    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 16/05/2013 at 22:39, xxxxxxxx wrote:

      The C4DNoise allocator does not require a position vector as input, only the seed value. As littledevil already pointed
      out, you can (actually need to, because this is what makes it slow) allocate the C4DNoise once only instead of each
      and every time a color is calculated.

      What do you mean with "the turbulence() functions are allocated in the Output() method"?

      -Nik

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

        On 16/05/2013 at 23:31, xxxxxxxx wrote:

        I think I've got it figured out.
        I was trying to use the Noise() function inside of the InitRender() method. And that was tripping me up because the Noise() function requires a position parameter that I could not figure out how to satisfy inside of the the InitRender() method.

        I don't know why I was thinking that I HAD to use the Noise() function inside the InitRender() method along with the allocation.
        For some reason I thought I had to keep them together in the same scope. I guess I do that kind of thing so often that I've developed a habit. And forgot that I don't have to keep them together like that.

        If I allocate a C4DNoise instance in InitRender(). And then keep my Noise() function inside the Output() method. It all seems to work fine. And it's not slow anymore.

        -ScottA

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

          On 17/05/2013 at 00:17, xxxxxxxx wrote:

          If you allocate it in InitRender() (which is the right way to do it), do NOT forget to free it in FreeRender(), otherwise you will end up with a nice pile of memory leaks, that eat up more and more memory with every render.

          Remember to use the -debug command line parameter (which used to be c4d_debug.txt) to have the console window come up and do some memory tracing.

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

            On 17/05/2013 at 07:56, xxxxxxxx wrote:

            I've always used the c4d_debug.txt file to do my debugging. But I would like to try using the command line approach to see if I like it better.
            But the problem is I've never done this before. And I don't know how to do it.

            After searching around for a bit. I found some examples for plain C++

            `int main(int argc, char** argv)
            

            But C4D plugins don't have an int main() function. So I don't know how to set it up.
            And then I'm not sure how to use it.
            In the C++ examples I'm finding. They are peppered with commands throughout the code.
            Is there a way to have the entire plugin be checked for memory leaks with one -debug instance like the c4d_debug.txt works?

            -ScottA
            `

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

              On 17/05/2013 at 08:14, xxxxxxxx wrote:

              Call Cinema 4D from the command-line just like you would call any other program from the command-line.

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

                On 17/05/2013 at 08:35, xxxxxxxx wrote:

                Ah. Ok.
                I was confusing "command args" with "command line". !LOL[URL-REMOVED]

                Thanks,
                -ScottA


                [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

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

                  On 17/05/2013 at 09:49, xxxxxxxx wrote:

                  Since there are no examples in the SDK for how to use the Noise() function.
                  I'm posting a simple example. Just in case anyone needs it:

                    
                  //This is an example of using the Noise() function in a shader plugin  
                    
                  #include "c4d.h"  
                  #include "c4d_symbols.h"  
                  #include "myshader.h"  
                  #include "lib_noise.h"  
                    
                  #define PLUGIN_ID 1000000  //temp ID only!!!  
                    
                    
                  class MyShader : public ShaderData  
                  {  
                    private:   
                    C4DNoise *mynoise;  
                    
                    public:  
                        virtual Bool               Init(GeListNode *node);  
                        virtual    Vector             Output(BaseShader *chn, ChannelData *cd);  
                        virtual    INITRENDERRESULT   InitRender(BaseShader *sh, const InitRenderStruct &irs);  
                        virtual    void               FreeRender(BaseShader *sh);  
                    
                        static NodeData *Alloc(void) { return gNew MyShader; }  
                  };  
                    
                  Bool MyShader::Init(GeListNode *node)  
                  {  
                    BaseContainer *data = ((BaseShader* )node)->GetDataInstance();  
                    
                    mynoise = NULL;  
                    
                    return TRUE;  
                  }  
                    
                  INITRENDERRESULT MyShader::InitRender(BaseShader *sh, const InitRenderStruct &irs)  
                  {  
                    BaseContainer *data = sh->GetDataInstance();  
                    
                    LONG seed = 555;  
                    mynoise = C4DNoise::Alloc(seed);  
                      
                    return INITRENDERRESULT_OK;  
                  }  
                    
                  Vector MyShader::Output(BaseShader *chn, ChannelData *cd)  
                  {      
                    Vector p = cd->p;  
                    p *= 10;            //The number of repeats  
                    
                    Real n = mynoise->Noise(NOISE_CRANAL, FALSE, p, 0.0, 1.0, FALSE, 0.25, 0.25, 0);  
                    
                    return Vector(n);  
                  }  
                    
                  void MyShader::FreeRender(BaseShader *sh)  
                  {  
                    mynoise->Free(mynoise);  
                  }  
                    
                  Bool RegisterShaderPlugin(void)  
                  {  
                    return RegisterShaderPlugin(PLUGIN_ID,GeLoadString(IDS_MY_SHADER),0, MyShader::Alloc,"myshader",0);  
                  }
                  

                  -ScottA

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

                    On 17/05/2013 at 10:07, xxxxxxxx wrote:

                    Scott, I'm so confused when you say "function" everytime, because this word relates to a global
                    function in the usual terms. The Noise() "function" is a method in this case, a method of the
                    C4DThread class. 🙂

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

                      On 17/05/2013 at 10:16, xxxxxxxx wrote:

                      Dangerous, Scott 🙂

                      You should definitely check 'mynoise' for NULL after allocating it in InitRender(), and then return INITRENDERRESULT_OUTOFMEMORY if it's NULL. If I think about it, you should always check all pointers for NULL:

                        
                      INITRENDERRESULT MyShader::InitRender(BaseShader *sh, const InitRenderStruct &irs;)   
                      {   
                          if (!sh)   
                              return INITRENDERRESULT_OUTOFMEMORY;   
                          BaseContainer *data = sh->GetDataInstance();   
                        
                          LONG seed = 555;   
                          mynoise = C4DNoise::Alloc(seed);   
                          if (!mynoise)   
                              return INITRENDERRESULT_OUTOFMEMORY;   
                             
                          return INITRENDERRESULT_OK;   
                      }   
                      

                      The line in FreeRender() will probably not work. Since Free() is a static function of the BaseShader class, it has to be as follows (also add a NULL check here, just in case).

                      void MyShader::FreeRender(BaseShader *sh)   
                      {   
                          if (mynoise) BaseShader::Free(mynoise);   
                      }
                      

                      And as a last tip: I would not set the mynoise pointer to NULL in the Init() function. To have a defined state of the MyShader class after allocation, you must initialize all members in the class constructor. Also use the INSTANCEOF() macro to indicate that your shader class is an instance of BaseShader. That enables you to use SUPER to call the parent class' functions (shown further down in Init()).

                        
                      class MyShader : public ShaderData   
                      {   
                          INSTANCEOF(MyShader, BaseShader)   
                        
                          private:   
                          C4DNoise *mynoise;   
                        
                          public:   
                              virtual Bool               Init(GeListNode *node);   
                              virtual    Vector             Output(BaseShader *chn, ChannelData *cd);   
                              virtual    INITRENDERRESULT   InitRender(BaseShader *sh, const InitRenderStruct &irs;);   
                              virtual    void               FreeRender(BaseShader *sh);   
                        
                              static NodeData *Alloc(void) { return gNew MyShader; }   
                        
                              MyShader() : mynoise(NULL)   
                              { }   
                      };   
                      

                      Use Init() only to initialize (= set default values for) the parameters in your shader's BaseContainer. And again, an additional NULL pointer check for 'data'.

                        
                      Bool MyShader::Init(GeListNode *node)   
                      {   
                          BaseContainer *data = ((BaseShader* )node)->GetDataInstance();   
                          if (!   
                        
                          // Set default parameters in 'data' here   
                          data->SetReal(MYSHADER_PARAMETER_BLAH, 1.0);   
                          data->SetLong(MYSHADER_PARAMETER_FOOBAR, 123);   
                        
                          return SUPER::Init(node);   
                      }   
                      
                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 17/05/2013 at 10:30, xxxxxxxx wrote:

                        I'm just curious: Why does the C4D API use the INSTANCEOF() macro? In my humble opinion, it
                        is doing some "hidden magic" (which is what macros always do) and this one is making even darker
                        magic. From the name itself it is almost not possible to conclude it typedefs the parent class as
                        SUPER.

                        > typedef ShaderData SUPER;

                        So clear, and even a bit shorter. 🙂

                        -Nik

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

                          On 17/05/2013 at 10:49, xxxxxxxx wrote:

                          Thanks Frank.
                          The code I posted works works fine for me with no memory leaks. But I do admit that it's very lean, and not using of defensive code.

                          I didn't now that about the INSTANCEOF() macro.
                          That code has always been a bit of a mystery to me about what it's really used for.

                          I do usually use the style:  type::Free(instance) to free allocated memory.
                          And I only do it that way because that's how other people use it. Not knowing why I'm using it that way. Rather than using the style: mynoise- >Free(mynoise);
                          Most of the time I can't use the style: mynoise->Free(mynoise); because it doesn't free the memory.
                          But in this case it worked. So that's what I used.
                          But I really don't have a good grasp of why one style works. And one style doesn't.
                          I'm self taught. And C++ memory management is something I've never really understood properly.

                          -ScottA

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

                            On 17/05/2013 at 10:58, xxxxxxxx wrote:

                            Originally posted by xxxxxxxx

                            I didn't now that about the INSTANCEOF() macro.
                            That code has always been a bit of a mystery to me about what it's really used for.

                            And here's my proof, thanks Scott. 😉 The INSTANCEOF() macro is one of the most confusing things
                            I have seen in the C4D API. 😄

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

                              On 17/05/2013 at 12:42, xxxxxxxx wrote:

                              Nah, it's not confusing. It just enables you to use SUPER::blah() instead of ShaderData::Blah(). You don't have to use it, but it saves you some typing work, especially if you override more functions than just one. No voodoo going on here.

                              If you ever wonder what stuff does, just look up how it's defined.

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

                                On 17/05/2013 at 12:48, xxxxxxxx wrote:

                                class MyShader : public ShaderData {
                                  
                                    typedef ShaderData SUPER;
                                    INSTANCEOF(MyShader, ShaderData);
                                  
                                };
                                

                                Shorter! 🙂 And those lines are equal. Of course if you know very well what the macro does, this
                                line won't interfere you while analyzing code. But for someone just getting started in C++, this
                                is very confusing because

                                1. he doesn't know what the macro does, and it's name is not really implying that it typedefs the
                                base class to SUPER. Yes, this is in the documentation, but having to look up what a macro
                                actually does is IMHO a bad design. Though, this is really just my subjective opinion.
                                2. he wonders why the compiler complains that SUPER is not defined when he is creating is first
                                subclass (he obviously forgot about the INSTANCEOF() part).

                                That's at least what I remember from back then. Until I actually saw the definition line in the C4D
                                header files, I assumed it to be some black magic.

                                Best,
                                -Niklas

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

                                  On 18/05/2013 at 04:38, xxxxxxxx wrote:

                                  Originally posted by xxxxxxxx

                                  but having to look up what a macro actually does is IMHO a bad design

                                  If you don't look it up, how would you ever know what it does (except if it's indicated by the macro's name)? That is not bad design, it just normal to look things up. There are functions and macros and structures and lots of other stuff... if you don't know what they are for, look it up. It's just one click.

                                  If you only assume what stuff is good for, without verifying your assumptions, and then considering stuff black magic based on your assumption, you should rethink your strategy. Remember that old saying: "Every catastrophe's beginning is a s**tty assumption."

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