如何使用用于 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 对象(顶点和法线存储在头文件中)?的主要内容,如果未能解决你的问题,请参考以下文章
在哪里可以找到为 iPhone 新手构建简单 OpenGL 应用程序的教程?