BaseShader Manual


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"_s))
return maxon::OK;
// allocate elements
Material* material = Material::Alloc();
TextureTag* textureTag = TextureTag::Alloc();
// check for successful allocation
if (!material || !bitmapShader || !textureTag)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
// start undo for the complete task
// configure the texture tag
const DescID projectionParam = DescID(TEXTURETAG_PROJECTION);
const Int32 projectionUVW = TEXTURETAG_PROJECTION_UVW;
textureTag->SetParameter(projectionParam, projectionUVW, DESCFLAGS_SET::NONE);
doc->AddUndo(UNDOTYPE::NEWOBJ, textureTag);
// configure the bitmap shader and the material
// insert the material
doc->AddUndo(UNDOTYPE::NEWOBJ, material);
// finalize


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)
ApplicationOutput("Shader: " + shader->GetName());
shader = shader->GetNext();


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.
BaseShader* const noiseShader = BaseShader::Alloc(Xnoise);
if (noiseShader == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);

Read-Only Properties

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:

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);
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
// sample the shader in UV space
ChannelData channelData; = 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


Two BaseShader elements can be compared with:

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

Further Reading