Open Search
    Substance Functions Manual

    About

    The Substance functions allow to import and handle Allegorithmic Substance assets into a BaseDocument. In a document they can be used with shaders and materials. The Substance functions are defined in the lib_substance.h header file.

    Access Assets

    Substance assets store a reference to a Substance archive file (.sbsar) and the current value set of its parameters. These assets are stored in the BaseDocument.

    // This example accesses the first Substance to loop through all Substances.
    while (substance != nullptr)
    {
    ApplicationOutput("Substance: " + substance->GetName());
    substance = substance->GetNext();
    }
    // This example accesses all selected Substances
    if (substances == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    GetSubstances(doc, substances, true);
    const Int32 substanceCount = substances->GetCount();
    for (Int32 i = 0; i < substanceCount; ++i)
    {
    C4DAtom* const atom = substances->GetIndex(i);
    const BaseList2D* const asset = static_cast<BaseList2D*>(atom);
    if (asset == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    ApplicationOutput("Selected Substance: " + asset->GetName());
    }
    Py_ssize_t i
    Definition: abstract.h:645
    Definition: ge_autoptr.h:37
    Definition: c4d_baselist.h:2208
    String GetName() const
    Definition: c4d_baselist.h:2381
    BaseList2D * GetNext()
    Definition: c4d_baselist.h:2246
    Definition: c4d_baselist.h:1395
    maxon::Int32 Int32
    Definition: ge_sys_math.h:60
    #define atom
    Definition: graminit.h:72
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:67
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:210
    void GetSubstances(BaseDocument *const doc, AtomArray *arr, Bool onlySelected)
    BaseList2D * GetFirstSubstance(BaseDocument *const doc)
    const char * doc
    Definition: pyerrors.h:226

    Add Assets

    A Substance asset can be imported using the Filename of a Substance archive file (.sbsar).

    // This example imports a Substance asset with the given filename.
    // Then a copy of that asset is created.
    BaseList2D* substance = nullptr;
    // import Substance
    const SUBSTANCE_IMPORT_RESULT res = ImportSubstance(doc, filename, copy, false, false, true, &substance);
    // check if the Substance was imported successfully
    const Bool importFailure = res != SUBSTANCE_IMPORT_RESULT::SUCCESS;
    const Bool invalidSubstance = substance == nullptr;
    if (importFailure || invalidSubstance)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // copy Substance
    BaseList2D* const copySubstance = static_cast<BaseList2D*>(substance->GetClone(COPYFLAGS::NONE, nullptr));
    if (copySubstance == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    const String originalName = substance->GetName();
    const String copyName = originalName + " Copy";
    copySubstance->SetName(copyName);
    // insert copy
    if (!InsertLastSubstance(doc, copySubstance))
    return maxon::UnknownError(MAXON_SOURCE_LOCATION);
    PyCompilerFlags const char * filename
    Definition: ast.h:15
    void SetName(const maxon::String &name)
    Definition: c4d_baselist.h:2387
    C4DAtom * GetClone(COPYFLAGS flags, AliasTrans *trn)
    Definition: c4d_baselist.h:1480
    Definition: c4d_string.h:39
    Py_UCS4 * res
    Definition: unicodeobject.h:1113
    maxon::Bool Bool
    Definition: ge_sys_math.h:55
    @ NONE
    None.
    SUBSTANCE_IMPORT_COPY
    Definition: lib_substance.h:280
    @ NO
    Do not copy file to project directory (absolute file path).
    SUBSTANCE_IMPORT_RESULT
    Definition: lib_substance.h:266
    SUBSTANCE_IMPORT_RESULT ImportSubstance(BaseDocument *const doc, const Filename &fn, SUBSTANCE_IMPORT_COPY &copyFile, Bool errPopup, Bool addUndo, Bool createMaterial, BaseList2D **assetPtr)
    Bool InsertLastSubstance(BaseDocument *const doc, BaseList2D *asset)

    Get Assets

    A Substance asset can contain one or multiple graphs, input parameters and output bitmaps.

    // This example loops through the graphs of the given Substance asset.
    // The graph is then used to loop through the input parameters and output images.
    void* graph = nullptr;
    // loop through graphs
    do
    {
    graph = GetSubstanceGraph(substance, graph, name);
    if (graph != nullptr)
    {
    ApplicationOutput("Graph Name: " + name);
    // loop through inputs
    void* input = nullptr;
    do
    {
    String inputName;
    UInt32 inputID;
    Int32 numberElements;
    Int32 descID;
    input = GetSubstanceInput(substance, graph, input, inputID, descID, numberElements, type, inputName);
    if (input != nullptr)
    ApplicationOutput("Input: " + inputName);
    } while (input != nullptr);
    // loop through outputs
    void* output = nullptr;
    do
    {
    UInt32 outputID;
    String outputName;
    output = GetSubstanceOutput(substance, graph, output, outputID, type, outputName, nullptr);
    if (output != nullptr)
    ApplicationOutput("Output: " + outputName);
    } while (output != nullptr);
    }
    } while (graph != nullptr);
    const char const char * name
    Definition: abstract.h:195
    Py_ssize_t char * output
    Definition: unicodeobject.h:985
    maxon::UInt32 UInt32
    Definition: ge_sys_math.h:61
    SUBSTANCE_INPUT_TYPE
    Definition: lib_substance.h:292
    SUBSTANCE_OUTPUT_TYPE
    Definition: lib_substance.h:315
    void * GetSubstanceInput(BaseList2D *const asset, void *const graph, void *const prevInput, UInt32 &inputUid, Int32 &firstId, Int32 &numElements, SUBSTANCE_INPUT_TYPE &type, String &name)
    void * GetSubstanceOutput(BaseList2D *const asset, void *const graph, void *const prevOutput, UInt32 &outputUid, SUBSTANCE_OUTPUT_TYPE &type, String &name, BaseBitmap **bmpPtr)
    void * GetSubstanceGraph(BaseList2D *const asset, void *const prevGraph, String &name)
    PyObject ** type
    Definition: pycore_pyerrors.h:34

    Materials and Shaders

    Substance assets are used in shaders and are typically applied (but not limited) to materials:

    // This example creates a material from a given Substance asset.
    BaseMaterial* const material = CreateMaterial(substance, 0, mode);
    if (material == nullptr)
    return maxon::UnknownError(MAXON_SOURCE_LOCATION);
    const String substanceName = substance->GetName();
    const String materialName = substanceName + " Material";
    material->SetName(materialName);
    doc->InsertMaterial(material);
    Definition: c4d_basematerial.h:28
    const wchar_t * mode
    Definition: fileutils.h:96
    SUBSTANCE_MATERIAL_MODE
    Definition: lib_substance.h:252
    SUBSTANCE_MATERIAL_MODE PrefsGetMaterialModeSetting()
    BaseMaterial * CreateMaterial(BaseList2D *const asset, Int32 graphIndex, SUBSTANCE_MATERIAL_MODE mode)

    An example how to configure a Substance shader can be found on Substance Elements Manual.

    Substance Preferences

    These utility functions allow fast access to the most important Substance preferences.

    Utility

    Further utility functions are:

    // This example checks if the given scene uses Substance assets in the materials.
    // get first material
    BaseMaterial* material = doc->GetFirstMaterial();
    // check all materials
    bool useSubstances = false;
    while (material != nullptr)
    {
    // check if the given material uses Substances
    if (MaterialUsesSubstance(material))
    {
    useSubstances = true;
    break;
    }
    material = material->GetNext();
    }
    if (useSubstances)
    ApplicationOutput("This scene uses Substances.");
    BaseMaterial * GetNext()
    Definition: c4d_basematerial.h:60
    Bool MaterialUsesSubstance(BaseMaterial *const mat)

    Further Reading