Sample shader with modified ChannelData

  • On 28/04/2015 at 09:27, xxxxxxxx wrote:

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

    I want to sample a shader in my shader but with different UV coordinates than the ones requested 
    for my shader. Modifying ChannelData::p doesn't change anything (strangely) (and also the SDK says it's

    Any idea how to do it?

    Update: Nevermind, the problem is the Noise shader. Everything else seems to work fine. I am only
    wondering why it won't work for the Noise shader (even if I change it to UV space)

  • On 29/04/2015 at 08:55, xxxxxxxx wrote:


    if you could share the code you use to sample the shader we might be able to find out what is going wrong.

    Best wishes,

  • On 29/04/2015 at 10:12, xxxxxxxx wrote:

    Hi Sebastian,

    I've doctored this code since the actual codebase is much larger and more complex. But
    basically it mimics what a certain code branch will do:

    virtual Vector Output(BaseShader* shader, ChannelData* cd) {
      if (!shader || !cd) return Vector(1.0, 0, 0);
      BaseContainer* bc = shader->GetDataInstace();
      if (!bc) return Vector(1.0, 1.0, 0);
      BaseShader* subShader = static_cast<BaseShader*>(
        bc->GetLink(MYSHADER_SUBSHADER, shader->GetDocument(), Xbase));
      if (!subShader) return Vector(0.0, 1.0, 0);
      static const Int32 stepu = 1.0 / 6;
      static const Int32 stepv = 1.0 / 6;
      Float u = fmod(Abs(cd->p.x), 1);
      Float v = fmod(Abs(cd->p.y), 1);
      // This function calculates the stepped value of *x* based on
      // the specified *step*.
      auto steppit = [](const Float x, const Float step) -> Float {
        if (Abs(step - 1.0) <= EPSILON) return 0.0;
        Float r = (x - fmod(x, step)) / (1.0 - step);
        // Rounding errors could lead r to exceed 1.0 *sligthly*,
        // but we really need to make sure it does not, otherwise we
        // will start sampling the other end of the shader again.
        if (r > 1.0) r = 1.0;
        else if (r < 0.0) r = 0.0;
        return r;
      u = steppit(i, stepu);
      v = steppit(i, stepv);
      ChannelData data = *cd;
      data.p = Vector(u, v, 0);
      return subShader->Sample(&data);

    Of course, InitRender() and FreeRender() are called on the subShader.


  • On 30/04/2015 at 08:31, xxxxxxxx wrote:

    I am currently facing a much more important problem. 😢
    I only know at the time ShaderData::Output() is called what sub-shader I need to sample. So once
    I figured it out, I will call InitRender() on it. But unfortunately that leads me to a deadlock.

    What happens is the following:

    1. I figure out a shader that I need to sample from my shader , I create an AutoLocker 
    2. I create a clone of the shader that I want to sample and insert it as a shader into my shader
    3. I use the copy of the InitRenderStruct from InitRender() and initialize its member  vd  with the
    VolumeData from the ChannelData.
    4. I call subShader- >InitRender() with the new InitRenderStruct, but this call never exits
    5. I unlock the AutoLocker

    I found this case happening when subShader  is a Layer shader. I thought it would be dangerous
    to initialize a shader from Output(), but is it impossible?

    Thanks a lot in advance,

  • On 04/05/2015 at 07:17, xxxxxxxx wrote:

    I've moved the initialization to my InitRender() method and now it all works fine (except for the Noise
    Shader which still ignores the U/V data I pass). It's been much more effort to actually figure out the
    shader's that will be needed rather than initializing them on-demand as I could deduce it from the
    ChannelData that was passed to Output().

  • On 04/05/2015 at 07:38, xxxxxxxx wrote:

    @Niklas, you can get the correct Noise for whatever UV coordinate you want with a hack, noise shader got a Bitmap view that you can get with a size "1k for example" , and then hit the pixel that you want from the UV coordinate

  • On 11/05/2015 at 02:04, xxxxxxxx wrote:


    sampling a shader I prefer to use a fully setup ChannelData object like this:

    ChannelData channelData;  
  = 0;  
    channelData.scale = 0;  
    channelData.t = 0;  
    channelData.texflag = TEX_TILE;  
    channelData.p.x = u;  
    channelData.p.y = (1.0-v);  
    channelData.p.z = w;  
    channelData.d = Vector(1,1,1);  
    channelData.n = Vector(0,1,0);  
    channelData.vd = NULL;  
    Vector res = shader->Sample(&channelData);  

    best wishes,

  • On 11/05/2015 at 04:55, xxxxxxxx wrote:

    Thank you Sebastian, I'll give it a try!

Log in to reply