如何使用用于 iPhone 开发的 OpenGL ES 渲染 3D 对象(顶点和法线存储在头文件中)?

Posted

技术标签:

【中文标题】如何使用用于 iPhone 开发的 OpenGL ES 渲染 3D 对象(顶点和法线存储在头文件中)?【英文标题】:How do you render a 3D object (where the vertices and normals are stored in a header file) using OpenGL ES for iPhone development? 【发布时间】:2013-12-06 19:28:09 【问题描述】:

我使用搅拌机创建了一个简单的 3D 立方体对象,并使用 Jeff Lamarche 的搅拌机导出将其存储在头文件中并将其添加到我的项目中。但是我无法渲染它。

头文件:

//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);

这是我正在使用的代码:

//
//  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

非常感谢任何帮助。此外,任何关于 OpenGL ES 的教程都会很棒。 提前致谢

【问题讨论】:

【参考方案1】:

从 Blender 获得顶点和法线数据是不够的,您还需要投影和模型视图矩阵以及相机和灯光位置。更好的方法是导出到包含该文件的文件格式,例如 Collada 或 POD(如果您想保持简单)。 PowerVR SDK 包括从 Blender 导出的工具,甚至包括解析 POD 的基本游戏引擎。您还可以通过这种方式获得纹理坐标和动画。在这里查看我的第一篇文章:

http://montgomery1.com/opengl/

【讨论】:

以上是关于如何使用用于 iPhone 开发的 OpenGL ES 渲染 3D 对象(顶点和法线存储在头文件中)?的主要内容,如果未能解决你的问题,请参考以下文章

用于 OpenCV 的 Iphone 6 相机校准

OpenGL:切换和反转轴

在哪里可以找到为 iPhone 新手构建简单 OpenGL 应用程序的教程?

在 iPhone 上加载 openGL 游戏的屏幕?

iPhone 上的 OpenGL ES 2.0:无法超过小索引/顶点数

iphone opengl es 2.0,如何使用objective-c类来存储原始数据?