Redshift Renderer

Demonstrates basic operations with the Redshift renderer in Cinema 4D.

About

With S26 the Redshift render engine has been integrated with Cinema 4D. While the render engine has already previously been available to Cinema 4D users, it was then a plugin and therefor not part of the public Cinema 4D SDK. With the integration come also architectural changes as for example the unification of camera and light types and a unified nodes model.

Current Limitations

In the current form of Redshift integration there are no Redshift specific frameworks yet exposed. But the core features of Redshift can be accessed through the classic and Nodes API. Currently missing from the public API are also the Redshift render engine ID and the Redshift node space ID for node materials. They must be provided manually in third party code at the moment as demonstrated by the examples here.

Redshift has also an anti-tampering mechanism which ensures Redshift is being run with a valid license. This mechanism triggers when a debugger, as for example provided by Visual Studio and XCode, is attached to Cinema 4D. The anti-tampering mechanism then obfuscates the rendering output of Redshift as shown in Figure I. Plugins making use of Redshift can still be debugged as any other plugin, but to see the final output of a plugin which generates for example a Redshift node material setup, the plugin must be compiled and loaded by a normal instance of the Cinema 4D application without a debugger attached.

Fig I: At the top - a Redshift Material graph and of a Redshift material in a Cinema 4D instance without a debugger attached. At the bottom - the same scene loaded into a Cinema 4D instance to which a debugger has been attached, in this case provided by Visual Studio. The anti-tampering mechanism detects the debugger and obfuscates all Redshift output, as shown by the rendering of the viewport and the material preview thumbnails.

Examples

Set Render Engine to Redshift

Sets the render engine of the active render data of a document to Redshift.

Also assures that the required Redshift video post node is present in the render data. This example requires defining the Redshift renderer plugin ID as shown here, as the ID is currently not exposed in the SDK.

// The Redshift render engine plugin ID is currently not exposed in the public API and must be
// hardcoded.
const maxon::Int32 PID_REDSHIFT_RENDER_ENGINE = 1036219;
maxon::Result<void> SetRenderEngineToRedshift(BaseDocument* doc)
{
// Attempt to open an undo stack item. The undo handling can be omitted when not required.
if (!doc->StartUndo())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to open undo item."_s);
// Get the active render data of the passed document.
if (rdata == nullptr)
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, "Could not access render data of the passed document."_s);
// Set the render engine to Redshift.
if (!doc->AddUndo(UNDOTYPE::CHANGE, rdata))
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to insert undo data."_s);
bc->SetInt32(RDATA_RENDERENGINE, PID_REDSHIFT_RENDER_ENGINE);
// A lambda to search the video post nodes of a RenderData instance for a node with a specific ID.
auto FindVideoPost = [](RenderData* rdata, Int32 videoPostType) -> BaseVideoPost*
{
if (rdata == nullptr)
return nullptr;
// Get the first video post node in the render data.
BaseVideoPost* videoPost = rdata->GetFirstVideoPost();
// Iterate over all nodes until a node with #videoPostType has been found and return it or
// return #nullptr when no such node can be found.
while (videoPost)
{
if (videoPost->IsInstanceOf(videoPostType))
return videoPost;
videoPost = videoPost->GetNext();
}
return nullptr;
};
// When there is no Redshift video post node present, then insert one.
if (FindVideoPost(rdata, PID_REDSHIFT_RENDER_ENGINE) == nullptr)
{
// Allocate the Redshift video post plugin.
BaseVideoPost* redshiftVideoPost = BaseVideoPost::Alloc(PID_REDSHIFT_RENDER_ENGINE);
if (!redshiftVideoPost)
return maxon::OutOfMemoryError(
MAXON_SOURCE_LOCATION, "Could not allocate redshift video post plugin."_s);
// Insert the Redshift video post plugin.
rdata->InsertVideoPost(redshiftVideoPost);
if (!doc->AddUndo(UNDOTYPE::NEWOBJ, redshiftVideoPost))
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to insert undo data."_s);
}
// Close the undo item.
if (!doc->EndUndo())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to close undo item."_s);
return maxon::OK;
}
Definition: c4d_basecontainer.h:47
void SetInt32(Int32 id, Int32 l)
Definition: c4d_basecontainer.h:505
Definition: c4d_basedocument.h:498
Bool AddUndo(UNDOTYPE type, void *data, Bool allowFromThread=false)
Bool EndUndo(void)
RenderData * GetActiveRenderData(void)
Bool StartUndo(void)
const BaseContainer * GetDataInstance() const
Definition: c4d_baselist.h:2326
Definition: c4d_videopost.h:24
static BaseVideoPost * Alloc(Int32 type)
BaseVideoPost * GetNext(void)
Definition: c4d_videopost.h:56
Bool IsInstanceOf(Int32 id) const
Definition: c4d_baselist.h:1416
Definition: c4d_basedocument.h:144
void InsertVideoPost(BaseVideoPost *pvp, BaseVideoPost *pred=nullptr)
BaseVideoPost * GetFirstVideoPost()
@ RDATA_RENDERENGINE
Definition: drendersettings.h:39
maxon::Int32 Int32
Definition: ge_sys_math.h:60
int32_t Int32
32 bit signed integer datatype.
Definition: apibase.h:178
return OK
Definition: apibase.h:2620
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:67
@ NEWOBJ
A new object, material, tag, or other classic API node instance has been inserted into the document....
@ CHANGE
Any change to an object, including hierarchy modifications, modification in positioning,...
#define iferr_scope
Definition: resultbase.h:1374

Render a Document with Redshift

Renders the current frame in a document with the Redshift render engine into a bitmap.

The bitmap is displayed with the Picture Viewer after the rendering has finished. Uses the function RenderDocument to render the document and the example snippet Set Render Engine to Redshift to set the render engine of the passed document.

maxon::Result<void> RenderDocumentWithRedshift(BaseDocument* doc)
{
// Clone the document which should be rendered with Redshift. When it is acceptable that the
// active render data of #doc are changed to have set Redshift as their render engine, then the
// step of cloning the document can be left out.
doc = static_cast<BaseDocument*>(doc->GetClone(COPYFLAGS::NONE, nullptr));
if (doc == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Failed to clone document."_s);
// Set the render engine of #doc to Redshift. See SetRenderEngineToRedshift() example for details.
SetRenderEngineToRedshift(doc) iferr_return;
// Get the active render data of the passed document.
if (rdata == nullptr)
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, "Could not access render data of the passed document."_s);
// Get the active render data data container.
// Get the render resolution.
const maxon::Int32 xRes = bc->GetInt32(RDATA_XRES);
const maxon::Int32 yRes = bc->GetInt32(RDATA_YRES);
// Initialize a bitmap to render into with the render resolution.
bmp->AddChannel(true, true);
// Render #doc into #bmp with the render settings in #bc. It is important to pass here
// RENDERFLAGS::EXTERNAL instead of ::NONE, as all renderers which are not the standard renderer
// are considered external by Cinema 4D.
RenderDocument(doc, *bc, nullptr, nullptr, bmp, RENDERFLAGS::EXTERNAL, nullptr);
// Show the rendered bitmap in the Picture Viewer.
ShowBitmap(bmp);
// Since ShowBitmap() does make a copy of the displayed bitmap, #bmp can be freed at this point.
return maxon::OK;
}
RENDERRESULT RenderDocument(BaseDocument *doc, const BaseContainer &rdata, ProgressHook *prog, void *private_data, BaseBitmap *bmp, RENDERFLAGS renderflags, BaseThread *th, WriteProgressHook *wprog=nullptr, void *data=nullptr)
Bool ShowBitmap(const Filename &fn)
BaseBitmap * AddChannel(Bool internal, Bool straight)
static BaseBitmap * Alloc(void)
Int32 GetInt32(Int32 id, Int32 preset=0) const
Definition: c4d_basecontainer.h:303
C4DAtom * GetClone(COPYFLAGS flags, AliasTrans *trn)
Definition: c4d_baselist.h:1460
Definition: c4d_basebitmap.h:944
static void Free(MultipassBitmap *&bm)
@ RDATA_XRES
Definition: drendersettings.h:153
@ RDATA_YRES
Definition: drendersettings.h:154
@ RGB
8-bit RGB channels.
@ NONE
None.
@ EXTERNAL
External render.
#define iferr_return
Definition: resultbase.h:1465

