Gabriel at Visgraf/IMPA, Rio de Janeiro, Brasil

Sistemas Gráficos 3D - Project


This page contains project material developed during the 3d graphical systems course at IMPA. The project was developed to run in Apple Xcode platform version 4.6.3 or higher.

        

Screenshots from the app, showing navigation in a scene.



Youtube video showing app running on iPod3.


Objective:

Develop a drawing engine and scenegraph system for use with iphone. The engine should open a custom scenegraph and allow the user to navigate the scene using sensors and touchscreen.

Organization:

The project is divided in 3 parts: scenegraph exporter, drawing engine and interaction.

Scenegraph:

due to prior experience using Autodesk 3DS MAX content creation platform, this was adopted for scene creation and exporting. The user can model the scene using 3D tools and export the the scene using a custom script written for this project. The script is written in MAX Script language and can be executed inside 3DSMAX. The script captures the current scene state and relationship between objects and exports this to a XML file.

The scene graph is organized in the following structure: Models, Lights, Cameras, Groups, Shaders, Textures.

Elements which will be drawn or affect drawing transformations have similar initial tags which define the transform node. Groups only have the transform data, since they exist for organizing the scenegraph. Other elements have specific element information, example: models have shader tags, lighst have multiplier/color and so on... All nodes have the following transform structure:

  • Parent (Name as string, used for scenegraph)
  • ParentType (Can be: Group, Model, Light, Camera)
  • Transform
    • Position (x, y, z) (local position in - parent space)
    • Euler (x, y, z) (local rotation in - parent space)
    • Scale (x, y, z) (local scale in - parent space)
    • AngleAxis (x, y, z, w) (local AxisAngle in - parent space)
    • QuatAngle (x, y, z, w) (local quaternion in - parent space)
  • WorldPosition (x, y, z) (position in - world space)
  • Child: List of all chindren elements (as Strings, - used for scenegraph)

  • Model: Drawable meshes (contains transform matrix, mesh file name and shader name.
  • Light: Light sources (Light intensity, type(spot, omni..) and transform)
  • Camera: Camera Data (fov, transform, far/near clipping)
  • Group: Basic transform nodes (can be used to transform multiple objects simultaneously, also used for hierarchy configuration and drawing order)

Models have an extra export step where geometry information is saved - on seperate xml file which contains :vertices, - normals, UV coordinates.

None Transform binded elements:
  • Shader: Diffuse, Glossiness, other usefull shader properties...
  • Texture: Image filenames used with shaders.

Here is a link to a XML scenegraph and Model files for futher details:   Scene   ||  Model
Here are the respective model files for the example scene: scene.zip
Here is a link to the maxscript exporter code: Exporter

The scene xml file starts at the group named world, once this element is found by the parser all other elements are read in a tree fashion where the world group is the root node.

Drawing:

Drawing is done following the glkit view specifications using the update and draw delegate methods. Drawing command goes through the whole scenegraph starting from the world group node and draws using glDrawElements all drawable models (meshes). Also lights and materials are passed to a simple shader program which is capable of reproducing some graphic effects.

Main delegate draw method

- (void) glkView:(GLKView *)view drawInRect:(CGRect)rect {

   if (self.myScene != nil && self.myScene->loaded && self.myScene->allLightBuffer != nil) {

       if ([[helper3D platformString] isEqualToString:@"Simulator"]) {
          glViewport(0, 0, 320,480);
       } else {
          glViewport(0, 0, 640,960);
       }
       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

       glUseProgram(self.myScene.baseShaderProgram->baseProgramIndex);

       // Lights are the same for all objects...
       glUniform1fv(self.myScene.baseShaderProgram->uniformLights, 40, self.myScene->allLightBuffer); //make sure lights arent nil...!!!
       glEnableClientState(GL_VERTEX_ARRAY);
       [self.myScene drawChildren:nil parentMatrix:GLKMatrix4Identity]; //Draw the whole scene from the world group node...
       glDisableClientState(GL_VERTEX_ARRAY);
    }
}



Model Drawing...

- (void) drawModel:(Node*)n matrix:(GLKMatrix4)pMatrix {

       w3dModel *m = n.drawableContent;
       GLKMatrix3 normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(pMatrix), NULL);
       GLKMatrix4 finalMatrix = GLKMatrix4Multiply(projectionMatrix, pMatrix);

       // Lights are the same for all objects... so look in the gl delegate for light uniform..
       [self drawDiffuseMap:m];

       glEnableVertexAttribArray(0);
       glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, m->smallVList);
       glEnableVertexAttribArray(1);
       glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, m->smallNList);
       glEnableVertexAttribArray(2);
       glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, m->smallUVList);
       glUniformMatrix4fv(self.baseShaderProgram->uniformModelViewM, 1, 0, finalMatrix.m);
       glUniformMatrix3fv(self.baseShaderProgram->uniformNormalM, 1, 0, normalMatrix.m);
       glUniformMatrix4fv(self.baseShaderProgram->uniformModelM, 1, 0, pMatrix.m);
       glUniform1fv(self.baseShaderProgram->uniformMaterial, 4, m.shader->shaderFloatBuffer); //Material properties from the model shader..
       glDrawElements(GL_TRIANGLES, m->nFaces, GL_UNSIGNED_SHORT, m->smallFList);

}


Here is a link to vertex and fragment shader files: Fragment   Vertex

Interaction:

The phone attitude data for camera rotation is retrieved from the CMMotionManager (*motionManager) object. The user touch input is captured by the UIPanGestureRecognizer (*swipe) object.

// Init!
motionManager = [[CMMotionManager alloc] init];
[motionManager startDeviceMotionUpdates];

// Init!
swipe = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleViewsSwipe:)];
[self.view addGestureRecognizer:swipe];

// Handler...
- (void)handleViewsSwipe:(UIPanGestureRecognizer *)recognizer {
dist = [recognizer translationInView:self.view];
GLKVector2 d = GLKVector2Make(dist.x, dist.y);
disLen = GLKVector2Length(d) * 3;
[recognizer setTranslation:CGPointMake(0.0, 0.0) inView:self.view];
}

Project Download:

Download the xcode project here: engine.zip (contains a scene and runs in the simulator)

I´ll post them soon... still wrapping it all up...