How do you render a 3D object (where the vertices and normals are stored in a header file) using OpenGL ES for iPhone development?

StackOverflow https://stackoverflow.com/questions/20136016

Question

I created a simple 3D cube object using blender and used Jeff Lamarche's blender export to store it in a header file and added it into my project. However I am having trouble rendering it.

header file:

//If not using MC3D, change 1 to 0 to add needed types
#if 0
    #import "MC3DTypes.h"
#else
    struct texCoord
    {
        GLfloat     u;
        GLfloat     v;
    };
    typedef struct texCoord texCoord;
    typedef texCoord* texCoordPtr;

    typedef struct vec2 vec2;
    typedef vec2* vec2Ptr;

    struct vec3
    {
        GLfloat x;
        GLfloat y;
        GLfloat z;
    };

    typedef struct vec3 vec3;
    typedef vec3* vec3Ptr;

    struct vec4
    {
        GLfloat x;
        GLfloat y;
        GLfloat z;
        GLfloat w;
        };

    typedef struct vec4 vec4;
    typedef vec4* vec4Ptr;

#endif

struct vertexData
{
    vec3        vertex;
    vec3        normal;
};
typedef struct vertexData vertexData;
typedef vertexData* vertexDataPtr;


static const vertexData MeshVertexData[] = {
    {/*v:*/{1.000000, -1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, -0.577349} },
    {/*v:*/{1.000000, -1.000000, 1.000000}, /*n:*/{0.577349, -0.577349, -0.577349} },
    {/*v:*/{-1.000000, -1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, -0.577349} },
    {/*v:*/{1.000000, 1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, 0.577349} },
    {/*v:*/{-1.000000, 1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, 0.577349} },
    {/*v:*/{0.999999, 1.000000, 1.000001}, /*n:*/{0.577349, -0.577349, 0.577349} },
    {/*v:*/{1.000000, -1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, -0.577349} },
    {/*v:*/{1.000000, 1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, 0.577349} },
    {/*v:*/{1.000000, -1.000000, 1.000000}, /*n:*/{0.577349, -0.577349, -0.577349} },
    {/*v:*/{1.000000, -1.000000, 1.000000}, /*n:*/{0.577349, -0.577349, -0.577349} },
    {/*v:*/{0.999999, 1.000000, 1.000001}, /*n:*/{0.577349, -0.577349, 0.577349} },
    {/*v:*/{-1.000000, -1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, -0.577349} },
    {/*v:*/{-1.000000, -1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, -0.577349} },
    {/*v:*/{-1.000000, 1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, 0.577349} },
    {/*v:*/{-1.000000, 1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, 0.577349} },
    {/*v:*/{1.000000, 1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, 0.577349} },
    {/*v:*/{1.000000, -1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, -0.577349} },
    {/*v:*/{-1.000000, 1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, 0.577349} },
    {/*v:*/{-1.000000, -1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, -0.577349} },
    {/*v:*/{1.000000, -1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, -0.577349} },
    {/*v:*/{-1.000000, -1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, -0.577349} },
    {/*v:*/{1.000000, 1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, 0.577349} },
    {/*v:*/{0.999999, 1.000000, 1.000001}, /*n:*/{0.577349, -0.577349, 0.577349} },
    {/*v:*/{1.000000, -1.000000, 1.000000}, /*n:*/{0.577349, -0.577349, -0.577349} },
    {/*v:*/{1.000000, -1.000000, -1.000000}, /*n:*/{0.577349, 0.577349, -0.577349} },
    {/*v:*/{-1.000000, -1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, -0.577349} },
    {/*v:*/{-1.000000, 1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, 0.577349} },
    {/*v:*/{-1.000000, 1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, 0.577349} },
    {/*v:*/{-1.000000, 1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, 0.577349} },
    {/*v:*/{0.999999, 1.000000, 1.000001}, /*n:*/{0.577349, -0.577349, 0.577349} },
    {/*v:*/{-1.000000, -1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, -0.577349} },
    {/*v:*/{-1.000000, -1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, -0.577349} },
    {/*v:*/{-1.000000, 1.000000, -1.000000}, /*n:*/{-0.577349, 0.577349, 0.577349} },
    {/*v:*/{0.999999, 1.000000, 1.000001}, /*n:*/{0.577349, -0.577349, 0.577349} },
    {/*v:*/{-1.000000, 1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, 0.577349} },
    {/*v:*/{-1.000000, -1.000000, 1.000000}, /*n:*/{-0.577349, -0.577349, -0.577349} },
};

