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 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.

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.
RenderData* rdata = doc->GetActiveRenderData();
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);
// 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, VPrsrenderer) == nullptr)
{
// Allocate the Redshift video post plugin.
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
const BaseContainer * GetDataInstance() const
Definition: c4d_baselist.h:2346
Definition: c4d_videopost.h:24
static BaseVideoPost * Alloc(Int32 type)
BaseVideoPost * GetNext()
Definition: c4d_videopost.h:56
Bool IsInstanceOf(Int32 id) const
Definition: c4d_baselist.h:1436
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
return OK
Definition: apibase.h:2690
#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 VPrsrenderer
Videopost plugin 'Redshift'. @PublicExposure.
Definition: c4d_videopostdata.h:251
const char * doc
Definition: pyerrors.h:226
#define iferr_scope
Definition: resultbase.h:1384

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)
{
if (doc == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "The passed document is not null."_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.
RenderData* rdata = doc->GetActiveRenderData();
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 and add an alpha channel to it.
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()
Int32 GetInt32(Int32 id, Int32 preset=0) const
Definition: c4d_basecontainer.h:303
Definition: c4d_basebitmap.h:968
static void Free(MultipassBitmap *&bm)
@ RDATA_XRES
Definition: drendersettings.h:154
@ RDATA_YRES
Definition: drendersettings.h:155
@ RGB
8-bit RGB channels.
int32_t Int32
32 bit signed integer datatype.
Definition: apibase.h:176
@ EXTERNAL
External render.
#define iferr_return
Definition: resultbase.h:1519

Create a Redshift Camera

Instantiates a Redshift camera and inserts it into a document.

Also modifies the projection mode, the near clipping plane and the transform of the new camera to demonstrate setting up a camera in more detail.

maxon::Result<void> CreateRedshiftCamera(BaseDocument* doc)
{
// The Redshift camera is a classic API object as any other and can be instantiated with its
// plugin id Orscamera.
if (!redshiftCamera)
return maxon::OutOfMemoryError(
MAXON_SOURCE_LOCATION, "Could not allocate Redshift camera object."_s);
// Get the data container pointer for the camera.
BaseContainer* bc = redshiftCamera->GetDataInstance();
// Set the camera projection from the default value of "Perspective" to "Orthographic".
// Enable the "near-clip-plane" and sets its value to 100 units.
// Construct a transform translating the camera to the point (500, 500, 0) and rotating it first
// by 45° on the y-axis and then by -25° on the x-axis.
Matrix transform = (
MatrixMove(Vector(500.0, 500.0, -250.0)) *
// Set the new global matrix of the camera and insert it into the document.
redshiftCamera->SetMg(transform);
doc->InsertObject(redshiftCamera, nullptr, nullptr);
// Set the camera as the active render camera of the document.
BaseDraw* renderBaseDraw = doc->GetRenderBaseDraw();
if (!renderBaseDraw)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not access render BaseDraw."_s);
renderBaseDraw->SetSceneCamera(redshiftCamera);
// Converting between Orscamera and Ocamera sensor size values:
// Under the parameter RSCAMERAOBJECT_APERTURE, an Orscamera object is exposing a sensor size
// equivalent for the standard Ocamera object parameter CAMERAOBJECT_APERTURE, the value which is
// named "Sensor Size (Film Gate)" in the Attribute Manager. While the horizontal sensor size of
// an Orscamera object exposed with RSCAMERAOBJECT_SENSOR_SIZE is equal to the conversion value
// RSCAMERAOBJECT_APERTURE in some configurations, this does not hold true for all camera
// configurations.
const Float sensorSizeStdCamera = bc->GetFloat(RSCAMERAOBJECT_APERTURE);
BaseObject* convertStdCamera = BaseObject::Alloc(Ocamera);
if (!convertStdCamera)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not allocate camera object."_s);
convertStdCamera->SetParameter(
// To convert from an Ocamera instance to a new Orscamera, the operation can be simply reversed.
// The new Orscamera will then automatically be set to horizontal fitting mode for its sensor.
const Float stdCameraApperatureValue = 50.0;
BaseObject* convertRsCamera = BaseObject::Alloc(Orscamera);
if (!convertRsCamera)
return maxon::OutOfMemoryError(
MAXON_SOURCE_LOCATION, "Could not allocate Redshift camera object."_s);
convertRsCamera->SetParameter(
RSCAMERAOBJECT_APERTURE, GeData(stdCameraApperatureValue), DESCFLAGS_SET::NONE);
convertStdCamera->SetName("Conversion Redshift->Standard"_s);
convertRsCamera->SetName("Conversion Standard->Redshift"_s);
doc->InsertObject(convertRsCamera, nullptr, nullptr);
doc->InsertObject(convertStdCamera, nullptr, nullptr);
return maxon::OK;
}
Float GetFloat(Int32 id, Float preset=0.0) const
Definition: c4d_basecontainer.h:335
void SetFloat(Int32 id, Float r)
Definition: c4d_basecontainer.h:533
void SetBool(Int32 id, Bool b)
Definition: c4d_basecontainer.h:498
Definition: c4d_basedraw.h:754
void SetSceneCamera(BaseObject *op, Bool animate=false)
Definition: c4d_basedraw.h:842
void SetName(const maxon::String &name)
Definition: c4d_baselist.h:2387
Definition: c4d_baseobject.h:225
void SetMg(const Matrix &m)
Definition: c4d_baseobject.h:488
static BaseObject * Alloc(Int32 type)
Bool SetParameter(const DescID &id, const GeData &t_data, DESCFLAGS_SET flags)
Definition: c4d_gedata.h:83
maxon::Vec3< maxon::Float64, 1 > Vector
Definition: ge_math.h:145
maxon::Float Float
Definition: ge_sys_math.h:66
MAXON_ATTRIBUTE_FORCE_INLINE Float32 DegToRad(Float32 r)
Converts float value from degrees to radians.
Definition: apibasemath.h:474
#define Orscamera
New Camera Object (Redshift)
Definition: ge_prepass.h:1037
#define Ocamera
Camera - CameraObject.
Definition: ge_prepass.h:1036
Matrix MatrixRotY(Float w)
Matrix MatrixRotX(Float w)
Matrix MatrixMove(const Vector &t)
@ CAMERAOBJECT_APERTURE
Definition: ocamera.h:42
@ RSCAMERAOBJECT_PROJECTION_ORTHOGRAPHIC
Definition: orscamera.h:229
@ RSCAMERAOBJECT_NEAR_CLIPPING_ENABLE
Definition: orscamera.h:18
@ RSCAMERAOBJECT_APERTURE
Definition: orscamera.h:46
@ RSCAMERAOBJECT_PROJECTION
Definition: orscamera.h:10
@ RSCAMERAOBJECT_NEAR_CLIPPING
Definition: orscamera.h:17

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 SetLink(Int32 id, C4DAtomGoal *link)
Definition: c4d_basecontainer.h:604
void SetVector(Int32 id, const Vector &v)
Definition: c4d_basecontainer.h:555
BaseTag * MakeTag(Int32 type, BaseTag *pred=nullptr)
Definition: c4d_basetag.h:48
@ NONE
None.
#define Orslight
Redshift light.
Definition: ge_prepass.h:1035
#define Ocube
Cube.
Definition: ge_prepass.h:1102
#define Ttargetexpression
Target expression.
Definition: ge_prepass.h:1405
@ REDSHIFT_LIGHT_AREA_GEOMETRY_DISC
Definition: orslight.h:203
@ REDSHIFT_LIGHT_PHYSICAL_COLOR
Definition: orslight.h:47
@ REDSHIFT_LIGHT_TYPE
Definition: orslight.h:9
@ REDSHIFT_LIGHT_TYPE_PHYSICAL_AREA
Definition: orslight.h:192
@ 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 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 an empty graph for that node space to the
// material.
const maxon::LiteralId redshiftId("com.redshift3d.redshift4c4d.class.nodespace");
material->CreateEmptyGraph(redshiftId) iferr_return;
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 outputNodeTypeId("com.redshift3d.redshift4c4d.node.output");
const maxon::Id materialNodeTypeId("com.redshift3d.redshift4c4d.nodes.core.standardmaterial");
const maxon::Id colormixNodeTypeId("com.redshift3d.redshift4c4d.nodes.core.rscolormix");
const maxon::Id noiseNodeTypeId("com.redshift3d.redshift4c4d.nodes.core.maxonnoise");
const maxon::Id textureNodeTypeId("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;
{
// Add the new nodes to the graph which are required for the setup. Passing the empty ID as
// the first argument will let Cinema 4D choose the node IDs, which is often the best option
// when newly created nodes must not be referenced by their ID later.
maxon::GraphNode outNode = graph.AddChild(maxon::Id(), outputNodeTypeId) iferr_return;
maxon::GraphNode materialNode = graph.AddChild(maxon::Id(), materialNodeTypeId) iferr_return;
maxon::GraphNode colormixNode = graph.AddChild(maxon::Id(), colormixNodeTypeId) iferr_return;
maxon::GraphNode noiseNode = graph.AddChild(maxon::Id(), noiseNodeTypeId) iferr_return;
maxon::GraphNode rustTexNode = graph.AddChild(maxon::Id(), textureNodeTypeId) iferr_return;
maxon::GraphNode sketchTexNode = graph.AddChild(maxon::Id(), textureNodeTypeId) iferr_return;
// The port IDs which are used here can be discovered with the "IDs" option "Preferences/Node
// Editor" option enabled. The selection info overlay in the bottom left corner of the Node
// Editor will now show both the IDs of the selected node or port.
// Get the "Out Color" out-port of the "Standard Material" node and the "Surface" in-port of
// from the "Output" node in this graph.
maxon::GraphNode outcolorPortMaterialNode = materialNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.standardmaterial.outcolor")) iferr_return;
maxon::GraphNode surfacePortOutNode = outNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.node.output.surface")) iferr_return;
// Connect the "Out Color" port to the "Surface" port. The connection order of an out-port
// connecting to an in-port is mandatory.
outcolorPortMaterialNode.Connect(surfacePortOutNode) iferr_return;
// 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.
maxon::GraphNode outcolorPortRustTexNode = rustTexNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.outcolor")) iferr_return;
maxon::GraphNode input1PortColormixNode = colormixNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.input1")) iferr_return;
outcolorPortRustTexNode.Connect(input1PortColormixNode) iferr_return;
// Connect the output port of the sketch "Texture" node to the "Input 2" in-port of the
// "Color Mix" node.
maxon::GraphNode outcolorPortSketchTexNode = sketchTexNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.outcolor")) iferr_return;
maxon::GraphNode input2PortColormixNode = colormixNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.input2")) iferr_return;
outcolorPortSketchTexNode.Connect(input2PortColormixNode) iferr_return;
// Connect the output port of the "Color Mix" node to the "Base > Color" in-port of the "Standard
// Material" node.
maxon::GraphNode outcolorPortColormixNode = colormixNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.outcolor")) iferr_return;
maxon::GraphNode basecolorPortMaterialNode = materialNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.standardmaterial.base_color")) iferr_return;
outcolorPortColormixNode.Connect(basecolorPortMaterialNode) iferr_return;
// Connect the output port of the "Maxon Noise" node both to the "Mix Amount" in-port of
// the "Color Mix" node and the in-port "Reflection > Roughness" of the "Standard Material" node.
maxon::GraphNode outcolorPortNoiseNode = noiseNode.GetOutputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.maxonnoise.outcolor")) iferr_return;
maxon::GraphNode amountPortColormixNode = colormixNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix.mixamount")) iferr_return;
maxon::GraphNode roughnessPortMaterialNode = materialNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.standardmaterial.refl_roughness")) iferr_return;
outcolorPortNoiseNode.Connect(amountPortColormixNode) iferr_return;
outcolorPortNoiseNode.Connect(roughnessPortMaterialNode) iferr_return;
// Set the noise type of the "Maxon Noise" node to "Wavy Turbulence"
// Setting a value of a port without a connection 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 noise type of
// the noise node to "Wavy Turbulence" in the Attribute Manager of Cinema 4D.
maxon::GraphNode noisetypePortNoiseNode = noiseNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.maxonnoise.noise_type")) iferr_return;
noisetypePortNoiseNode.SetDefaultValue(NOISE_WAVY_TURB) iferr_return;
// Set the texture paths of both texture nodes to the texture asset URLs defined above.
// Here we encounter something new, a port which has ports itself is a "port-bundle" in terms
// of the Nodes API. The "Filename" port of a texture node is a port bundle which consists out
// of two sub-ports, the "path" and the "layer" port of the texture. The texture URL must be
// written into the "path" sub-port.
maxon::GraphNode pathPortRustTexNode = rustTexNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0")).FindChild(
pathPortRustTexNode.SetDefaultValue(rustTextureUrl) iferr_return;
maxon::GraphNode pathPortSketchTexNode = sketchTexNode.GetInputs().FindChild(
maxon::Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0")).FindChild(
pathPortSketchTexNode.SetDefaultValue(sketchTextureUrl) iferr_return;
} transaction.Commit() iferr_return;
// Insert the material into the document.
doc->InsertMaterial(material);
return maxon::OK;
}
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)
Result< typename SFINAEHelper< GraphNode, BASE >::type > GetOutputs() const
Definition: graph.h:1204
Result< Bool > SetDefaultValue(T &&value) const
Definition: graph.h:1785
Result< typename SFINAEHelper< GraphNode, BASE >::type > GetInputs() const
Definition: graph.h:1193
Result< void > Connect(const GraphNode &target, Wires modes=WIRE_MODE::CONNECT_DEFAULT, Bool reverse=false) const
Definition: graph.h:1491
Definition: graph.h:1950
Definition: apibaseid.h:253
Definition: url.h:952
Py_ssize_t char * output
Definition: unicodeobject.h:985
#define Mmaterial
Standard material.
Definition: ge_prepass.h:998
@ NOISE_WAVY_TURB
Wavy turbulence.
Definition: lib_noise.h:60
The maxon namespace contains all declarations of the MAXON API.
Definition: autoweight.h:14
Url GetAssetUrl(const DndAsset &asset)
@ LATEST
Set this flag to obtain only the latest version of the asset.
Definition: node.h:10