如何在OpenGL ES中为立方体贴图?

时间:2010-03-03 01:05:01

标签: iphone opengl-es textures

让纹理贴图在openGL ES(iphone)中工作时遇到很多麻烦。

这就是我所做的:

  • 构建了一个顶点数组
  • 构建了一个面数组,用于引用每个面
  • 的顶点数组的索引
  • 构建了一个颜色数组,因此我可以确定我知道多维数据集上的哪个顶点是哪个。

以下所有Jeff Lamarche's tutorials。获取对象渲染和移动不是问题。

现在我正在尝试获取立方体(实际上是一块瓷砖,Z在X或Y中更窄)以在两个相对的面上粘贴纹理(其他面板可以稍后出现)。我已经能够让一张脸上班,但我在任何其他方面都没有得到可行的结果。

在OpenGL ES中对对象进行纹理贴图的最系统方法是什么,任何人都可以看到我的代码中的错误在哪里?

#import "GLViewController.h"
#import "ConstantsAndMacros.h"
#import "OpenGLCommon.h"
#import "Cube.h"

@implementation GLViewController

@synthesize initDone;
@synthesize tileArray;
@synthesize tileRows;
@synthesize tileCols;
@synthesize cubes;
@synthesize gridOffsetX;
@synthesize gridOffsetY;
@synthesize gridOffsetZ;
@synthesize tileSpacing;

- (void)drawView:(UIView *)theView
{
    static GLfloat rot = 0.0;

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    // This is the same result as using Vertex3D, just faster to type and
    // can be made const this way

    static const Vertex3D vertices[]= {
        {1.0f,  -1.0f,   0.2f},
        {1.0f,  -1.0f,  -0.2f},
        {1.0f,   1.0f,  -0.2f},
        {1.0f,   1.0f,   0.2f},
        {-1.0f, -1.0f,   0.2f},
        {-1.0f, -1.0f,  -0.2f},
        {-1.0f,  1.0f,  -0.2f},
        {-1.0f,  1.0f,   0.2f}
    };  

    static const Color3D colors[] = {
        {1.0, 0.0, 0.0, 20.0},
        {1.0, 1.0, 1.0, 20.0},
        {1.0, 1.0, 1.0, 20.0},
        {0.0, 0.0, 1.0, 20.0},
        {0.0, 1.0, 0.0, 20.0},
        {1.0, 1.0, 1.0, 20.0},
        {1.0, 1.0, 1.0, 20.0},
        {1.0, 1.0, 1.0, 20.0},
    };

    static const GLubyte cubeFaces[] = {
        0, 1, 3,     
        2, 3, 1,   

        0, 3, 4, 
        3, 4, 7,        // first main face

        2, 1, 6,        // second main face
        1, 6, 5,

        5, 6, 7, 
        5, 4, 7,

        7, 6, 3, 
        6, 3, 2,

        4, 0, 5,
        1, 0, 5, 
    };

    static const Vector3D normals[] = {
        {0.200000, -0.400000, 0.000000},
        {0.400000, -0.200000, -0.400000},
        {0.333333, 0.333333, -0.333333},
        {0.400000, 0.400000, -0.200000},
        {-0.333333, -0.333333, 0.333333},
        {-0.400000, -0.400000, -0.200000},
        {-0.200000, 0.400000, -0.400000},
        {-0.400000, 0.200000, 0.000000},
    };

    static const GLfloat texCoords[] = {
        0.0, 0.0,   // texture  face
        1.0, 1.0,
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,


        0.0, 0.0,   // texture  face
        1.0, 1.0,
        1.0, 0.0,
        1.0, 0.0,
        0.0, 1.0,
        1.0, 1.0,

        0.0, 0.0,   // texture  face
        1.0, 1.0,
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,

        0.0, 0.0,   // texture  face
        1.0, 1.0,
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,

        0.0, 0.0,   // texture  face
        1.0, 1.0,
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,

        0.0, 0.0,   // 
        1.0, 1.0,
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0,

    };

      glTexCoordPointer(2, GL_FLOAT, 0, texCoords);


    glLoadIdentity();
    glClearColor(0.7, 0.7, 0.7, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glVertexPointer(3, GL_FLOAT, 0, vertices);
    glColorPointer(4, GL_FLOAT, 0, colors);
    glNormalPointer(GL_FLOAT, 0, normals);
    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);

    NSMutableArray *tempRow;
    Cube *tempCube;
    for (int i = 1; i <= cubes.tileRows; i++)
    {
        tempRow = [cubes rowAtIndex:i-1];
        for (int j = 1; j <= cubes.tileCols; j++)
        {
            tempCube = [tempRow objectAtIndex:j-1];
            glLoadIdentity();
            glTranslatef(gridOffsetX + (tileSpacing * (GLfloat)i), gridOffsetY + (tileSpacing * (GLfloat)j), gridOffsetZ);
            glRotatef(rot, 1.0, 0.0, 0);
            glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, cubeFaces);
        }
    }

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    static NSTimeInterval lastDrawTime;
    if (lastDrawTime)
    {
        NSTimeInterval timeSinceLastDraw = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;
        rot+=30 * timeSinceLastDraw;                
    }
    //NSLog(@"rot is %f", rot);
    lastDrawTime = [NSDate timeIntervalSinceReferenceDate];    
}



