On 31/08/2014 at 11:04, xxxxxxxx wrote:
Hello,
the Cinema 4D viewport uses OpenGL; the CalcSurface-function is written in C++ so there is no way of calling that function while drawing the viewport. What we can do is to use a bitmap texture to define how the material looks like in the viewport. Then the OpenGL viewport can use that texture on the assigned objects.
When you want to create such texture you have to set the PLUGINFLAG_MATERIAL_GLIMAGE flag while registering your MaterialData-plugin. Then you can use the InitGLImage function to define the preview texture.
virtual Bool InitGLImage(BaseMaterial* mat, BaseDocument* doc, BaseThread* th, BaseBitmap* bmp, Int32 doccolorspace, Bool linearworkflow)
{
GeData data;
mat->GetParameter(DescLevel(MYMATERIAL_DIFFUSE_TEXTURE), data, DESCFLAGS_GET_0);
String name = data.GetString();
// if defined use bitmap
if (name.Content() == true)
{
// get full path
Filename texture;
GenerateTexturePath(doc->GetDocumentPath() + doc->GetDocumentName(), Filename(name), Filename(), &texture);
// load texture into BaseBitmap
BaseBitmap * loadedBitmap = BaseBitmap::Alloc();
IMAGERESULT res = loadedBitmap->Init(texture);
if (res == IMAGERESULT_OK)
{
BaseBitmap * tempBitmap = BaseBitmap::Alloc();
tempBitmap->Init(bmp->GetBw(), bmp->GetBh(), bmp->GetBt());
// scale and copy loaded bitmap into temp bitmap
loadedBitmap->ScaleIt(tempBitmap, 256, true, true);
const Int32 width = bmp->GetBw();
const Int32 height = bmp->GetBh();
UInt16 r, g, b = 0;
for (Int32 y = 0; y < height; y++)
{
for (Int32 x = 0; x < width; x++)
{
tempBitmap->GetPixel(x, y, &r, &g, &b);
bmp->SetPixel(x, y, r, g, b);
}
}
BaseBitmap::Free(tempBitmap);
}
BaseBitmap::Free(loadedBitmap);
}
else
{
// use diffuse color
mat->GetParameter(MYMATERIAL_DIFFUSE_COLOR, data, DESCFLAGS_GET::DESCFLAGS_GET_0);
const Vector diffuseColor = data.GetVector();
const Int32 r = (Int32)(diffuseColor.x * 255.0);
const Int32 g = (Int32)(diffuseColor.y * 255.0);
const Int32 b = (Int32)(diffuseColor.z * 255.0);
const Int32 width = bmp->GetBw();
const Int32 height = bmp->GetBh();
for (Int32 y = 0; y < height; y++)
{
for (Int32 x = 0; x < width; x++)
{
bmp->SetPixel(x, y, r, g, b);
}
}
}
return true;
};
In some cases Cinema 4D does use special OpenGL-shaders to re-create the look of (C++) shaders in the viewport. This is what happens when you turn on "Noises" when "Advanced OpenGL" is activated. This only works for some standard shaders like noise. When you put a noise shader into a layer shader then Cinema will again bake the texture.
I'm not quite sure what Cinema does when you don't use OpenGL but the software viewport. Maybe it will create some preview texture itself when no texture is provided by the material.
So when to use MaterialData and ShaderData? Well, a MaterialData plugin is something that appears in the Material Manager. This can be some complex material like Cheen or just some scene entry that can be assigned to objects and are not really "shaders" or "materials" (like the architectural grass, hair material, sketch material).
A ShaderData is a (fragment)-shader that can be used within a material (or anywhere else where you find a SHADERLINK). It's Output function returns the color for the given fragment (defined by the ChannelData argument). So as an example if you want to do something that modifies the transparency of a object you can create a MaterialData plugin and use it's CalcTransparency function. Or you write a ShaderData that can be used by a material (that deals with transparency). ShaderData plugins can be used in different channels of the standard material (or at completely different places), MaterialData plugins can just be used as materials.
When you add a "Image" to the "Texture" parameter in the standard material's "Color" channel you really define a BaseShader of the type Xbitmap. That shader is called by the standard material when it is calculating the color. The actual bitmap sampling happens within that shader.
best wishes,
Sebastian