// Example OpenGL ES 1.1 Drawing Code:
// glEnableClientState(GL_VERTEX_ARRAY);
// glEnableClientState(GL_NORMAL_ARRAY);
// glVertexPointer(3, GL_FLOAT, sizeof(VertexData3D), &MeshVertexData[0].vertex);
// glNormalPointer(GL_FLOAT, sizeof(VertexData3D), &MeshVertexData[0].normal);
// glDrawArrays(GL_TRIANGLES, 0, kMeshNumberOfVertices);
// glDisableClientState(GL_VERTEX_ARRAY);
// glDisableClientState(GL_NORMAL_ARRAY);

And here is the code I am using:

//
//  ES1Renderer.m
//  glTestingGround
//
//  Created by David Jacobs on 3/8/10.
//  Copyright Stanford University 2010. All rights reserved.
//

#import "ES1Renderer.h"
#import "banana.h"
#import "PVRTexture.h"
#import "cubefr.h"

#define BUFFER_OFFSET(x)((char *)NULL+(x))

@implementation ES1Renderer




// Create an ES 1.1 context
- (id) init
{
    if (self = [super init])
    {
        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];

        if (!context || ![EAGLContext setCurrentContext:context])
        {
            [self release];
            return nil;
        }

        // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
        glGenFramebuffersOES(1, &defaultFramebuffer);
        glGenRenderbuffersOES(1, &colorRenderbuffer);
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);

        glEnable(GL_CULL_FACE);
        glEnable(GL_CCW);


        // ###################### Texture Demo #################################
        /*NSString * path = [[NSBundle mainBundle] pathForResource: @"banana" ofType:@"pvrtc"];
        texture = [[PVRTexture alloc] initWithContentsOfFile:path];

        glBindTexture(GL_TEXTURE_2D, texture.name);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);*/
        // #####################################################################
    }

    return self;
}



- (void) render
{
    // Replace the implementation of this method to do your own custom drawing


    // This application only creates a single context which is already set current at this point.
    // This call is redundant, but needed if dealing with multiple contexts.
    [EAGLContext setCurrentContext:context];    
    // This application only creates a single default framebuffer which is already bound at this point.
    // This call is redundant, but needed if dealing with multiple framebuffers.
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);

        //obj2opengl.pl banana.obj
    //To include the converted object all you have to do is

        // include generated arrays

    // ---------------------------------------------------------------
    // Determines the Normalized Device Coordinate -> Window Coordinate Transform
    // ---------------------------------------------------------------

    glViewport(0, 0, backingWidth, backingHeight);    

    // ---------------------------------------------------------------
    // Determines the Eye Coordinate -> Clip Coordinate Transform
    // ---------------------------------------------------------------

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();   
    glFrustumf(-2, 2, -3, 3, 5, 20);



    // ---------------------------------------------------------------
    // Determines the Object Coordinate -> Eye Coordinate Transform
    // ---------------------------------------------------------------
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity();

    glTranslatef(0, 0, -8);

    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // ####################### Geometry Demo #########################