Create a Redshift Light Object

Instantiates a Redshift light object and inserts it into a document.

Also modifies the light type and shape, the color and intensity and the transform of the new light object to demonstrate setting up a light object in more detail. Finally, adds a target tag to the light object to orient towards a dummy geometry created alongside with this example.

maxon::Result<void> CreateRedshiftLight(BaseDocument* doc)
{
// A Redshift light is a classic API object as any other and can be instantiated with its
// plugin id Orslight.
if (redshiftLight == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not allocate light object."_s);
// Get the data container pointer for the light.
BaseContainer* bc = redshiftLight->GetDataInstance();
// As for the standard renderer, different light types are all represented by the same light
// object and are only differentiated by the light type parameter of a light object instance.
// Set the type of the light to "Area" and its shape to "Disc".
// Set the light color to HSL(40°, 25%, 100%) and the light intensity to 150%. As for the standard
// lights, color values must be set in the RGB color space. There is also a HSL/RGB conversion
// function in the maxon API in addition to the classic API function HSLtoRGB() used here.
// Construct a transform translating the light to the point (-100, 500, -100).
Matrix transform = MatrixMove(Vector(-100.0, 500.0, -100.0));
// Set the new global matrix of the light and insert it into the document.
redshiftLight->SetMg(transform);
doc->InsertObject(redshiftLight, nullptr, nullptr);
// Add a cube object to the document.
if (cubeObject == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not allocate cube object."_s);
doc->InsertObject(cubeObject, nullptr, nullptr);
// Create a target tag on the light object and set the cube object as the target, orienting the
// the light object towards the cube.
BaseTag* targetTag = redshiftLight->MakeTag(Ttargetexpression);
if (targetTag == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not allocate target tag."_s);
bc = targetTag->GetDataInstance();
// When creating or changing expressions (tags) that modify a scene state, as for example this
// target tag, the passes on the document must be executed. Otherwise the expression will not
// be executed until Cinema 4D does execute the passes on the given document on its own (for
// example when the user starts interacting with the document).
doc->ExecutePasses(nullptr, false, true, false, BUILDFLAGS::NONE);
return maxon::OK;
}
Vector HSLtoRGB(const Vector &col)
void SetFloat(Int32 id, Float r)
Definition: c4d_basecontainer.h:533
void SetLink(Int32 id, C4DAtomGoal *link)
Definition: c4d_basecontainer.h:604
void SetVector(Int32 id, const Vector &v)
Definition: c4d_basecontainer.h:555
Bool ExecutePasses(BaseThread *bt, Bool animation, Bool expressions, Bool caches, BUILDFLAGS flags)
void InsertObject(BaseObject *op, BaseObject *parent, BaseObject *pred, Bool checknames=false)
Definition: c4d_baseobject.h:225
void SetMg(const Matrix &m)
Definition: c4d_baseobject.h:488
static BaseObject * Alloc(Int32 type)
BaseTag * MakeTag(Int32 type, BaseTag *pred=nullptr)
Definition: c4d_basetag.h:47
maxon::Vec3< maxon::Float64, 1 > Vector
Definition: ge_math.h:145
@ NONE
None.
#define Orslight
Redshift light.
Definition: ge_prepass.h:1011
#define Ocube
Cube.
Definition: ge_prepass.h:1076
#define Ttargetexpression
Target expression.
Definition: ge_prepass.h:1285
Matrix MatrixMove(const Vector &t)
@ REDSHIFT_LIGHT_AREA_GEOMETRY_DISC
Definition: orslight.h:197
@ REDSHIFT_LIGHT_PHYSICAL_COLOR
Definition: orslight.h:47
@ REDSHIFT_LIGHT_TYPE
Definition: orslight.h:9
@ REDSHIFT_LIGHT_TYPE_PHYSICAL_AREA
Definition: orslight.h:186
@ REDSHIFT_LIGHT_PHYSICAL_INTENSITY
Definition: orslight.h:51
@ REDSHIFT_LIGHT_PHYSICAL_AREA_GEOMETRY
Definition: orslight.h:57
@ TARGETEXPRESSIONTAG_LINK
Definition: ttargetexpression.h:6

Create a Redshift Material

Creates a Redshift node material, modifies its node graph and inserts the material into a document.

The example adds two Texture nodes, a Color Mix node, and a Maxon Noise node to the node graph of the material and creates connections between these nodes. The two texture nodes are setup to reference texture assets textures delivered with Cinema 4D. See Asset API for more information on the asset system of Cinema 4D which is used here.

maxon::Result<void> CreateRedshiftMaterial(BaseDocument* doc)
{
// Get the asset URL of the "rust" and "sketch" texture assets delivered with Cinema 4D. See the
// Asset API Handbook in the Cinema 4D C++ documentation for more information on the Asset API.
// The asset id of the "RustPaint0291_M.jpg" asset in "tex/Surfaces/Dirt Scratches & Smudges"
maxon::Id rustPaintId("file_edb3eb584c0d905c");
// The asset id of the "Sketch (HR basic026).jpg" asset in "tex/Surfaces/Dirt Scratches & Smudges"
maxon::Id sketchBasicId("file_3b194acc5a745a2c");
// Get the user preferences repository.
maxon::AssetRepositoryRef lookupRepo = maxon::AssetInterface::GetUserPrefsRepository();
if (!lookupRepo)
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, "Could not access user preferences repository"_s);
// Retrieve the asset descriptions for both assets.
const maxon::Id fileTypeId = maxon::AssetTypes::File().GetId();
const maxon::AssetDescription rustAssetDescription = lookupRepo.FindLatestAsset(
if (!rustAssetDescription)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find texture asset."_s);
const maxon::AssetDescription sketchAssetDescription = lookupRepo.FindLatestAsset(
fileTypeId, sketchBasicId, maxon::Id(), maxon::ASSET_FIND_MODE::LATEST) iferr_return;
if (!sketchAssetDescription)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find texture asset."_s);
// Get asset URL from both asset descriptions, pointing to the texture wrapped by the asset.
// There are no further steps required as downloading, the Asset API will handle the access
// and the resolving of these asset URLs in the "asset" scheme.
rustAssetDescription, true) iferr_return;
const maxon::Url sketchTextureUrl = maxon::AssetInterface::GetAssetUrl(
sketchAssetDescription, true) iferr_return;
// --- Start of Redshift related code ------------------------------------------------------------
// Create a NodeMaterial by instantiating a Mmaterial BaseMaterial and casting it to a
// NodeMaterial. This could also be done in two steps (first allocating the Mmaterial and
// then casting it) or by casting an already existing Mmaterial into a NodeMaterial.
NodeMaterial* material = static_cast<NodeMaterial*>(BaseMaterial::Alloc(Mmaterial));
if (material == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not allocate node material."_s);
// Define the id of the Redshift node space and add that node space to the material. When the
// node material should contain graphs for other node spaces, these must also be added.
const maxon::LiteralId redshiftId("com.redshift3d.redshift4c4d.class.nodespace");
material->AddGraph(redshiftId) iferr_return;
// Get the Redshift node graph from the material.
const maxon::nodes::NodesGraphModelRef& graph = material->GetGraph(redshiftId) iferr_return;
// The ids of the nodes which are required to build the graph. These ids can be discovered in the
// Asset Browser with the #-button in the "Info Area" of the Asset Browser.
const maxon::Id colormixId("com.redshift3d.redshift4c4d.nodes.core.rscolormix");
const maxon::Id noiseId("com.redshift3d.redshift4c4d.nodes.core.maxonnoise");
const maxon::Id rsmaterialId("com.redshift3d.redshift4c4d.nodes.core.material");
const maxon::Id textureId("com.redshift3d.redshift4c4d.nodes.core.texturesampler");
// Start modifying the graph by starting a graph transaction. Transactions in the Nodes API work
// similar to transactions in databases and implement an all-or-nothing model. When an error occurs
// within a transaction, all already carried out operations will not be applied to the graph. The
// modifications to a graph are only applied when the transaction is committed. The scope
// delimiters { and } used here between BeginTransaction() and transaction.Commit() are not
// technically required, but they make a transaction more readable.
maxon::GraphTransaction transaction = graph.BeginTransaction() iferr_return;
{
// Find the RS-Material node which is contained within a standard Redshift material graph. This
// example assumes that there is exactly one RS-Material node in the graph that is already
// connected to the output node (which is true for the RS default material as of S26).
graph, rsmaterialId, false, results) iferr_return;
if (results.GetCount() < 1)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find RS-Material node."_s);
maxon::GraphNode rsmaterialNode = results[0];
// Add the new nodes which are required for the setup. Passing the empty ID for the node IDs
// will let Cinema 4D choose a node id, which is often the best option when newly created nodes
// must not be referenced by their id later.
maxon::GraphNode colormixNode = graph.AddChild(maxon::Id(), colormixId) iferr_return;
maxon::GraphNode noiseNode = graph.AddChild(maxon::Id(), noiseId) iferr_return;
maxon::GraphNode rustTextureNode = graph.AddChild(maxon::Id(), textureId) iferr_return;
maxon::GraphNode sketchTextureNode = graph.AddChild(maxon::Id(), textureId) iferr_return;
// The port IDs which are used here can be discovered with the view/"Show ID" option in the
// dialog menu of the Node Editor. Selecting ports with this option enabled will show their ID
// in the info overlay in the bottom left corner of the Node Editor.
// Connect the "outColor" out-port of the the "Texture" node for the rust texture to the
// "Input 1" in-port of the "Color Mix" node.
// This is the collection of all out-ports of the texture node for the rust texture node.
maxon::GraphNode outportsRust = rustTextureNode.GetOutputs() iferr_return;
// This is the node representing the output port "Out Color" of the rust texture node.
maxon::GraphNode outcolorOutportRust = outportsRust.FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.outcolor")) iferr_return;
// Carry out the same operation but for the "Input 1" input port of the "Color Mix" node.
maxon::GraphNode inportsColormix = colormixNode.GetInputs() iferr_return;
maxon::GraphNode input1InportColormix = inportsColormix.FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.input1")) iferr_return;
// Assert that both ports have been referenced correctly.
if (!outcolorOutportRust.IsValid() || !input1InportColormix.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
// Connect the "Out Color" out-port to the "Input 1" in-port. The order, connecting an output
// port to an input port, is important here.
outcolorOutportRust.Connect(input1InportColormix) iferr_return;
// Connect the output port of the sketch "Texture" node to the "Input 2" in-port of the
// "Color Mix" node.
maxon::GraphNode outcolorOutportSketch = sketchTextureNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.outcolor")) iferr_return;
maxon::GraphNode input2InportColormix = colormixNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.input2")) iferr_return;
if (!outcolorOutportSketch.IsValid() || !input2InportColormix.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
outcolorOutportSketch.Connect(input2InportColormix) iferr_return;
// Connect the output port of the "Color Mix" node to the to the "Diffuse Color" in-port of the
// "RS Material" node.
maxon::GraphNode outcolorOutportColormix = colormixNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.outcolor")) iferr_return;
maxon::GraphNode diffusecolorInportRsmaterial = rsmaterialNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.material.diffuse_color")) iferr_return;
if (!outcolorOutportColormix.IsValid() || !diffusecolorInportRsmaterial.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
outcolorOutportColormix.Connect(diffusecolorInportRsmaterial) iferr_return;
// Connect the output port of the "Maxon Noise" node both to the to the "Mix Amount" in-port of
// the "Color Mix" node and the in-port "Reflection Roughness" of the "RS Material" node.
maxon::GraphNode outcolorOutportNoise = noiseNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.maxonnoise.outcolor")) iferr_return;
maxon::GraphNode mixamountInportColormix = inportsColormix.FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.mixamount")) iferr_return;
maxon::GraphNode reflectionroughnessInportRsmaterial = rsmaterialNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.material.refl_roughness")) iferr_return;
if (!outcolorOutportNoise.IsValid() || !mixamountInportColormix.IsValid() ||
!reflectionroughnessInportRsmaterial.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
outcolorOutportNoise.Connect(mixamountInportColormix) iferr_return;
outcolorOutportNoise.Connect(reflectionroughnessInportRsmaterial) iferr_return;
// Set the noise type port of the "Maxon Noise" node to a new dfault value.
// Setting a value of a port (in this case the noise_type port) without a connection, i.e., a
// wire from an out-going port, is done by setting the default value of a port. What is done
// here is the equivalent to a user changing the value of a node parameter in the Attribute
// Manager of Cinema 4D.
maxon::GraphNode noisetypeInportNoise = noiseNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.maxonnoise.noise_type")) iferr_return;
if (!noisetypeInportNoise.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
// Set the noise type to wavy turbulence.
// Set the texture path ports of both Texture nodes to new default values.
// Retrieve the "Filename" port of the texture node.
maxon::GraphNode tex0InportRust = rustTextureNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0")) iferr_return;
if (!tex0InportRust.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
// The "Filename" port is a port bundle which consists out of two sub-ports, the "path" and the
// "layer" port. The texture URL is written into the "path" sub-port.
maxon::GraphNode pathInportRust = tex0InportRust.FindChild(maxon::Id("path")) iferr_return;
if (!pathInportRust.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
// Set the path of the rust texture node to the URL of the rust texture asset.
pathInportRust.SetDefaultValue(rustTextureUrl) iferr_return;
// Set the path of the sketch texture node to the URL of the sketch texture asset.
maxon::GraphNode tex0InportSketch = sketchTextureNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0")) iferr_return;
if (!tex0InportRust.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
maxon::GraphNode pathInportSketch = tex0InportSketch.FindChild(maxon::Id("path")) iferr_return;
if (!pathInportRust.IsValid())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to access port."_s);
pathInportSketch.SetDefaultValue(sketchTextureUrl) iferr_return;
}
transaction.Commit() iferr_return;
// Insert the material into the document.
doc->InsertMaterial(material);
return maxon::OK;
}
void InsertMaterial(BaseMaterial *mat, BaseMaterial *pred=nullptr, Bool checknames=false)
Definition: c4d_basematerial.h:28
Definition: c4d_basematerial.h:391
static MAXON_METHOD const UpdatableAssetRepositoryRef & GetUserPrefsRepository()
static MAXON_METHOD Result< Url > GetAssetUrl(const AssetDescription &asset, Bool isLatest)
Definition: basearray.h:413
MAXON_ATTRIBUTE_FORCE_INLINE Int GetCount() const
Definition: basearray.h:574
static MAXON_METHOD Result< void > FindNodesByAssetId(const GraphModelRef &graphModel, const Id &assetId, Bool exactId, const ValueReceiver< const GraphNode & > &callback)
Result< typename SFINAEHelper< GraphNode, BASE >::type > GetOutputs() const
Definition: graph.h:1348
Result< Bool > SetDefaultValue(T &&value) const
Definition: graph.h:1916
Result< typename SFINAEHelper< GraphNode, BASE >::type > FindChild(const InternedId &name) const
Definition: graph.h:1371
Result< typename SFINAEHelper< GraphNode, BASE >::type > GetInputs() const
Definition: graph.h:1337
Result< void > Connect(const GraphNode &target, Wires modes=WIRE_MODE::CONNECT_DEFAULT, Bool reverse=false) const
Definition: graph.h:1622
Definition: graph.h:2314
Bool IsValid() const
Definition: graph.h:2327
Definition: apibaseid.h:251
Definition: url.h:876
#define Mmaterial
Standard material.
Definition: ge_prepass.h:983
@ NOISE_WAVY_TURB
Wavy turbulence.
Definition: lib_noise.h:60
The maxon namespace contains all declarations of the MAXON API.
Definition: c4d_basedocument.h:16
Url GetAssetUrl(const DndAsset &asset)
@ LATEST
Set this flag to obtain only the latest version of the asset.