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

    Sampling shader to Bitmap

    SDK Help
    0
    9
    799
    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 25/02/2016 at 01:56, xxxxxxxx wrote:

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

      ---------
      Hello.

      I have to sample a shader and create a bitmap based on that shader.
      The problem is that I get a small error in the very first line of pixels.
      I send you 2 images with the correct and the wrong version of the result:
      correct: https://dl.dropboxusercontent.com/u/432275/correct.png
      wrong: https://dl.dropboxusercontent.com/u/432275/wrong.png

      These 2 bitmaps are both 100x100 (for testing).
      For each pixel, i sample the shader using the corresponding texture coordinates.

      Here is the code that I use for sampling:

      unsigned int resolution_x = 100; //Testing
      unsigned int resolution_y = 100;
      			 
      BaseBitmap * bitmap = BaseBitmap::Alloc(); 
      IMAGERESULT init_result = bitmap->Init(resolution_x, resolution_y);
      if (init_result = IMAGERESULT_OK) {
      	InitRenderStruct irs;
      	shader->InitRender(irs);
      	ChannelData channel_data;
      	channel_data.off = 0;
      	channel_data.scale = 0;
      	channel_data.t = 0;
      	channel_data.texflag = TEX_TILE;
      	channel_data.p.z = 0;
      	channel_data.d = Vector(1,1,1);
      	channel_data.n = Vector(0,1,0);
      	channel_data.vd = NULL;
      				
      	for (unsigned int x = 0; x < resolution_x; ++x ) {
      		for (unsigned int y = 0; y < resolution_y; ++y ) {
      			channel_data.p.x = ((LReal)x)/(resolution_x-1) ;
      			channel_data.p.y = ((LReal)y)/(resolution_y-1)  ; //!!!!!!!
      			assert(channel_data.p.x <= 1 && channel_data.p.y <= 1 );
      			Vector color = shader->Sample(&channel_data);
      			bitmap->SetPixel(x, y, 255*color.x , 255*color.y , 255*color.z);				
      		}
      	}
        
      	shader->FreeRender();
      	if (bitmap->Save(Filename(file.c_str()), FILTER_PNG, NULL, SAVEBIT_0) == IMAGERESULT_OK) {
      		//image saved
      	}
      }
      

      Now, in the line i have marked with //!!!!! i add a small error correction value 0.001.
      That way i get the correct result.

      Why is this error correction value  needed and why is this needed only in Y texture coordinates ?

      Thank you for your time.

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

        On 25/02/2016 at 03:20, xxxxxxxx wrote:

        Hmm, not sure exactly (don't know the sampling code) but referencing "Blur Offset" and "Blur Scale" in a C4D material, the MIP radius should be something lower (around 0.01 or lower) than 1 (I'm guessing this might be the issue here).
        Also no TEX_TILE required right? Just pass 0.

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

          On 25/02/2016 at 07:09, xxxxxxxx wrote:

          Thank you very much for your response.

          I don't use this shader in a C4D material. I have create my own MaterialData. 
          Even with texflag set to 0, the issue persists (I still need to add 0.001 to Y tex coordinate).

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

            On 25/02/2016 at 10:01, xxxxxxxx wrote:

            Based on your usage of "assert". It looks like you are using raw C++ code rather than the SDK.
            By using a nested for() loop. You are also using the slowest possible code to handle images.
            If you must use raw C++ for some reason. I can't offer much advice. Because I would need to see the rest of your code.

            If you are open to using the SDK. There are some things I can give advice about.

            First:
            Consider using the GetPixelCnt() function inside of a single for() loop. It is much, much faster than using a nested for() loop.

            Second:
            This is a very simple way to render the shader to a bitmap

            //This is how to render the shader in a material to it's own bitmap image  
            //NOTE: even though it works fine. This is private and Not supported by Maxon(it may change in future releases)  
              
            #include "customgui_matpreview.h"  
              
              
              AutoAlloc<BaseBitmap> bitmap;  
              bitmap->Init(800,600);  
              
              BaseMaterial *mat = doc->GetFirstMaterial();  
              BaseShader *shader = mat->GetFirstShader();  
              
              BaseShader *clone = (BaseShader* )shader->GetClone(COPYFLAGS_0,nullptr);  
              
              RenderShaderPreview(doc->GetDocumentPath(),clone,shader,nullptr,bitmap,nullptr,0,RENDER_PREVIEW_USE_BMP_SIZE);  
              
              ShowBitmap(bitmap);  
              
              BaseShader::Free(clone);
            

            Third:
            I do have a custom method that samples the shader using the SDK and a nested for() loop.
            The code is similar to yours. But slightly different.
            *I did not write this myself. Someone posted it here a long time ago( maybe niklas? )

            //This is a custom method that is used to render the shader to a bitmap image  
              
            Bool RenderShader(BaseShader* shader, BaseBitmap* bmp, Real scale=1.0)  
            {  
              InitRenderStruct irs;  
              if(shader->InitRender(irs) != INITRENDERRESULT_OK) return FALSE;  
              
              LONG w = bmp->GetBw();  
              LONG h = bmp->GetBh();  
              ChannelData cd;  
              cd.p = Vector(0, 0, 0);  
              cd.n = Vector(0, 0, 1);  
              cd.d = Vector(0, 0, 0);  
              cd.t = 0.0;  
              cd.texflag = 0;  
              cd.vd = NULL;  
              cd.off = 0.0;  
              cd.scale = 0.0;  
              
              for (LONG x=0; x < w; x++)   
              {  
                  for (LONG y=0; y < h; y++)   
                  {  
                      cd.p.x = (Real) x * scale;  
                      cd.p.y = (Real) y * scale;  
                      Vector pixel = shader->Sample(&cd);  
              
                      LONG r = pixel.x * 255;  
                      LONG g = pixel.y * 255;  
                      LONG b = pixel.z * 255;  
                      bmp->SetPixel(x, y, r, g, b);  
                  }  
              }  
              
              ShowBitmap(bmp);  
              shader->FreeRender();  
              return TRUE;  
            }
            

            -ScottA

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

              On 25/02/2016 at 14:35, xxxxxxxx wrote:

              Hello and thank you very much for you help.

              This code works great for single planes but it doesn't for polygons.
              I didn't mention it earlier because I didn't know that was a different case, but the shader is depended on particles' positions.

              How can I generate the bitmap based on that restriction ?

              Thank you for your time.

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

                On 26/02/2016 at 01:51, xxxxxxxx wrote:

                Hello,

                what do you mean with "single planes" and "polygons"?

                If a shader depends on the world space position of the sampled fragment surface point (and the world space position of some other scene elements) one cannot bake this shader by just sampling the UV coordinates. For example a cube has the same UV coordinates for each face. But the effect of a shader like ambient occlusion may be different for each surface.

                Best wishes,
                Sebastian

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

                  On 26/02/2016 at 02:12, xxxxxxxx wrote:

                  Hello.

                  The most simple case that i have used is a plane (10x10 polygon object).
                  The particles are emitted and collided on that.
                  If I sample the shader with plane's UV coordinates, I can produce a bitmap that if used as a texture, it will give the same visual result with C4D's renderer.

                  Another case is when i use a Cube (10x10x10 polygon object).
                  Even if I unwrap it's UV texture (via BP UV Edit) and sample the shader with UV, the result totally wrong.

                  So, in every case I want to create a bitmap that will be used as texture and give the same result as in C4D renderer.

                  Is there any way to do that ?

                  Thank you.

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

                    On 26/02/2016 at 09:16, xxxxxxxx wrote:

                    Hello,

                    sampling a shader in UV-space will not get a meaningful result for every shader. Some shaders do not operate in UV space but in world space etc. For example the Proximal shader does not depend on any UV coordinates but on the position of the shaded fragment and the position of the referenced objects. Also a shader and a material could be assigned to any number of objects.

                    If you look at the material editor you see the shader preview. This preview is done by sampling the shader in UV space. For some shaders that's enough. But for some shaders not.

                    Best wishes,
                    Sebastian

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

                      On 28/02/2016 at 09:10, xxxxxxxx wrote:

                      Hello.

                      So, is it possible to create a bitmap based on a shader that operates in world space ?

                      Thank you.

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