Convert colors with the color profiles provided by the OpenColorIO (OCIO) configuration of a scene.
Overview
Cinema 4D implements color management primarily with International Color Consortium (ICC) color profiles and the OpenColorIO (OCIO) standard. OCIO implements a color management pipeline for digital content creation applications to decouple the color representation requirements of color computations from the requirements of displaying colors on hardware-devices. This allows for a lossless transfer of color data between different applications while giving artists always the ability to view their artwork with the colors the final consumer will see. OCIO achieves this by defining color spaces by purpose so that they can be applied selectively to color data. The two abstract color spaces and one transform defined by the OCIO standard are:
- The Render Space is the color space the application does operate in. All color data is converted to this space before processing and the application does carry out all computations in this space. This is usually a linear color space. For Cinema 4D documents in OCIO mode this is by default the ACEScg space.
- The Display Space is a space to convert colors from the Render Space to a color representation which is suited for displaying these colors on a screen. This is usually a non-linear color space. For Cinema 4D documents in OCIO mode this is by default the sRGB space.
- The View Transform is a transform which is applied before the display space and is meant to emulate the final look of color data on a consumer device. This could for example emulate the look of a movie-screen on the display of an artist. For Cinema 4D documents in OCIO mode this is by default the ACES 1.0 SDR-video space.
- Cinema 4D adds to this a special transform which is only applied to thumbnails, the Thumbnail View Transform.
Each application in a color management pipeline assigns a color profile to each of these abstract color spaces to suite its specific needs. Applications communicate the possible choices for each space with the help of OCIO configuration files, allowing for a persistent color previewing experience along the pipeline without having to bake hardware dependent information into outputs (Fig. I).
Technical Overview
Cinema 4D currently does provide only shallow public access to its OCIO API, with the consequence that high level OCIO concepts such as an OCIO configuration or an OCIO processor are not represented by dedicated types in the public API. There are however multiple entry points which provide access to the most important functionalities of OCIO.
OCIO is bound intrinsically to a scene in form of cinema::BaseDocument, a scene can either have OCIO enabled or not, and also stores the currently active color profiles for the principal OCIO spaces. These settings are expressed as the parameters:
- Note
- There are two exception to the rule of OCIO color spaces being intrinsically bound to a document: The type cinema::BaseBitmap and cinema::VideoPostData. With the methods cinema::BaseBitmap::GetColorProfile and SetColorProfile, the three OCIO transforms render, display, and view can be overwritten on a per bitmap basis. This can be useful when a bitmap should ignore the OCIO display and view transforms in the Picture Viewer of Cinema 4D. Similarly, cinema::VideoPostData::GetColorProfileInfo allows for overriding color profile information in an upcoming rendering.
These parameters can be read and written with cinema::BaseDocument::GetParameter and SetParameter. Due to the fact that the values of OCIO color spaces and transforms depend on the loaded OCIO configuration, the values written to the parameters must be retrieved with the following functions:
Additionally, the following methods exist:
- CopyLinearWorkflow: Copies the color management settings from one document to another.
- GetOcioConfigPath: Returns the OCIO configuration path used by Cinema 4D.
- UpdateOcioColorSpaces: Propagates changes made to the OCIO settings of a document to the bound OCIO color spaces.
- GetOcioProfiles: Returns the color profiles for the currently active OCIO settings.
To convert colors between OCIO color space representations, the type cinema::OcioConverter must be used, providing the methods:
The transform paths are defined by the enumeration COLORSPACETRANSFORMATION. Note that a path can contain multiple transforms, as the path is always carried out in a sensible manner, e.g., OCIO_RENDERING_TO_VIEW will contain the display transform, as the OCIO transform chain is render->display->view
. The available paths are:
Related Topics
Examples
The examples shown here are all part of the OCIO Plugin in the SDK. Once the SDK has been compiled and installed, the plugin can be found under the menu entry Extensions\Example.image\C++ SDK: OCIO Examples
.
Color Convert Scenes
Convert all colors contained in a document or contained in a set of elements in a document to a new OCIO Render space.
{
BaseContainer* bc =
doc->GetDataInstance();
{
doc->UpdateOcioColorSpaces();
}
doc->GetActiveOcioColorSpacesNames(renderSpaceName, _dummy, _dummy, _dummy);
AutoAlloc<SceneColorConverter> converter;
if (!converter)
converter->Init(
doc,
"sRGB"_cs,
"scene-linear Rec.709-sRGB"_cs, renderSpaceName)
iferr_return;
}
NONE
Definition: asset_browser.h:1
Definition: string.h:1542
Definition: hashmap.h:3031
PyObject PyObject * result
Definition: abstract.h:43
@ DOCUMENT_COLOR_MANAGEMENT
Definition: ddoc.h:153
@ DOCUMENT_COLOR_MANAGEMENT_OCIO_CONVERTED
Definition: ddoc.h:157
@ DOCUMENT_COLOR_MANAGEMENT_OCIO
Definition: ddoc.h:155
return OK
Definition: apibase.h:2740
#define MAXON_FUNCTIONNAME
This macro returns the function name of the current member or global function.
Definition: objectbase.h:2902
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:69
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:204
#define ConstDescID(...)
Definition: lib_description.h:592
void EventAdd(EVENT eventflag=EVENT::NONE)
const char * doc
Definition: pyerrors.h:226
#define iferr_scope
Definition: resultbase.h:1396
#define iferr_return
Definition: resultbase.h:1531
Copy Color Management Settings
Copy all color management settings from one document to another.
This does not entail any scene element color space conversions, one must instead use SceneColorConverter as demonstrated in the example Color Convert Scenes .
{
AutoAlloc<BaseDocument> newDoc;
BaseDocument::CopyLinearWorkflow(
doc, newDoc,
false);
newDoc->SetName(
doc->GetName() +
"(Copy)");
doc->GetName(), newDoc->GetName());
newDoc.Free();
}
Read and Write OCIO Settings
Read and write the OCIO color management settings stored in a document.
{
BaseContainer* bc =
doc->GetDataInstance();
{
doc->UpdateOcioColorSpaces();
}
{
}
"OCIO configuration does not contain a 'ACES2065 - 1' render space."_s);
doc->UpdateOcioColorSpaces();
}
PyObject PyObject const char const char char ** s
Definition: bytesobject.h:60
@ DOCUMENT_OCIO_RENDER_COLORSPACE
Definition: ddoc.h:144
#define NOTOK
Definition: ge_sys_math.h:258
int32_t Int32
32 bit signed integer datatype.
Definition: apibase.h:175
#define MAXON_UNLIKELY(...)
Definition: compilerdetection.h:427
Convert Colors
Convert colors along OCIO conversion paths defined by the OCIO color spaces associated with a document.
{
BaseContainer* bc =
doc->GetDataInstance();
{
doc->UpdateOcioColorSpaces();
}
if (!converter)
{
if (!converter)
}
}
OCIO_SRGB_TO_RENDERING
sRGB to Rendering color space transformation.
Definition: ge_prepass.h:16
OCIO_RENDERING_TO_VIEW
Rendering to view color space transformation.
Definition: ge_prepass.h:9
OCIO_VIEW_TO_RENDERING
View to rendering color space transformation.
Definition: ge_prepass.h:11
OCIO_RENDERING_TO_DISPLAY
Rendering to display color space transformation.
Definition: ge_prepass.h:14
maxon::StrongRef< OcioConverter > OcioConverterRef
Definition: operatingsystem.h:317
A vector consisting of three components X, Y and Z.
Definition: vec.h:21
Convert Colors Arbitrarily
Convert colors from and to OCIO color spaces using arbitrary in- and output spaces.
{
BaseContainer* bc =
doc->GetDataInstance();
{
doc->UpdateOcioColorSpaces();
}
return maxon::IoError(
const maxon::ColorProfile linearRgbSpaceProfile = maxon::ColorSpaces::RGBspace(
).GetDefaultLinearColorProfile();
maxon::ColorProfile renderSpaceProfile, _;
doc->GetOcioProfiles(renderSpaceProfile, _, _, _);
doc->GetActiveOcioColorSpacesNames(renderSpaceName, __, __, __);
const maxon::PixelFormat rgbFormat = maxon::PixelFormats::RGB::F32();
if (!(srgb2014Profile.CheckCompatiblePixelFormat(rgbFormat) ||
linearRgbSpaceProfile.CheckCompatiblePixelFormat(rgbFormat) ||
renderSpaceProfile.CheckCompatiblePixelFormat(rgbFormat)))
return maxon::UnexpectedError(
rgbFormat, srgb2014Profile, rgbFormat, linearRgbSpaceProfile,
rgbFormat, linearRgbSpaceProfile, rgbFormat, renderSpaceProfile,
(
const maxon::Pix*)&inputBuffer.r, maxon::PixelFormats::RGB::F32());
(
maxon::Pix*)&outputBuffer.r, maxon::PixelFormats::RGB::F32());
preConverter.Convert(inputBufferHandler, outputBufferHandler, 1)
iferr_return;
srgb2014Profile, colorData, linearRgbSpaceProfile, outputBuffer);
inputBuffer = outputBuffer;
ocioConverter.Convert(inputBufferHandler, outputBufferHandler, 1)
iferr_return;
srgb2014Profile, colorData, renderSpaceName, outputBuffer);
}
static MAXON_METHOD Result< ColorProfileConvert > Init(const PixelFormat &srcPixelFormat, const ColorProfile &srcProfile, const PixelFormat &dstPixelFormat, const ColorProfile &dstProfile, COLORCONVERSIONINTENT intent, COLORCONVERSIONFLAGS flags)
static MAXON_METHOD Result< ColorProfile > OpenProfileFromFile(const Url &fn)
Definition: string.h:1287
ImageBufferTemplate< PixelConstBuffer > ImageConstBuffer
Definition: gfx_image_pixelformat.h:186
UChar Pix
unspecified pixel format depth.
Definition: gfx_image_imagechannel.h:17
ImageBufferTemplate< PixelMutableBuffer > ImageMutableBuffer
Definition: gfx_image_pixelformat.h:187
#define MAXON_FILE
Definition: compilerdetection.h:518
@ NONEXISTENT
Url doesn't exist.
A color consisting of three components R, G and B.
Definition: col.h:16
Several functions use this helper structure to pass the image data to functions.
Definition: gfx_image_pixelformat.h:524
Get and Set Color Parameters
Read and write color parameters in an OCIO document either in the native Render space of the document or other spaces.
{
BaseContainer* bc =
doc->GetDataInstance();
{
doc->UpdateOcioColorSpaces();
}
doc->GetActiveOcioColorSpacesNames(renderSpace, _, viewTransform, _);
GeData data;
const Vector defaultColor = data.GetVector();
if (!converter)
const Vector colorSrgb = converter->TransformColor(
BaseMaterial* m1 = BaseMaterial::Alloc(
Mmaterial);
BaseMaterial* m2 = BaseMaterial::Alloc(
Mmaterial);
BaseMaterial* m3 = BaseMaterial::Alloc(
Mmaterial);
const Vector color{ 1, 0, 0 };
m1->SetName("Material (Render Space)"_s);
m2->SetName("Material (sRGB)"_s);
m3->SetName("Material (View Transform)"_s);
}
@ DOCUMENT_DEFAULTMATERIAL_COLOR
Definition: ddoc.h:67
OCIO_RENDERING_TO_SRGB
Rendering to sRGB color space transformation.
Definition: ge_prepass.h:17
#define Mmaterial
Standard material.
Definition: ge_prepass.h:1007
@ MATERIAL_COLOR_COLOR
Definition: mmaterial.h:56
maxon::Vec3< maxon::Float64, 1 > Vector
Definition: ge_math.h:140
Manage Bitmap OCIO Color Profiles
Read and write the OCIO color spaces associated with cinema::BaseBitmap instances to change or nullify parts of an OCIO conversion path for them.
This makes it for example possible to disable the Display and View transform for a singular bitmap when displayed in the Picture Viewer.
{
BaseBitmap* clone;
finally { BaseBitmap::Free(clone); };
BaseContainer* bc =
doc->GetDataInstance();
{
doc->UpdateOcioColorSpaces();
}
const maxon::Id assetId(
"file_9748feafc2c00be8");
const maxon::AssetDescription asset = repository.FindLatestAsset(
AutoAlloc<BaseBitmap> bitmap;
clone = bitmap->GetClone();
const ColorProfile* const profile = clone->GetColorProfile(BaseBitmap::COLORPROFILE_INDEX_RENDERSPACE);
clone->SetColorProfile(profile, BaseBitmap::COLORPROFILE_INDEX_DISPLAYSPACE);
clone->SetColorProfile(profile, BaseBitmap::COLORPROFILE_INDEX_VIEW_TRANSFORM);
}
static MAXON_METHOD const UpdatableAssetRepositoryRef & GetUserPrefsRepository()
static MAXON_METHOD Result< Url > GetAssetUrl(const AssetDescription &asset, Bool isLatest)
Definition: apibaseid.h:243
OK
User has selected a font.
Definition: customgui_fontchooser.h:0
IMAGERESULT
Definition: ge_prepass.h:3947
Bool ShowBitmap(const Filename &fn)
maxon::Url MaxonConvert(const Filename &fn, MAXONCONVERTMODE convertMode)
The maxon namespace contains all declarations of the Maxon API.
Definition: autoweight.h:21
@ LATEST
Set this flag to obtain only the latest version of the asset.
const char const char const char * file
Definition: object.h:439
OCIO Aware Render
Realizes a renderer which manipulates the OCIO profiles of an upcoming rendering.
void OcioAwareRenderer::GetColorProfileInfo(
BaseVideoPost*
node, VideoPostStruct* vps, ColorProfileInfo&
info)
{
return;
BaseContainer* data =
node->GetDataInstance();
if (data->GetBool(ID_OVERWRITE_OCIO_DISPLAY_SPACE))
info.displayColorSpace =
info.renderingColorSpace;
if (data->GetBool(ID_OVERWRITE_OCIO_VIEW_TRANSFORM))
info.viewColorSpace =
info.renderingColorSpace;
}
RENDERRESULT OcioAwareRenderer::Execute(BaseVideoPost*
node, VideoPostStruct* vps)
{
{
};
if (!vps || !vps->doc || !vps->doc->GetDataInstance() || !vps->render)
if (vps->thread && vps->thread->TestBreak())
if (!rgbaBuffer)
if (rgbaBuffer->GetBt() != 32)
BaseContainer* nodeData =
node->GetDataInstance();
Vector color = nodeData->GetVector(ID_RENDER_COLOR);
BaseContainer* docData = vps->doc->GetDataInstance();
nodeData->GetBool(ID_PRETRANSFORM_OCIO_OUTPUT))
{
const OcioConverter* converter = OcioConverter::Init(vps->doc)
iferr_return;
if (!converter)
}
const
Int32 height = rgbaBuffer->GetBh();
const
Int32 bytesPerPixel = rgbaBuffer->GetCpp();
{
lineBuffer[ix * bytesPerPixel + 0] = (
Float32)color.x;
lineBuffer[ix * bytesPerPixel + 1] = (
Float32)color.y;
lineBuffer[ix * bytesPerPixel + 2] = (
Float32)color.z;
}
for (
Int32 iy = 0; iy < height; iy++)
rgbaBuffer->SetLine(0, iy,
width, lineBuffer, 32,
false);
}
FRAME
Called when the renderer prepares to render a frame.
Definition: c4d_videopostdata.h:1
for(i=0;i< length;i++)
Definition: unicodeobject.h:61
#define NewMemClear(T, cnt)
Definition: defaultallocator.h:216
USERBREAK
Thread has been canceled.
Definition: ge_prepass.h:4
FAILED
Generic error if a rendering has failed due to missing license or similar.
Definition: ge_prepass.h:8
OUTOFMEMORY
Not enough memory.
Definition: ge_prepass.h:1
COLORSPACETRANSFORMATION
Definition: ge_prepass.h:502
RENDERRESULT
Definition: ge_prepass.h:426
#define VPBUFFER_RGBA
RGB and alpha multipass channel.
Definition: c4d_videopostdata.h:115
maxon::Float32 Float32
Definition: ge_sys_math.h:59
maxon::Int32 Int32
Definition: ge_sys_math.h:51
void DeleteMem(T *&p)
Definition: defaultallocator.h:269
unsigned long Py_ssize_t width
Definition: pycore_traceback.h:88
_Py_clock_info_t * info
Definition: pytime.h:197
#define iferr_scope_handler
Definition: resultbase.h:1414
Initialize Colors of Scene Elements in 2025
[New in 2025.0.0] Demonstrates the changes made to color initiations for scene elements in 2025.0.0.
With release 2025, OCIO has been substantially updated in Cinema 4D, leading to changes for how colors are interpreted in NodeData::Init. All colors are now interpreted as colors in sRGB-2.2 space in NodeData::Init
, specifically when the document is in OCIO mode. This differs from before where colors were interpreted in the document's render space. Other places in code still interpret colors in the document's render space.
This change was necessary because OCIO became the default color management mode in Cinema 4D 2025 and we wanted to preserve the colors defined in legacy code. This example demonstrates how to circumvent this behavior in case one wants to interpret colors in the document's Render space. This example can also be applied to pre-2025 frameworks. Although not necessary there, it will have no negative side effects either.
{
BaseList2D*
const blist =
static_cast<BaseList2D*
>(
node);
BaseContainer* const bc = blist ? blist->GetDataInstance() : nullptr;
if (!bc)
return false;
if (!isCloneInit)
bc->SetVector(OCIO_NODE_2025_COLOR,
Vector(1, 0, 0));
PreloadTextures()
iferr_ignore("this might fail but we cannot do anything about it");
return true;
}
{
BaseBitmap* bmp = MAXON_REMOVE_CONST(_bitmap);
BaseBitmap::Free(bmp);
}
{
BaseBitmap* bmp;
{
if (bmp)
BaseBitmap::Free(bmp);
_bitmap = nullptr;
return err;
};
const maxon::Url assetUrl(
"asset:///file_5b6a5fe03176444c"_s);
if (!asset)
"Could not resolve asset
for '
UV Test Grid.png'."_s);
bmp = BaseBitmap::Alloc();
if (!bmp)
_bitmap = bmp;
}
{
if (!data)
return SUPER::Message(
node,
type, data);
BaseList2D*
const blist =
static_cast<BaseList2D*
>(
node);
BaseContainer* const bc = blist ? blist->GetDataInstance() : nullptr;
if (!bc)
return SUPER::Message(
node,
type, data);
{
bc->SetVector(OCIO_NODE_2025_COLOR,
Vector(1, 0, 0));
return true;
}
return SUPER::Message(
node,
type, data);
}
Represents a C4DAtom that resides in a 4D list.
Definition: c4d_baselist.h:1990
static MAXON_METHOD Bool WaitForDatabaseLoading()
static MAXON_METHOD Result< AssetDescription > ResolveAsset(const Url &url, const AssetRepositoryRef &repository)
Py_ssize_t PyObject * from
Definition: unicodeobject.h:502
Vec3< Float, 1 > Vector
Definition: vector.h:56
#define MSG_MENUPREPARE
Allows tags, objects, shaders etc. to do some setup work when called from the menu....
Definition: c4d_baselist.h:417
UV
UV Options.
Definition: lib_activeobjectmanager.h:18
Definition: autoweight.h:11
maxon::Bool Bool
Definition: ge_sys_math.h:46
Url GetAssetUrl(const DndAsset &asset)
PyObject ** type
Definition: pycore_pyerrors.h:34
#define iferr_ignore(...)
Definition: resultbase.h:1496
Drawing with OCIO Colors in a Viewport
[New in 2025.0.0] Demonstrates how to draw into a viewport when OCIO color management is enabled in a document.
With 2025 it has become more important to correctly draw colors in the viewport when OCIO is enabled. This example demonstrates how to draw colors using the flag SET_PEN_USE_PROFILE_COLOR
in a BaseDraw
instance. And the special case of drawing colors from the settings of a Cinema 4D instance such as the world axis colors.
ocio_node_2025