Main and make

In order to build a final program we must define a main function, which is the entry point for the operating system when loading the program. The main program will setup the renderer and initialize the shader system.
Create a file called main.cpp and enter the following code in you favourite text editor:

#include "vrenderer.h"
#include "integrator.h"

using namespace OSL;

static ShadingSystem *shadingsys = NULL;
static VRenderer rend;
static ErrorHandler errhandler;

static const float xres = 256;
static const float yres = 256;

void setup_shaderglobals(ShaderGlobals &sg,
                         ShadingSystem *shadingsys,
                         int x, int y);

int main(int argc, char *argv[])
{
    shadingsys = ShadingSystem::create(&rend, NULL, &errhandler);
    shadingsys->attribute("lockgeom", 1);

    shadingsys->ShaderGroupBegin();
    //shadingsys->Parameter("paramname", TypeDesc paramtype, void *value);
    shadingsys->Shader("surface", argv[1], NULL);
    shadingsys->ShaderGroupEnd();

    ShadingAttribStateRef shaderstate = shadingsys->state();

    // Create shading context
    PerThreadInfo *threadinfo = shadingsys->create_thread_info();
    ShadingContext *ctx = shadingsys->get_context(threadinfo);

    // Setup global input variables to shader
    ShaderGlobals shaderglobals;
    setup_shaderglobals(shaderglobals, shadingsys, 0, 0);

    // Execute shader
    if (shadingsys->execute(*ctx, *shaderstate, shaderglobals))
    {
        std::cout << "Shader executed successfully" << std::endl;
    }
    else
    {
        std::cout << "Shader failed to execute" << std::endl;
    }

    return 0;
}

The next thing to do is to create a helper function that sets-up the ShaderGlobals object. This data structure contains all the global variables accessible from the open shading language program.

void setup_shaderglobals(ShaderGlobals &sg,
                         ShadingSystem *shadingsys,
                         int x, int y)
{
    memset(&sg, 0, sizeof(ShaderGlobals));

    sg.u = (float) (x + 0.5f) / xres;
    sg.v = (float) (y + 0.5f) / yres;
    sg.dudx = 1.0f / xres;
    sg.dvdy = 1.0f / yres;

    sg.P = Vec3(sg.u, sg.v, 1.0f);

    sg.dPdx = Vec3(sg.dudx, sg.dudy, 0.0f);
    sg.dPdy = Vec3(sg.dvdx, sg.dudy, 0.0f);
    sg.dPdz = Vec3(0.0f, 0.0f, 0.0f);

    sg.dPdu = Vec3(1.0f, 0.0f, 0.0f);
    sg.dPdu = Vec3(0.0f, 1.0f, 0.0f);

    sg.N = Vec3(0, 0, 1);
    sg.Ng = Vec3(0, 0, 1);

    sg.surfacearea = 1;
}

Of course the values defined here is not meaningfull, in the final rendering systems these variables would be set up by the ray tracer. But we need something to start working with…

The last thing we need to do is to edit the file CMakeLists.txt, which we copied in the first step in the tutorial. Edit the file so it looks like this:

# The 'vtrace' executable
SET ( vtrace_srcs vrenderer.cpp integrator.cpp )
ADD_EXECUTABLE ( vtrace ${vtrace_srcs} main.cpp )
LINK_ILMBASE ( vtrace )
TARGET_LINK_LIBRARIES ( vtrace oslexec oslcomp oslquery ${OPENIMAGEIO_LIBRARY} ${Boost_LIBRARIES} ${CMAKE_DL_LIBS})
INSTALL ( TARGETS vtrace RUNTIME DESTINATION bin )

Now we are ready to build the first test program. Change working directory to the project root, and make the program:
# cd ../../
# make

Also compile a test shader:
# oslc src/shaders/matte.osl

If everyting went according to plan, you can now run the program on the compiles test shader:
# dist/linux/bin/vtrace src/shaders/matte

Initialize VRenderer
Shader executed successfully

Congratulations you have executed your first shader program…

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License