Custom MaterialData UV & Parameter Bugs [SOLVED]

On 31/10/2014 at 10:09, xxxxxxxx wrote:

Hey Sebastian,

I'm looking forward to your sample 🙂

For example, in MyMaterial::InitRender you ignore the given document and work on the active document.

I commented the line in code, but I guess not that clear^^ I changed irs.doc to GetActiveDocument() because the GenerateTexturePath failed when the RenderDocument() call was made for the preview. The path targeted a strange subfolder of module in some C4D directory, so I was not able to find my textures. The GenerateTexturePath part of my code is also commented and weird, as the documentation about this call is plain wrong!

On 03/11/2014 at 01:56, xxxxxxxx wrote:


can you give an example of how you have problems with GenerateTexturePath()?

Also, I must discourage you from using GetActiveDocument() in any render context because the active document may not be related to the render process at all.

Best wishes,

On 03/11/2014 at 03:03, xxxxxxxx wrote:

I guess you know that the docu about GenerateTexturePath is wrong? There is already a thread about it here in the forum. Search for "TEXTURE (description element)") in the online R15 docu. 
This code is from MyMaterial::loadDiffuseTexture, that can be found in the attached project.

// Instead of this:
GenerateTexturePath(pDoc->GetDocumentPath() + pDoc->GetDocumentName(), Filename(diffuseTextureString), Filename(), &texturePath)
// This has to be used:
GenerateTexturePath(pDoc->GetDocumentPath(), diffuseTextureString, Filename(), &texturePath)

Since I have fixed this code, I don't have any problems, except that the docu should be corrected.

The real problem I'm having is, that the GenerateTexturePath returns a completely strange path when it is called for the material preview. You can simply debug this:
1. In MyMaterial::InitRender() change the GetActiveDocument() back to irs.doc (which is the "correct, active, current, used" document for the rendering)
2. Add this line just before GenerateTexturePath is called in loadDiffuseTexture:
Filename documentPath = pDoc->GetDocumentPath();
3. Set a breakpoint in loadDiffuseTexture at the newly created line
4. Hit F5 in visual studio and C4D will start, because I have configured the debugger like so.
5. Navigate to the MyMaterialBug.c4d scene that I have attached and open it (all from C4D, so that the debugger is used!)
6. The breakpoint triggers, hit F10 (step over) and you see that the documentPath is indeed the correct one (E.g. C:\Users\FrozenTarzan\Desktop\MyMaterialBug). So just hit F5 (continue) or step over the rest to verify that everything works fine. This call was made to generate the OpenGL image (at least I guess so)
7. Double click the MyMaterial.
8. The breakpoint triggers again, hit F10 (step over) and see that the documentPath is something like this:
This path cannot be used to find the textures with GenerateTexturePath because there are none! So my only solution was to change the line irs.doc to GetActiveDocument because then I can retrieve the correct paths for my textures.

Please use the instructions above to verify the problem.

On 05/11/2014 at 06:10, xxxxxxxx wrote:


when you double click on your material Cinema will create an new preview image. This preview image is created by rendering a simple scene. This scene is stored in the folder you mention above (resource\modules\xtensions\preview_scenes). To find out if the current render process is a preview rendering simply check the flag INITRENDERFLAG_PREVIEWRENDER.

The path to the original scene is stored in the given document's BaseContainer with the ID DOCUMENT_SECONDARYPATH.

      if(irs.doc && irs.doc->GetDataInstance())  
          const Filename originalPath = irs.doc->GetDataInstance()->GetFilename(DOCUMENT_SECONDARYPATH);  

Best wishes,

On 06/11/2014 at 01:18, xxxxxxxx wrote:

Hey Sebastian,

sorry for the late reply!

Your code snippet works great. My textures are found now 🙂

Open issues:
* Perfect sphere options and workaround for correct UV-mapping when OpenGL is enabled and when scene is rendered. As we discussed earlier there are hacks to accomplish it by turning the "perfect sphere" off, but I would like to see an official statement.

* Parameter-Update bug when OpenGL is enabled


