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. :cry:
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!