Creating and Rendering a Scene - Arnold Developer Guide
This example C++ code uses the Arnold API to create a basic scene containing a sphere, a textured quad mesh, a point light and a camera. It then renders the scene to a user-specified JPEG file on disk.
Source Code
example.cpp
#include <ai.h>
int main()
{
AiBegin();
// create anew universe to create objects in
AtUniverse *universe = AiUniverse();
// start an Arnold session, log to both a file and the console
AtRenderSession *session = AiRenderSession(universe, AI_SESSION_BATCH);
AiMsgSetLogFileName("scene1.log");
AiMsgSetConsoleFlags(universe, AI_LOG_ALL);
AiMsgSetLogFileFlags(universe, AI_LOG_ALL);
// create a sphere geometric primitive
AtNode *sph = AiNode(universe, AtString("sphere"), AtString("mysphere"));
AiNodeSetVec(sph, AtString("center"), 0.0f, 4.0f, 0.0f);
AiNodeSetFlt(sph, AtString("radius"), 4.0f);
// create a polymesh, with UV coordinates
AtNode *mesh = AiNode(universe, AtString("polymesh"), AtString("mymesh"));
AtArray* nsides_array = AiArray(1, 1, AI_TYPE_UINT, 4);
AiNodeSetArray(mesh, AtString("nsides"), nsides_array);
AtArray* vlist_array = AiArray(12, 1, AI_TYPE_FLOAT, -10.f, 0.f, 10.f, 10.f, 0.f, 10.f, -10.f, 0.f, -10.f, 10.f, 0.f, -10.f);
AiNodeSetArray(mesh, AtString("vlist"), vlist_array);
AtArray* vidxs_array = AiArray(4, 1, AI_TYPE_UINT, 0, 1, 3, 2);
AiNodeSetArray(mesh, AtString("vidxs"), vidxs_array);
AtArray* uvlist_array = AiArray(8, 1, AI_TYPE_FLOAT, 0.f, 0.f, 1.f, 0.f, 1.f, 1.f, 0.f, 1.f);
AiNodeSetArray(mesh, AtString("uvlist"), uvlist_array);
AtArray* uvidxs_array = AiArray(4, 1, AI_TYPE_UINT, 0, 1, 2, 3);
AiNodeSetArray(mesh, AtString("uvidxs"), uvidxs_array);
// create a red standard surface shader
AtNode *shader1 = AiNode(universe, AtString("standard_surface"), AtString("myshader1"));
AiNodeSetRGB(shader1, AtString("base_color"), 1.0f, 0.02f, 0.02f);
AiNodeSetFlt(shader1, AtString("specular"), 0.05f);
// create a textured standard surface shader
AtNode *shader2 = AiNode(universe, AtString("standard_surface"), AtString("myshader2"));
AiNodeSetRGB(shader2, AtString("base_color"), 1.0f, 0.0f, 0.0f);
// create an image shader for texture mapping
AtNode *image = AiNode(universe, AtString("image"), AtString("myimage"));
AiNodeSetStr(image, AtString("filename"), AtString("arnold.png"));
AiNodeSetFlt(image, AtString("sscale"), 4.f);
AiNodeSetFlt(image, AtString("tscale"), 4.f);
// link the output of the image shader to the color input of the surface shader
AiNodeLink(image, AtString("base_color"), shader2);
// assign the shaders to the geometric objects
AiNodeSetPtr(sph, AtString("shader"), shader1);
AiNodeSetPtr(mesh, AtString("shader"), shader2);
// create a perspective camera
AtNode *camera = AiNode(universe, AtString("persp_camera"), AtString("mycamera"));
// position the camera (alternatively you can set 'matrix')
AiNodeSetVec(camera, AtString("position"), 0.f, 10.f, 35.f);
AiNodeSetVec(camera, AtString("look_at"), 0.f, 3.f, 0.f);
AiNodeSetFlt(camera, AtString("fov"), 45.f);
// create a point light source
AtNode *light = AiNode(universe, AtString("point_light"), AtString("mylight"));
// position the light (alternatively use 'matrix')
AiNodeSetVec(light, AtString("position"), 15.f, 30.f, 15.f);
AiNodeSetFlt(light, AtString("intensity"), 4500.f); // alternatively, use 'exposure'
AiNodeSetFlt(light, AtString("radius"), 4.f); // for soft shadows
// get the global options node and set some options
AtNode *options = AiUniverseGetOptions(universe);
AiNodeSetInt(options, AtString("AA_samples"), 8);
AiNodeSetInt(options, AtString("xres"), 480);
AiNodeSetInt(options, AtString("yres"), 360);
AiNodeSetInt(options, AtString("GI_diffuse_depth"), 4);
// set the active camera (optional, since there is only one camera)
AiNodeSetPtr(options, AtString("camera"), camera);
// create an output driver node
AtNode *driver = AiNode(universe, AtString("driver_jpeg"), AtString("mydriver"));
AiNodeSetStr(driver, AtString("filename"), AtString("scene1.jpg"));
// create a gaussian filter node
AtNode *filter = AiNode(universe, AtString("gaussian_filter"), AtString("myfilter"));
// assign the driver and filter to the main (beauty) AOV,
// which is called "RGBA" and is of type RGBA
AtArray *outputs_array = AiArrayAllocate(1, 1, AI_TYPE_STRING);
AiArraySetStr(outputs_array, 0, AtString("RGBA RGBA myfilter mydriver"));
AiNodeSetArray(options, AtString("outputs"), outputs_array);
// finally, render the image!
AiRender(session, AI_RENDER_MODE_CAMERA);
// ... or you can write out an .ass file instead
// AtParamValueMap* params = AiParamValueMap();
// AiParamValueMapSetInt(params, AtString("mask"), AI_NODE_ALL);
// AiSceneWrite(universe, "scene1.ass", params);
// AiParamValueMapDestroy(params);
// Arnold session shutdown
AiRenderSessionDestroy(session);
AiUniverseDestroy(universe);
AiEnd();
return 0;
}
Compiling
The following commands compile and run the example on various platforms:
Linux
export ARNOLD_PATH=/path/to/arnold
export LD_LIBRARY_PATH=$ARNOLD_PATH/bin
c++ example.cpp -o example -std=c++11 -Wall -O2 -fPIC -I$ARNOLD_PATH/include -L$ARNOLD_PATH/bin -lai
./example
macOS
export ARNOLD_PATH=/path/to/arnold
export DYLD_LIBRARY_PATH=$ARNOLD_PATH/bin
c++ example.cpp -o example -Wall -O2 -I$ARNOLD_PATH/include -L$ARNOLD_PATH/bin -lai
./example
Windows Visual Studio command prompt
set ARNOLD_PATH=c:/path/to/arnold
set PATH="%ARNOLD_PATH/bin;$PATH"
cl example.cpp /I %ARNOLD_PATH%/include %ARNOLD_PATH%/lib/ai.lib /link /out:example.exe
example
Output
Once rendered, the output should look like this: