Sampling from ShaderLink into BaseBitmap [SOLVED]

On 25/05/2016 at 07:46, xxxxxxxx wrote:

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


I must be missing something very obvious. I cannot get proper bitmap pixels sampled from a shaderlink. I am running this from GetVritualObjects.

For example, I have a generator plugin that generates a plane. 
I have a shader link in the description that lets the user input a shader, like a bitmap or a noise shader.
I need to sample this shader into a bitmap that I can use later to do some calculations, based on the plane UVs.
This would be done from inside GetVirtualObjects. Or is there a better place to do it?

Here is the code I am using:

	AutoAlloc<BaseBitmap> bmp;
	BaseShader* shaderLink = (BaseShader* )bc->GetLink(MYSHADERLINK,doc);
	if (shaderLink)
		InitRenderStruct irs;
		LONG bitmapWidth = 100; 
		LONG bitmapHeight = 100; 
		IMAGERESULT res = bmp->Init(bitmapWidth, bitmapHeight);
		if (res == IMAGERESULT_OK)
			ChannelData chD;
			chD.p = Vector(0, 0, 0);
			chD.n = Vector(0, 1, 0);
			chD.d = Vector(0, 0, 0);
			chD.t = 0.0;
			chD.texflag = TEX_TILE;
			chD.vd = NULL; = 0.0;
			chD.scale = 0.0;
			for (LONG x=0; x < bitmapWidth; x++) 
				for (LONG y=0; y < bitmapHeight; y++) 
					chD.p.x = (Real) x ;
					chD.p.y = (Real) y ;
					Vector pixel = shaderLink->Sample(&chD);
					LONG r1 = pixel.x * 255;
					LONG g1 = pixel.y * 255;
					LONG b1 = pixel.z * 255;
					bmp->SetPixel(x, y, r1, g1, b1);

Any help would be greatly appreciated.

Edited for a better explanation.

On 25/05/2016 at 08:02, xxxxxxxx wrote:

1. ChannelData.p is READ ONLY.  And it is in UVW coordinate space not image or other space.

2. Sample() must be called within a set of InitRender()/FreeRender() calls.

On 25/05/2016 at 08:16, xxxxxxxx wrote:

Thank you for the reply Robert.

Do you have an example by any chance with the correct InitRender()/FreeRender() calls that I can look at?

On 25/05/2016 at 08:47, xxxxxxxx wrote:

Originally posted by xxxxxxxx

  1. ChannelData.p is READ ONLY.  And it is in UVW coordinate space not image or other space.

It is READ ONLY from the context of a shader. However to feed the shader, you can manipulate ChannelData.p to your liking (outside of ShaderData::Output())

On 26/05/2016 at 01:50, xxxxxxxx wrote:

Hi Salozo,

There are several mistakes in your code.

First, you're missing the call to shaderLink- >FreeRender() after you've finished with the sampling.
(Note you can check the return value of InitRender() if INITRENDERRESULT_OK.)

Second, and this seems the most important issue, U and V coordinates have to be in the [0-1] range.
This is why you're not getting the shader pixels as expected.
The following lines have to be changed:

Originally posted by xxxxxxxx

chD.p.x = (Real) x ;
chD.p.y = (Real) y ;

Divide x and y by the width and height of the bitmap.

On 26/05/2016 at 05:24, xxxxxxxx wrote:

Also note that Cinema calls FreeRender() even when the InitRender()
returned an error. Some shaders might depend on this behavioura and
you should replicate it to avoid memory leaks or even more
crucial errorrs.

On 26/05/2016 at 12:32, xxxxxxxx wrote:

Thank you Yannik, Nicklas and Robert. Yannick's remark did the trick.