/*
#define TETRA_FRONT   0.0,    0.0,    1.0
#define TETRA_RIGHT 0.943,    0.0, -0.333
#define TETRA_TOP  -0.471,  0.816, -0.333
#define TETRA_LEFT -0.471, -0.816, -0.333

#define v1 1.000000, -1.000000, -1.000000
#define v2 1.000000, -1.000000, 1.000000
#define v3 -1.000000, -1.000000, 1.000000
#define v4 -1.000000, -1.000000, -1.000000
#define v5 1.000000, 1.000000, -1.000000
#define v6 0.999999, 1.000000, 1.000001
#define v7 -1.000000, 1.000000, 1.000000
#define v8 -1.000000, 1.000000, -1.000000

    static const GLfloat tetraVertices[] = {
        TETRA_TOP,
        TETRA_RIGHT,
        TETRA_LEFT,
        TETRA_FRONT,
        TETRA_TOP,
        TETRA_RIGHT,        
    };
    static const GLfloat newVertices[] = {
        v1,
        v2,
        v3,
        v4,
        v5,
        v6,
        v7,
        v8
    };

#define RED      255,  0,  0,255
#define GREEN      0,255,  0,255
#define BLUE       0,  0,255,255
#define YELLOW   255,255,  0,255

    static const GLubyte tetraColors[] = {
        RED,
        GREEN,
        BLUE,
        YELLOW,
        RED,
        GREEN,      
    };
    static const GLubyte newColors[] = {
        RED,
        RED,
        RED,
        RED,
        RED,
        RED,
        RED,
        RED
    };

    static float t = 0.0;
    t += 1/30.f;
    //glVertexPointer(3, GL_FLOAT, 0, tetraVertices);
    glVertexPointer(3, GL_FLOAT, 0, newVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, newColors);
    //glColorPointer(4, GL_UNSIGNED_BYTE,0, tetraColors);
    glEnableClientState(GL_COLOR_ARRAY);



    glPushMatrix();
    glTranslatef(0, 0, -3);
    glRotatef(30*t, 0, 1, 0);
    glScalef(3, 3, 3);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);  
    glPopMatrix();


    glPushMatrix();
    glTranslatef(2, 2, 0);  
    glRotatef(-30*t, 1, 0, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);  
    glPopMatrix();

    glPushMatrix();
    glTranslatef(2, -2, 0); 
    glRotatef(-60*t, 1, 0, 1);
    glScalef(2, 2, 2);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);  
    glPopMatrix();
     */

    //glDisableClientState(GL_VERTEX_ARRAY);
    //glDisableClientState(GL_NORMAL_ARRAY);

    // set input data to arrays
    //glVertexPointer(3, GL_FLOAT, 0, MeshVertexData);
    //glEnableClientState(GL_VERTEX_ARRAY);

    //glNormalPointer(GL_FLOAT, 0,indexes);
    //glEnableClientState(GL_NORMAL_ARRAY);

    //glTexCoordPointer(2, GL_FLOAT, 0, bananaTexCoords);
    //glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    //glEnable(GL_TEXTURE_2D);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glVertexPointer(3, GL_FLOAT, sizeof(MeshVertexData), &MeshVertexData[0].vertex);
    glNormalPointer(GL_FLOAT, sizeof(MeshVertexData), &MeshVertexData[0].normal);
   //glTexCoordPointer(2, GL_FLOAT, sizeof(TexturedVertexData3D), &VertexData[0].texCoord);


    static float t = 0.0;
    t += 1/30.f;

    glPushMatrix();
    glTranslatef(0, 0, 0);
    glRotatef(30*t, 0, 1, 0);
    glScalef(1, 1, 1);
    //glDrawArrays(GL_TRIANGLES, 0, vertex_count);
    glDrawArrays(GL_TRIANGLES, 0, sizeof(&MeshVertexData[0].vertex));
    glPopMatrix();

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glLoadIdentity();
    //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    //glDisable(GL_TEXTURE_2D);

    // ###############################################################
    // Enable lighting

    // This application only creates a single color renderbuffer which is already bound at this point.
    // This call is redundant, but needed if dealing with multiple renderbuffers.
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer
{   
    // Allocate color buffer backing based on the current layer size
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer];
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);


    if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
    {
        NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
        return NO;
    }

    return YES;
}

- (void) dealloc
{
    // Tear down GL
    if (defaultFramebuffer)
    {
        glDeleteFramebuffersOES(1, &defaultFramebuffer);
        defaultFramebuffer = 0;
    }

    if (colorRenderbuffer)
    {
        glDeleteRenderbuffersOES(1, &colorRenderbuffer);
        colorRenderbuffer = 0;
    }

    // Tear down context
    if ([EAGLContext currentContext] == context)
        [EAGLContext setCurrentContext:nil];

    [context release];
    context = nil;

    [super dealloc];
}

@end

Any help is greatly appreciated. Also any tutorials on OpenGL ES would be great. Thanks in advance

Was it helpful?

Solution

It's not enough to have the vertex and normal data from Blender, you need the projection and model-view matrices and camera and light positions too. A better approach is to export to a file format that includes that, such as Collada, or POD (if you want to keep it simple). The PowerVR SDK includes tools to export from Blender and even a basic game engine that will parse POD. You also get texture coordinates and animations this way. Check out my first article here:

http://montgomery1.com/opengl/
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top