Open Search
    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"_s))
    return maxon::OK;
    // allocate elements
    Material* material = Material::Alloc();
    TextureTag* textureTag = TextureTag::Alloc();
    // check for successful allocation
    const Bool materialFailure = material == nullptr;
    const Bool shaderFailure = bitmapShader == nullptr;
    const Bool tagFailure = textureTag == nullptr;
    if (materialFailure || shaderFailure || tagFailure)
    {
    BaseShader::Free(bitmapShader);
    Material::Free(material);
    TextureTag::Free(textureTag);
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    }
    // start undo for the complete task
    doc->StartUndo();
    // configure the texture tag
    const DescID projectionParam { TEXTURETAG_PROJECTION };
    const Int32 projectionUVW = TEXTURETAG_PROJECTION_UVW;
    textureTag->SetParameter(projectionParam, projectionUVW, DESCFLAGS_SET::NONE);
    textureTag->SetMaterial(material);
    object->InsertTag(textureTag);
    doc->AddUndo(UNDOTYPE::NEWOBJ, textureTag);
    // configure the bitmap shader and the material
    material->InsertShader(bitmapShader);
    // insert the material
    doc->InsertMaterial(material);
    doc->AddUndo(UNDOTYPE::NEWOBJ, material);
    // finalize
    doc->EndUndo();
    void InsertShader(BaseShader *shader, BaseShader *pred=nullptr)
    Definition: c4d_baselist.h:2591
    Definition: c4d_basechannel.h:36
    static BaseShader * Alloc(Int32 type)
    static void Free(BaseShader *&ps)
    Bool SetParameter(const DescID &id, const GeData &t_data, DESCFLAGS_SET flags)
    Definition: lib_description.h:330
    Manages file and path names.
    Definition: c4d_file.h:94
    Bool FileSelect(FILESELECTTYPE type, FILESELECT flags, const maxon::String &title, const maxon::String &force_suffix=maxon::String())
    Definition: c4d_basematerial.h:241
    static void Free(Material *&bl)
    static Material * Alloc()
    Definition: c4d_basetag.h:654
    void SetMaterial(BaseMaterial *mat)
    static TextureTag * Alloc()
    static void Free(TextureTag *&bl)
    maxon::Bool Bool
    Definition: ge_sys_math.h:55
    maxon::Int32 Int32
    Definition: ge_sys_math.h:60
    return OK
    Definition: apibase.h:2690
    @ LOAD
    Load dialog.
    @ IMAGES
    Image files.
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:67
    #define Xbitmap
    Bitmap.
    Definition: ge_prepass.h:1304
    @ NEWOBJ
    A new object, material, tag, or other classic API node instance has been inserted into the document....
    @ MATERIAL_COLOR_SHADER
    Definition: mmaterial.h:294
    const char * doc
    Definition: pyerrors.h:226
    @ TEXTURETAG_PROJECTION
    Definition: ttexture.h:10
    @ TEXTURETAG_PROJECTION_UVW
    Definition: ttexture.h:17
    @ BITMAPSHADER_FILENAME
    Definition: xbitmap.h:6

    Access and Structure

    Shaders are stored in a special shader branching relation of the nodes who own them. The first shader in the shader branch of a node can be retrieved with BaseList2D::GetFirstShader and inserted with BaseList2D::InsertShader . This primarily applies to BaseList2D shader owners such as BaseObject or BaseMaterial .

    BaseShader instances which own shaders themselves tend to not insert shaders into their shader branch but as direct children although they are also BaseList2D instances. An example for this behaviour would be the type LayerShader which carries its owned shaders as direct children. When constructing such nested shader setups, one must call therefore GeListNode::InsertUnder on the root shader to insert child shaders, and not BaseList2D::InsertShader (Fig I).

    +-- GeListHead "object" // The object branch of the document.
    | +-- BaseObject "Shader Effector" // A Mograph shader effector object in the document.
    | | +-- GeListHead "shader" // The shader branch in of the effector.
    | | +-- BaseShader "Noise" // A noise shader owned and used by the effector, it has no children.
    | +-- BaseObject "cube" // A cube object, it owns no shaders.
    +-- GeListHead "material" // The material branch of the document.
    +-- BaseMaterial "Material.1" // The first material of the document, it owns a set of nested shaders.
    | +-- GeListHead "shader" // The shader branch in of the material.
    | +-- BaseShader "Layer.1" // A layer shader owned by the material with two children.
    | +-- BaseShader "Noise" // A noise shader owned by by the "Layer.1" shader.
    | +-- BaseShader "Noise" // Another noise shader owned by by the "Layer.1" shader.
    | +-- BaseShader "Layer.2" // Another layer shader owned by the material with one child.
    | +-- BaseShader "Color" // A color shader owned by the "Layer.2" shader.
    +-- BaseMaterial "Material.2" // The second material of the document, it owns no shaders.
    Definition: c4d_basedocument.h:498
    Definition: c4d_basematerial.h:28
    Definition: c4d_baseobject.h:225
    Definition: c4d_baselist.h:2044
    Fig. I: How shaders are stored within a scene graph often changes with the BaseShader type itself.
    Note
    This behaviour is a rule of thumb, but there is no guarantee that all shader types who own shader dependencies handle their owned shaders in this manner. For native Cinema 4D shaders as the Layer or Fusion Shader this holds true, but one must always check how a specific shader handles its owned shaders when dealing with a specific type.

    Traversing shaders therefore depends on the context:

    With either the list of shaders owned by a material or object, or within a hierarchy level of a set of nested shaders, one can navigate with the common GeListNode functions:

    // 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 != nullptr)
    {
    ApplicationOutput("Shader: " + shader->GetName());
    shader = shader->GetNext();
    }
    String GetName() const
    Definition: c4d_baselist.h:2381
    BaseShader * GetFirstShader() const
    Definition: c4d_baselist.h:2563
    BaseShader * GetNext()
    Definition: c4d_basechannel.h:68
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:210

    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.
    BaseShader* const noiseShader = BaseShader::Alloc(Xnoise);
    if (noiseShader == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    material->InsertShader(noiseShader);
    #define Xnoise
    Noise.
    Definition: ge_prepass.h:1340
    @ MATERIAL_BUMP_SHADER
    Definition: mmaterial.h:300

    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.

    A shader can sipmply be baked into a BaseBitmap using:

    // This example bakes the given BaseShader into the given BaseBitmap
    // and displays the result in the Picture Viewer window.
    const InitRenderStruct irs { doc };
    const maxon::Int32 colorProfile = irs.document_colorprofile;
    const maxon::Bool linearWorkflow = irs.linear_workflow;
    const maxon::Bool alpha = false;
    const maxon::Bool hdr = true;
    const maxon::Int xmin = 0;
    const maxon::Int ymin = 0;
    const maxon::Int xmax = sizeX - 1;
    const maxon::Int ymax = sizeY - 1;
    // bake shader
    const Bool bakeResult = shader->BakeShaderIntoBaseBitmap(bitmap, *doc, parentThread, alpha, colorProfile, linearWorkflow, hdr, xmin, xmax, ymin, ymax);
    if (bakeResult == false)
    return maxon::UnknownError(MAXON_SOURCE_LOCATION);
    // show result
    ShowBitmap(bitmap);
    Bool ShowBitmap(const Filename &fn)
    Bool BakeShaderIntoBaseBitmap(BaseBitmap &outBmp, BaseDocument &doc, BaseThread *parentThread, Bool doAlpha, Int32 colorSpace, Bool linearworkflow, Bool useHDR, Int xmin, Int xmax, Int ymin, Int ymax)
    Definition: c4d_basechannel.h:205
    Definition: c4d_shader.h:298
    Int64 Int
    signed 32/64 bit int, size depends on the platform
    Definition: apibase.h:188
    bool Bool
    boolean type, possible values are only false/true, 8 bit
    Definition: apibase.h:181
    int32_t Int32
    32 bit signed integer datatype.
    Definition: apibase.h:176
    // This example samples the given shader in UV space.
    // init the shader
    // 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;
    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();
    PyObject PyObject * v
    Definition: abstract.h:297
    Int32 CALC_TEXINFO(Int32 texflag, Int32 channel)
    Definition: c4d_shader.h:53
    Vector64 TransformColor(const Vector64 &input, COLORSPACETRANSFORMATION colortransformation)
    static const Float COLORTOINT_MULTIPLIER
    Constant to convert from vectors color components to integers.
    Definition: c4d_tools.h:25
    INITRENDERRESULT InitRender(const InitRenderStruct &is)
    Definition: c4d_basechannel.h:105
    Vector Sample(ChannelData *cd)
    Definition: c4d_basechannel.h:123
    void FreeRender()
    Frees all resources used by this shader that were allocated by calling InitRender().
    Definition: c4d_basechannel.h:110
    PyObject * x
    Definition: bytesobject.h:38
    Py_UCS4 * res
    Definition: unicodeobject.h:1113
    maxon::Float64 Float64
    Definition: ge_sys_math.h:67
    #define CHANNEL_COLOR
    The color channel of a material.
    Definition: c4d_shader.h:95
    COLORSPACETRANSFORMATION
    Definition: ge_prepass.h:498
    @ LINEAR_TO_SRGB
    Linear to sRGB color space transformation.
    INITRENDERRESULT
    Definition: ge_prepass.h:408
    @ OK
    Everything is OK, there was no error.
    Int32 SAFEINT32(Float32 x)
    Definition: apibasemath.h:275
    const char const char grammar * g
    Definition: parsetok.h:52
    unsigned long Py_ssize_t width
    Definition: pycore_traceback.h:88
    Definition: c4d_shader.h:1099
    Vector n
    [READ ONLY] The surface normal.
    Definition: c4d_shader.h:1112
    Float scale
    [READ ONLY] The MIP blur offset.
    Definition: c4d_shader.h:1117
    Float t
    [READ ONLY] The current time in seconds.
    Definition: c4d_shader.h:1114
    Vector d
    [READ ONLY] The MIP sample radius in UVW coordinates.
    Definition: c4d_shader.h:1113
    Int32 texflag
    [READ ONLY] The texture flags: TEX
    Definition: c4d_shader.h:1115
    VolumeData * vd
    [READ ONLY] The volume information, can be nullptr.
    Definition: c4d_shader.h:1116
    Float off
    Definition: c4d_shader.h:1117
    Vector p
    [READ ONLY] The texture position in UVW coordinates.
    Definition: c4d_shader.h:1111
    T y
    Definition: vec.h:40
    constexpr Unstrided Clamp01() const
    Returns a vector that is clamped to the range [0.0 .. 1.0].
    Definition: vec.h:454
    T x
    Definition: vec.h:39
    T z
    Definition: vec.h:41

    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