-(void)setupView:(GLView*)view
{
    initDone = NO;

    tileRows = 5;
    tileCols = 7;
    gridOffsetX = 5.2f;
    gridOffsetY = 6.9f;
    gridOffsetZ = -14.0;
    tileSpacing = -2.15f;

    cubes = [[Cubes alloc] initWithRowCount:tileRows colCount: tileCols ];

    const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 50.0; 
    GLfloat size; 
    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION); 
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0); 
    CGRect rect = view.bounds; 

//  glOrthof(-5.0,                                          // Left
//           5.0,                                          // Right
//             -5.0 / (rect.size.width / rect.size.height),   // Bottom
//           5.0 / (rect.size.width / rect.size.height),   // Top
//           0.01,                                         // Near
//           10000.0);                                     // Far

    glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / 
               (rect.size.width / rect.size.height), zNear, zFar); 

    glViewport(0, 0, rect.size.width, rect.size.height);  
    glMatrixMode(GL_MODELVIEW);

    glEnable(GL_COLOR_MATERIAL);
    // Enable lighting
    glEnable(GL_LIGHTING);

    // Turn the first light on
    glEnable(GL_LIGHT0);

    // Define the ambient component of the first light
    const GLfloat light0Ambient[] = {0.5, 0.5, 0.5, 1.0};
    glLightfv(GL_LIGHT0, GL_AMBIENT, light0Ambient);

    // Define the diffuse component of the first light
    const GLfloat light0Diffuse[] = {0.7, 0.7, 0.7, 1.0};
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse);

    // Define the specular component and shininess of the first light
    const GLfloat light0Specular[] = {0.7, 0.7, 0.7, 1.0};
    const GLfloat light0Shininess = 0.4;
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0Specular);


    // Define the position of the first light
    const GLfloat light0Position[] = {0.0, 10.0, 10.0, 0.0}; 
    glLightfv(GL_LIGHT0, GL_POSITION, light0Position); 

    // Define a direction vector for the light, this one points right down the Z axis
    const GLfloat light0Direction[] = {0.0, 0.0, -1.0};
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light0Direction);

    // Define a cutoff angle. This defines a 90° field of vision, since the cutoff
    // is number of degrees to each side of an imaginary line drawn from the light's
    // position along the vector supplied in GL_SPOT_DIRECTION above
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);


    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_SRC_COLOR);

    glGenTextures(1, &texture[0]);
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 

    NSString *path = [[NSBundle mainBundle] pathForResource:@"a-tile-64" ofType:@"png"];
    NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
    UIImage *image = [[UIImage alloc] initWithData:texData];
    if (image == nil)
        NSLog(@"Do real error checking here");

    GLuint width = CGImageGetWidth(image.CGImage);
    GLuint height = CGImageGetHeight(image.CGImage);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    void *imageData = malloc( height * width * 4 );
    CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
    CGColorSpaceRelease( colorSpace );
    CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
    CGContextTranslateCTM( context, 0, height - height );
    CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

    CGContextRelease(context);

    free(imageData);
    [image release];
    [texData release];

    glLoadIdentity(); 
};

- (void)dealloc 
{
    [tileArray release];
    [cubes release];

    [super dealloc];
}
@end

2 个答案:

答案 0 :(得分:2)

我还使用Jeff的教程启动了OpenGL ES。

我建议简化你要做的事情。例如:

  • 忘记法线
  • 忘记颜色
  • 忘记指数
  • 创建一个将顶点绑定到其属性的结构

Jeff提供了一个有用的TexturedVertexData3D Struct来实现这一点。如果您不想,您不必填写正常部分。

然后,适当地设置你的步伐:

glVertexPointer(3, GL_FLOAT, sizeof(TexturedVertexData3D), &vertices[0]);
glTexCoordPointer(2, GL_FLOAT, sizeof(TexturedVertexData3D), &vertices[0].texCoords);

使用glDrawArrays绘制对象:

glDrawArrays(GL_TRIANGLES, 0, nVertices);

完成此工作后,继续将法线和颜色添加到TexturedVertexData3D结构中,并相应地设置纹理和颜色指针。然后再次测试,或者如果事情不起作用,则发布更新。

此时您可以开始考虑如何使用索引。在渲染数千个顶点之前,指数才有意义。但是,当时机成熟时,通过使用它们可以获得不错的性能提升。

答案 1 :(得分:0)

我一直在看这个问题,因为我现在正在学习OpenGL,并将继续使用OpenGL ES。由于还没有人回答,我会给你我的想法,不要认为这是专家意见。

需要考虑的是,就像它的立场一样,你的Vertex,Color&amp;普通数组包含8个“项目”,但您的TexCoord数组包含36个“项目”。我很确定当你使用glDrawElements索引列表时,它会使用这些索引从所有激活的数组中选择项目。因此,您的TexCoord数组的最后28项将永远不会被使用,它们将根据cubeFaces指定的索引进行挑选。在您链接的教程中,所有数组中都有四个项目,可以很好地处理对象的单个面。

然而,对于使用3D对象的索引来说这是一个问题,因为尽管在立方体中重复使用了几个顶点,但它们的纹理坐标对于它们所用的不同三角形不一定相同。事实上,它们的法线也不会,因此在点亮对象时,这可能是代码的另一个问题。

我不知道对此最好的解决方案是什么,这就是为什么我对这个问题的任何其他答案感兴趣...按顶点绘制立方体顶点是一个选项。我也想知道是否可以分别绘制立方体的每个面,并且每次都更改TexCoord数组。或者也许有一些更简单或标准的方式来做这种我还不知道的事情!