On 07/11/2014 at 07:06, xxxxxxxx wrote:


to support perfect spheres and also different projection types set in the Texture Tag you have to set the VOLUMEINFO_EVALUATEPROJECTION flag in GetRenderInfo().

When you use InitGLImage() you have to set the filled bitmap dirty using SetDirty(). This will trigger the update.

We are currently working on a new MaterialData example for the SDK and want to publish is soon.

Best wishes,

On 07/11/2014 at 07:45, xxxxxxxx wrote:

Can I make a suggestion about your example? Or is it too late?

The current Materials examples don't show us how to make a material with only a couple of channels.
They either have no channels. Or all of standard the channels.
And it took me a while to figure out how to make a material with only a Color and Alpha channel because of that.

I also discovered that the checkboxes to enable/disable the channels are just ordinary generic gizmos declared in the .res file. Which I was surprised to discover.
Things like this are not currently explained very clearly, or at all, in the current MaterialData examples.


On 07/11/2014 at 11:26, xxxxxxxx wrote:

I would encourage too a very single addition "if possible" to the example, as I'm creating my renderer, I got 1 little thing to know about "material preview" , how they are rendered

On 08/11/2014 at 02:10, xxxxxxxx wrote:

Hey Sebastian,

to support perfect spheres and also different projection types set in the Texture Tag you have to set the VOLUMEINFO_EVALUATEPROJECTION flag in GetRenderInfo().

You are right, that this solves the uv-mapping of the parametric spheres without turning the "render perfect" off. But it breaks my material preview. When I use the VOLUMEINFO_EVALUATEPROJECTION flag my material preview still shows my diffuse color, but as soon as I load a texture, the preview becomes completely black, when I remove my texture, it shows the diffuse color again and seems to work. 
EDIT: I debugged it and this call in CalcSurface() :

m_pDiffuseTexture->GetPixel(x, y, &r, &g, &b);

always returns 0, 0, 0 for r, g, b when the render call is made for the preview.

When you use InitGLImage() you have to set the filled bitmap dirty using SetDirty(). This will trigger the update.

NICE! It works! For everyone else:
In: Bool MyMaterial::InitGLImage(BaseMaterial* mat, BaseDocument* doc, BaseThread* th, BaseBitmap* bmp, Int32 doccolorspace, Bool linearworkflow)

when you have set your pixels (in my case fetch a texture and multiply a color value) simply call:
in addition to the call, already in my sample:

I will close the other related thread and set it to solved. In this one we still have some issues with the preview and the projection evalutation.

My sample project available at the top shows how to create the preview. I copied it from one of the examples. As you might have noticed, there are still bugs in it. 😉


On 08/11/2014 at 11:16, xxxxxxxx wrote:

In my R13 version. I didn't use GetRenderInfo().
If I add that to my code. And set the VOLUMEINFO_EVALUATEPROJECTION flag. It does fix the render perfect problem. And displays the image correctly in the editor window even when rendering.

However. It also breaks the material preview image.
It turns it into a bright glowing white color.

Looking forward to seeing the final example.


On 10/11/2014 at 02:30, xxxxxxxx wrote:


The BaseChannel system is just a utility tool to organize a material. It is only used by the standard material so GetChannel() will only work with the standard material.

If you use the metaphor of "channels" in your material is up to you. In the resource file of a material plugin you can define different groups that allow you to organize your parameters. Take a look at the "Cheen" material to see how each group controls a completely different aspect.

Using and customizing the material preview is a large topic. For the most simple case just add "INCLUDE Mpreview;" to your res file and the preview itself will handle the rest. If you have any specific questions please open a new thread so the topics don't get mixed up.

Best wishes,

On 10/11/2014 at 03:01, xxxxxxxx wrote:

Hi Sebastian,

Using and customizing the material preview is a large topic.

That should not be a large topic in the API... it's just a small image of a single render pass^^

Have you tried to use the VOLUMEINFO_EVALUATEPROJECTION flag in my sample project? Have you tested it with spheres? Can you verify that the preview is broken because the GetPixel() returns 0, 0, 0 for the fetched color (like I described above)?

