【问题标题】:How do I texture map a cube in OpenGL ES?如何在 OpenGL ES 中对立方体进行纹理映射?
【发布时间】:2010-03-03 01:05:01
【问题描述】:

在使纹理贴图在 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

【问题讨论】:

  • 颜色显示正常吗?
  • +1 以获得 Jeff Lamarche 教程的链接。这正是我所需要的。

标签: iphone opengl-es textures


【解决方案1】:

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

我建议简化您正在尝试做的事情。例如:

  • 忘记常规
  • 忘记颜色
  • 忘记索引
  • 创建将顶点绑定到其属性的结构

Jeff 提供了一个有用的 TexturedVertexData3D 结构来执行此操作。如果您不想填写,您不必填写正常部分。

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

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

并使用 glDrawArrays 来绘制你的对象:

glDrawArrays(GL_TRIANGLES, 0, nVertices);

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

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

【讨论】:

  • 好的 --- 很高兴知道。我使用蛮力显式顶点重建了项目,一切运行良好,正如您使用 GLDrawArrays 建议的那样。纹理贴图以一种合理的方式工作,现在我觉得我可以,如你所说,逐步改进工作。
【解决方案2】:

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

需要考虑的是,就目前而言,您的顶点、颜色和法线数组包含 8 个“项目”,但是您的 TexCoord 数组有 36 个“项目”。我很确定当您将glDrawElements 与索引列表一起使用时,它会使用这些索引从所有激活的数组中选择项目。所以你的 TexCoord 数组的最后 28 项永远不会被使用,它们将根据cubeFaces 指定的索引被挑选出来。在您链接的教程中,所有数组中有四个项目,非常适合对象的单个面。

但是,使用 3D 对象的索引时会出现一些问题,因为尽管在立方体中重复使用了多个顶点,但它们的纹理坐标对于它们所使用的不同三角形不一定相同。事实上,它们的法线也不会,因此当涉及到照明对象时,这可能是您的代码的另一个问题。

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

【讨论】:

  • 我得出了类似的结论。当您对顶点数组使用索引时,可能会出现核心问题:我不清楚是否使用相同的索引来获取纹理顶点数组中的值。我找不到任何关于此的文档。我正在考虑现在恢复到基本三角形。我只处理简单的几何图形,因此使用顶点指针数组节省空间可能不值得麻烦。另外:我正在做的事情要求我能够以不同的方式将纹理映射到对象的面:使用三角形可能是做到这一点的唯一方法。
猜你喜欢
  • 1970-01-01
  • 2012-07-28
  • 2016-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-14
  • 1970-01-01
  • 2010-09-19
相关资源
最近更新 更多