BaseShader Manual

About

A BaseShader is the base class for shaders in Cinema 4D. Shaders are typically used with materials to define various surface properties. But shaders can also be used in other situations for example in combination with generator objects. BaseShader objects are not stored with the BaseDocument directly but must be inserted into the object that uses them.

BaseShader objects are an instance of Xbase.

// This example lets the user select an image file. If a file was selected
// a shader, material and texture tag are created that apply that image file
// to the given object.
Filename imageFile;
// open file selector dialog to select an image file
if (imageFile.FileSelect(FILESELECTTYPE_IMAGES, FILESELECT_LOAD, "Select Image File") == false)
return false;
// allocate elements
Material* material = Material::Alloc();
TextureTag* textureTag = TextureTag::Alloc();
// check for successful allocation
if (!material || !bitmapShader || !textureTag)
{
BaseShader::Free(bitmapShader);
Material::Free(material);
TextureTag::Free(textureTag);
return false;
}
// start undo for the complete task
doc->StartUndo();
// configure the texture tag
const DescID projectionParam = DescID(TEXTURETAG_PROJECTION);
const Int32 projectionUVW = TEXTURETAG_PROJECTION_UVW;
textureTag->SetParameter(projectionParam, projectionUVW, DESCFLAGS_SET_0);
textureTag->SetMaterial(material);
object->InsertTag(textureTag);
doc->AddUndo(UNDOTYPE_NEW, textureTag);
// configure the bitmap shader and the material
material->InsertShader(bitmapShader);
// insert the material
doc->InsertMaterial(material);
doc->AddUndo(UNDOTYPE_NEW, material);
// finalize
doc->EndUndo();

Access

Shaders are owned by the object that uses them. The shaders owned by a given object are organized in a list:

Shaders are typically organized in a list but can also be organized in a tree:

// This example loops through the shader list of the given material.
// Note that this example does not handle child or sub-shaders.
BaseShader* shader = material->GetFirstShader();
while (shader)
{
GePrint("Shader: " + shader->GetName());
shader = shader->GetNext();
}

Allocation/Deallocation

Shaders are created with the usual tools.

Newly created shaders are typically handed over to the object that uses them:

For a list of shader IDs see Shader Types.

// This example creates a noise shader and assigns it to the given material.
if (!noiseShader)
return false;
material->InsertShader(noiseShader);

Read-Only Properties

Note
Also supported shaders may be baked into a texture, depending on the used material channel and shader context.

Sampling a Shader

A shader returns a color value for a given point. This point can be a point in world or object space or a set of UV-coordinates. A shader is sampled this way typically in the rendering pipeline.

A shader has to be initiated:

After the shader has been initiated these functions can be used:

In the end the resources of the shader must be released:

Warning
Without properly initiated InitRenderStruct::vd argument it is not safe to sample a shader multi-threaded.
// This example samples the given shader in UV space.
// init the shader
InitRenderStruct irs(doc);
// check if linear workflow is enabled
if (irs.linear_workflow)
const INITRENDERRESULT res = shader->InitRender(irs);
if (res != INITRENDERRESULT_OK)
return false;
// sample the shader in UV space
ChannelData channelData;
channelData.off = 0;
channelData.scale = 0;
channelData.t = doc->GetTime().Get();
channelData.texflag = CALC_TEXINFO(0, CHANNEL_COLOR);
channelData.d = Vector(1, 1, 1);
channelData.n = Vector(0, 1, 0);
channelData.vd = nullptr; // VolumeData is nullptr
for (Int32 y = 0; y < height; ++y)
{
for (Int32 x = 0; x < width; ++x)
{
// generate UV coordinates
const Float64 xFloat = (Float64)x;
const Float64 yFloat = (Float64)y;
const Float64 u = xFloat / widthFloat;
const Float64 v = yFloat / heightFloat;
channelData.p.x = u;
channelData.p.y = v;
channelData.p.z = 0.0f;
const Vector color = shader->Sample(&channelData);
const Vector transformedColor = TransformColor(color, transform).Clamp01();
// write into the given BaseBitmap
const Int32 r = SAFEINT32(transformedColor.x * COLORTOINT_MULTIPLIER);
const Int32 g = SAFEINT32(transformedColor.y * COLORTOINT_MULTIPLIER);
const Int32 b = SAFEINT32(transformedColor.z * COLORTOINT_MULTIPLIER);
bitmap->SetPixel(x, y, r, g, b);
}
}
// free shader resources
shader->FreeRender();

Compare

Two BaseShader elements can be compared with:

Note
The comparison is mostly based on the shader's BaseContainer. Other internal data may not be compared.

Further Reading