I'm really interested how those interactions can happen in the API. The evaluation of a projection of UV-coordinates has nothing to do with a bitmap. Why in the world is there a difference WHEN and WHERE I fetch texels from a bitmap. This makes absolutely no sense and should be tackled!


On 11/11/2014 at 00:55, xxxxxxxx wrote:


if the given x/y coordinates are outside the dimensions of the given BaseBitmap, GetPixel() won't do anything and will not change the given r,g,b values. You should check if the x/y coordinates based on the UV-settings are valid.

I uploaded the simple material example. It may be included in the SDK.

MaterialData example (ZIP)

Best wishes,

On 11/11/2014 at 09:10, xxxxxxxx wrote:

Thanks for the sample! You are right that the uv coordinates of my objects where greater than 1.0. I really don't know why... this again makes no sense at all because the uvs should be the same independent of the "evaluate projection flag". The mapping looks exactly the same in the preview... but whatever, using this code in CalcSurface() works now:

float integral = 0.0f;
float u = modf(vd->uvw.x, &integral);
float v = modf(vd->uvw.y, &integral);		
Int32 x = static_cast<Int32>(m_pDiffuseTexture->GetBw() * u); 
Int32 y = static_cast<Int32>(m_pDiffuseTexture->GetBh() * v); 
UInt16 r = 0;
UInt16 g = 0;
UInt16 b = 0;
m_pDiffuseTexture->GetPixel(x, y, &r, &g, &b);

There is only one singe bug in here:
1. Enable OpenGL
2. Create a Null-Object
3. Create a parametric sphere (do not make it editable!)
4. Make the sphere a child of the null object
5. Create MyMaterial (download still up there in the post) and select a texture for the diffuse/color channel
6. Assign it to the Null-Object (the parent of the sphere!)
7. Select the sphere (child!) and move it

The result is, that the uv-mapping changes depending on the position of the sphere relative to the parent (null-object). It seems that the mapping is only correct, when the sphere is exactly at the origin/center of the parent.

See here:
_<_img src="" height="239" width="997" border="0" /_>_

On 11/11/2014 at 10:45, xxxxxxxx wrote:

this is a normal behavior!! 🙂 , I tested it with standard material and it does the same!!!!

edit: this is a CONFIRMED bug, when I render, it renders correctly "OpenGL got a problem here" , it renders correct because it uses UVs , not spherical projection "like OpenGL"

On 16/11/2014 at 10:44, xxxxxxxx wrote:

There seems to be a problem in your example.
When you choose to use a shader. And you load an image into the shader. The preview icon is white.
This only happens with the sphere preview option.

I just ran into this same problem when writing my own R13 material plugin.
And I discovered that if I Shift+LMB on the sphere in preview window and rotate it 180 degrees in X. The image shows up properly.
So I guess we need a way to either show both sides of the sphere. Or some way to see the other side of the sphere in the material's preview window?


On 21/11/2014 at 11:38, xxxxxxxx wrote:

Any progress in fixing the sphere preview yet?


On 24/11/2014 at 10:57, xxxxxxxx wrote:


I have not found a solution for this particular issue yet.

best wishes,

On 24/11/2014 at 11:43, xxxxxxxx wrote:

OK. Thanks for the update.
At least I know now that it's not something I'm doing wrong.


On 28/11/2014 at 02:18, xxxxxxxx wrote:


in the standards preview scene the Texture Tag tiles the U coordinate. This way coordinates bigger than 1 are created. So a material must handle such coordinates. To make sure a shader will handle this properly the texture flags in the ChannelData object have to be set. This can be done using CALC_TEXINFO:

             ChannelData channelData(vd);  
             channelData.texflag = CALC_TEXINFO(((TexData* )vd->tex)->texflag, CHANNEL_ANY);  
             resultColor = _renderParamShader->Sample(&channelData);  

For further questions on materials please open a new thread. Thanks.

Best wishes,