4.7. Advanced MBA scene rendering

This tutorial combines:

Open the 10-Advanced MBA Scene Rendering example:

  1. Example 4.52 shows the node traversal function:

    Example 4.52. Traversal function

    ...
    #include <mde/mde.h>
    
    #define TIME_INCREMENT 0.03f
    #define FIXED_FRAMERATE 1
    
    using namespace MDE;
    
    // the function takes as parameters: a node in the asset, the drawing context, a projection_view matrix,
    // a world matrix, and the current time
    void traverse(Tree<NodeAsset*>* node, Context* context, mat4 prjViw, mat4 world, float time)
    {
        if (!node) return;  // no node to draw
        // find the sibling node and recursively traverse it
        traverse(node->getNextSibling(), context, prjViw, world, time);
    
        if (node->data)  // skip if the node does not have any data
        {
            world *= node->data->sampleLocalTransform(time);
            mat4 inv_world;
            world.invert(inv_world);  // create the inverse of the world matrix and invert it
            mat3 tiv3 = inv_world.transposed().toMat3();
            // pass the calculated uniforms to the shaders
            context->setUniformMatrix("TRA_INV_WRL", tiv3);
            context->setUniformMatrix("WORLD", world);
            context->setUniformMatrix("PRJ_VIW_WRL", prjViw*world);
            node->data->setAbsoluteTransform(world);
            
            for (unsigned int i = 0; i < node->data->getBatchCount(); i++)
            {
                Batch b = node->data->getBatch(i);
                if (b.material)  // calculate how the material responds to the light sources
                {
                    // Check for diffuse texture
                    TextureAsset* diffuse = b.material->getMap("diffuse");
                    if (diffuse) 
                    {
                        context->setUniformSampler("TEXTURE_DIFFUSE", diffuse->getTexture());
                    }
    
                    // Check for spec level texture
                    TextureAsset* spec_level = b.material->getMap("spec_level");
                    if(spec_level)
                    {
                        context->setUniformSampler("TEXTURE_SPEC_LEVEL", spec_level->getTexture());
                    }
                    
                    // Check for ambient attribute
                    Attribute* ambient = b.material->getAttribute("ambient");
                    if(ambient)
                    {
                        float values[4];
                        ambient->getValue(time, values);
                        context->setUniform("MATERIAL_AMBIENT", 4, 1, values);
                    }
    
                    // Check for specular attribute
                    Attribute* specular = b.material->getAttribute("specular");
                    if(specular)
                    {
                        float values[4];
                        specular->getValue(time, values);
                        context->setUniform("MATERIAL_SPECULAR", 4, 1, values);
                    }
    
                    // Check for shininess attribute
                    Attribute* shininess = b.material->getAttribute("shininess");
                    if(shininess)
                    {
                        float value;
                        shininess->getValue(time, &value);
                        context->setUniform("MATERIAL_SHININESS", value);
                    }
    
    
                }
                if (b.geometry)
                {
                    // draw the geometry
                    b.geometry->draw();
                }
            }
        }
        // continue traversal over the child nodes
        traverse(node->getFirstChild(), context, prjViw, world, time);
    }
    ...
    

  2. Example 4.53 shows the initialization and loading of the asset files:

    Example 4.53. Creating the context and loading the scene assets

    ...
    int main()
    {
        try
        {
            Managed<System> system = create_system_backend();
            Managed<FileSystem> filesystem = system->createFileSystem("data/");
            Managed<Context> context = system->createContext(320, 240);
            #ifdef MDE_OS_PC_LINUX
                Managed<Keyboard> keyboard = system->createKeyboard(context);
            #else
                Managed<Keyboard> keyboard = system->createKeyboard();
            #endif
            Managed<Timer> timer = system->createTimer();
            Proxy proxy(filesystem, context);
    
            SceneAsset* scene = proxy.getSceneAsset("lightshow2_eksempelscene.MBA");
            Program* program = proxy.getProgramAsset("default.vert;default.frag")->getProgram();
            context->setProgram(program);
    ...
    

  3. Example 4.54 shows the camera and lighting setup:

    Example 4.54. Set the camera and light values

    ...
            //int numCams = scene->getAssetCount(Asset::TYPE_CAMERA);
            int currentCam = 0;
            float camFov = 270.0f;
            float camAspect = 4.0f/3.0f;
            float time = timer->getTime();
    
            vec3 lightPos(0.0f, 0.0f, 0.0f);
            vec3 camTarget(0.0f, 0.0f, 0.0f);    
            vec3 camPos(0.0f, 0.0f, 0.0f);
    
            glEnable(GL_CULL_FACE);
            glCullFace(GL_BACK);
            glEnable(GL_DEPTH_TEST);
    ...
    

  4. Example 4.55 shows the part of the draw loop that manages the camera:

    Example 4.55. Getting the camera asset

    ...
            do
            {
    #if FIXED_FRAMERATE == 1
                time += TIME_INCREMENT;
    #else
                time = timer->getTime();
    #endif
                ::printf("%f\n", time);
                glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    
                // Get camera asset
                CameraAsset* cam = (CameraAsset*)scene->getAsset(Asset::TYPE_CAMERA, currentCam);
                if (cam)
                {
                    // Find nodes in camera:
                    Array<MDE::Tree<MDE::NodeAsset*>*> nodes;
                    scene->findAssetNodes(cam, scene->getTree(0), nodes);
                    
                    // Set camera and target node:
                    NodeAsset* camNode = nodes[0]->data;
                    NodeAsset* targetNode = cam->getTargetNode();
    
                    // Set camera position
                    if(camNode)
                        camPos = camNode->getAbsolutePosition();
                    
                    // Set target node position
                    if(targetNode)
                        camTarget = targetNode->getAbsolutePosition();
                    
                    // Get camera FOV
                    Attribute* fovAttribute = camNode->getCamera(0)->getAttribute("xfov");
                    if(fovAttribute && fovAttribute->getComponentCount() == 1)
                        fovAttribute->getValue(time, &camFov);
    
                    // Get camera aspect
                    Attribute* aspectAttribute = camNode->getCamera(0)->getAttribute("aspect");
                    if(aspectAttribute && aspectAttribute->getComponentCount() == 1)
                        aspectAttribute->getValue(time, &camAspect);
    
                    context->setUniform("CAMERA_POSITION", 3, 1, camPos);
                    // Terminate on pressing key ESCAPE
                    if(keyboard->getSpecialKeyState(Keyboard::KEY_ESCAPE))
                        break;
                }
    ...
    

  5. Example 4.56 shows the part of the draw loop that modifies the lighting:

    Example 4.56. Modifying the lighting

    ...
                // For each light
                for(int i = 0; i < 3; i++)
                {
                    LightAsset* light = (LightAsset*)scene->getAsset(Asset::TYPE_LIGHT, i);
                    if (light)
                    {
                        Array<MDE::Tree<MDE::NodeAsset*>*> nodes;
                        scene->findAssetNodes(light, scene->getTree(0), nodes);
                        
                        NodeAsset* lightNode = nodes[0]->data;
                        if (lightNode)
                        {
                            vec3 lightPos = lightNode->getAbsolutePosition();
                            char buffer[255];
    
                            // Get and set attributes for light:
                            for(unsigned int j = 0; j < light->getAttributeCount(); j++)
                            {
                                // Check for the color attribute
                                Attribute* attr = light->getAttribute(j);
                                if(attr->name == "color")
                                {
                                        float values[3];
                                        attr->getValue(time, values);
                                        sprintf(buffer, "LIGHT_COLOR[%i]", i);
                                        context->setUniform(buffer, 3, 1, values);
                                }
                                // Check for the far attenuation start attribute
                                else if(attr->name == "far_attenuation_start")
                                {
                                        float value;
                                        attr->getValue(time, &value);
                                        sprintf(buffer, "LIGHT_FAR_ATTENUATION_START[%i]", i);
                                        context->setUniform(buffer, value);
                                }
                                // Check for the fat attenuation end attribute
                                else if(attr->name == "far_attenuation_end")
                                {
                                        float value;
                                        attr->getValue(time, &value);
                                        sprintf(buffer, "LIGHT_FAR_ATTENUATION_END[%i]", i);
                                        context->setUniform(buffer, value);
                                }
                            }
                            
                            // Set light position
                            sprintf(buffer, "LIGHT_POSITIONS[%i]", i);
                            context->setUniform(buffer, 3, 1, lightPos.coord);
                        }
                    }
            	}
    ...
    

  6. Example 4.57 shows the world, view, and project calculation and scene traversal:

    Example 4.57. Traversing the scene

    ...
                mat4 world = mat4::identity();
                mat4 view = mat4::lookAt( camPos, camTarget, vec3(0.0f, 0.0f, 1.0f) );
                mat4 proj = mat4::perspective(camFov, camAspect, 1.0f, 1000.0f);
                mat4 prjViw = proj*view;
                //context->setUniformMatrix("WORLD", world);
                //context->setUniformMatrix("PRJ_VIW_WRL", prjViw*world);
                //context->setUniformMatrix("PROJECTION", 4, 1, proj);
    
                traverse(scene->getTree(0), context, prjViw, world, time);        
            }while (context->update());
        }
        catch(Exception& e)
        {
            printf("An exception was thrown:\n%s\n", e.getMessage().getCharString() );
        }
    }
    

  7. Rebuild the project and run it. Figure 4.22 shows the shape:

    Figure 4.22. The advanced mba shape with tree traversal

    The advanced mba shape with tree traversal

    The asset contains:

    • all of the shaders

    • the environment bitmaps

    • the geometry for the central rotating shape

    • the camera path

    • the lighting sources.

    The asset file is organized in nodes. The application calls the traverse() function to calculate the current position and orientation for the central shape and the camera.

Copyright © 2010 ARM. All rights reserved.ARM DUI 0527A‑02a
Non-Confidential - Draft - BetaID070710