Adding an OpenGL ES view to your project using NinevehGL

September 7th, 2012 Posted by: - posted under:Tutorials

Recently I came across an openGL ES 2.0 engine that made setup, displaying and animating of 3D objects a breeze, called NinevehGL.  This 3D engine has many great features including a full multithreading environment, to keep the main run loop free during object rendering,  motion tweening, object groupings, custom lighting, materials and textures, custom shader support,  and native support for augmented reality, just to name a few. Another major benefit is the ability to import both wavefront (.obj) and Collada (.dae) files. This framework is very easy to use, powerful,  and can be utilized in many different ways.

IOS openGL rotating Earth using NinevehGL from Erick Bennett on Vimeo.

In this tutorial I am going to show you how to easily, and effectively add an openGL ES 2.0 3D view into your project, and display a fully rendered, rotating 3D earth. The model assets are available here, and include the object and texture. These assets are also available in the project ZIP file, available thru the link at the end of this tutorial.

Download and install the NinevehGL framework.

Since we want to add this view into an existing project and understand how the engine functions, lets create a new single-view project to start. Although NinevehGL can just as easily be setup thru interface builder, we will be adding this view programmatically. For this exercise, it does not matter if you select storyboard or XIB for the new project.

To begin with there are a few frameworks we will need to add. Do this by first selecting your projects main file in the project navigator pane. Make sure your projects target is selected, and under Build Phases click ‘Link Binaries with Libraries’. Use the + at the bottom of this display and add the QuartsCore  and OpenGLES frameworks.

Next, using the ‘Add Other’ button, navigate to your downloaded NinevehGL folder and import the NinevehGL.framework.

Now onto the code…….import NinevehGL into your header (.h) file,

#import <NinevehGL/NinevehGL.h>

add the delegate to your @interface, if this is missing your drawview method will never get called.

@interface ViewController : UIViewController <NGLViewDelegate>;

In order to see what is being rendered we will need an ivar for an NGLCamera, and for our single object, an NGLMesh. The complete code for all of this should look as follows.

#import <UIKit/UIKit.h>
#import <NinevehGL/NinevehGL.h> 

@interface ViewController : UIViewController <NGLViewDelegate> 
{ 
    NGLCamera *_camera; 
    NGLMesh *_mesh; 
}

In your source (.m) file you must initialize your NGLView, set its delgate to self, define a dictionary with a few basic settings, and initialize the mesh and camera. I am doing this in my viewDidLoad method but depending on your needs, this could be done elsewhere.

    
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // Setup our NGLView.
    NGLView *theView = [[NGLView alloc] initWithFrame:CGRectMake(40, 40, 240, 360)];

    // Set its delegate to self so the drawview method is used.
    theView.delegate = self;

    // Add the new view on top of our existing view. 
    [self.view addSubview:theView];

    // The content scale factor is used to increase the resolution to take advantage 
 of retina displays and values range from 1.0 to 2.0. This sets the contentscalefactor 
 to the max screen scale of the device.
    theView.contentScaleFactor = [[UIScreen mainScreen] scale];

    // Setup some initial environment states to be applied to our mesh.
    NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
	kNGLMeshCentralizeYes, kNGLMeshKeyCentralize,
	@"0.3", kNGLMeshKeyNormalize, nil];

    // Initialize the mesh which includes the model file to import (.obj or .dae).
    _mesh = [[NGLMesh alloc] initWithFile:@"earth.obj" settings:settings delegate:nil];

    // Initialize the camera used to render the scene.
    _camera = [[NGLCamera alloc] initWithMeshes:_mesh, nil];

    // If a trasparent background of the NGLView is needed
    //theView.backgroundColor = [UIColor clearColor];
    //nglGlobalColorFormat(NGLColorFormatRGBA);
    //nglGlobalFlush();

    // The following command displays a 3d view status monitor that will show your current frame rate and number of polygons being rendered in the view.
    [[NGLDebug debugMonitor] startWithView:(NGLView *)self.view];
}

You will need to add at least one method to your source (.m) file, this is the drawView loop. This drawView loop is used to generate each frame being displayed (up to 60 per second). This drawloop is where you would affect the mesh to animate movement or create the effects your a looking to display. The  [_camera drawCamera] is needed to commit the changes and render the frame. The method usually ends with this command.

-(void)drawView
{
    // Rotate on Y axis
    _mesh.rotateY += .5;

    // Draw to our camera to display on our view
    [_camera drawCamera];
}

In the above example, the _mesh.rotateY += .5 is used to rotate the mesh .5 degrees each time the frame is rendered.

Now build and run the project and you should see a slowly spinning planet Earth. The NGLView was purposely drawn smaller than the background view in order to show how you could overlay this NGLView over any other normal view to add 3D content. If you want the background of the NGLView to be transparent, set the background color of the view to clear and add the following additional commands. There is also a status monitor that can be run to display frame rates and the number of polygons being rendered for optimization.

// If a trasparent background of the NGLView is needed
 theView.backgroundColor = [UIColor clearColor];
 nglGlobalColorFormat(NGLColorFormatRGBA);
 nglGlobalFlush();

// The following command displays a 3d view status monitor that will show your current frame rate and number of polygons being rendered in the view.
 [[NGLDebug debugMonitor] startWithView:(NGLView *)self.view];

There are many commands you can use to affect your object, it’s movement and how it interacts in it’s 3D environment, here are just a few basic ones. Advanced animation, movement techniques, object hit testing, custom shaders, etc. would be worthy of a separate tutorial. Enjoy.

// rotation
 _mesh.rotateX, rotateY, rotateZ

// scaling
 _mesh.scaleX, scaleY, scaleZ 

// placement
 _mesh.x,y,z 

// offset center of objects rotation
 _mesh.pivot = nglVec3Make(x, y, z)

Assets

Project file