3.2、OpenGLES_Ch3_1示例

纹理涉及很多潜在的复杂选项,但是苹果的GLKit极大地简化了常见纹理的配置。本例是基于第2章的OpenGLES_Ch2_3示例建立的。在OpenGLES_Ch3_1中的一个单独的文件,OpenGLES_Ch3_1ViewController 类的实现文件,包含了对OpenGLES_Ch2_3的所有修改代码。下面的代码块用粗体标识了变化部分。首先,纹理坐标被加人到SceneVertex类型的声明中:


// This data type is used to store information for each vertex

typedef struct {
    GLKVector3 positionCoords;
    GLKVector2 textureCoords;
}
SceneVertex;

紋理坐标定义了几何圏形中的毎个頂点的紋理映射。为例子保存頂点数据的vertices数組初始化了紋理坐示和位置坐标。

/////////////////////////////////////////////
// Define vertex data for a triangle to use in example
static const SceneVertex vertices[] =
{
    {{-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f}},// lower left corner
    {{ 0.5f, -0.5f, 0.0f}, {1.Of, 0.Of}}, // lower right corner
    {{-0.5f,0.5f, 0.of}, {0.of, 1.0f}}, // upper left corner
};

“-viewDidLoad"方法扩展了示例OpenGLES_Ch2_3中的代碣来影呵GLKit提供的GLKTextureLoader炎,这个类用于將一个紋理圏像加載到一个OpenGL ES紋理緩存中。


////////////////////////////////////////////
// called when the view controller's view is loaded
// Perform initialization before the view is asked to draw
- (void)viewDidload
{
    [super viewDidload];
    // Verify the type of view created automatically by the
    //1 Interface Builder storyboard
    GLKview *view = (GLKView *)self.view; 
    NSAssert( [view isKindOfClass:[GLKView class],@"view controller's view is not a GLKView");

    // Create an OpenGL Es 2.0 context and provide it to the
    // view
    view.context = [[AGLKContext alloc] initWithAPI:kBAGLRenderingAPIOpenGLES2];
    // Make the new context current
    [AGLKContext setCurrentContext:view.context];
// Create a base effect that provides standard OpenGL ES 2.0
// shading language programs and set constants to be used for
// all subsequent rendering
    self.baseBffect = [[GLKBaseEffect alloc] init];
    self.baseBffect.useConstantColor = GL_TRUB;
    self.baseEffect.constantColor = GLKVector4Make(
    1.0f// Red ;
    1.0f// Green
    1.0f, // Blue
    1.0f);// Alpha

    // Set the background color stored in the current context
    ((AGLKContext * )view.context).clearcolor = GLKVector4Make(
        0.0f, // Red
        0.0f, // Green
        0.0f, // Blue
        1.0f);// Alpha

    // Create vertex buffer containing vertices to draw
    self.vertexBuffer = [[AGLKVertexAttribArrayBuffer alloc]
        initWithAttribStride:sizeof(SceneVertex)
            number0fVertices:sizeof(vertices) /sizeof(SceneVertex)
                        data:vertices
                        usage:GL_STATIC_DRAW];

    // Setup texture
    CGImageRef imageRef = [[UIImage imageNamed:e"leaves.gif"] CGImage];
    GLKTextureInfo *textureInfo = [GLKTextureLoader
    textureWithCGImage:imageRef
             options:ni1
             error: NULL] ;

    self.baseEffect.texture2d0.name = textureInfo.name;
    self.baseEffect.texture2d0.target = textureInfo.target;
}

CGImageRef是一个在苹果的Core Graphics框架中定义的C数据类型。Core Graphics包含很多强大的2D图像处理和绘制函数。UlImage的“+imageNamed:”方法会返回一个初始化自图形文件的Ullmage实例。很多不同的图像文件格式都支持。命名的图像必须被包含为应用的一部分, 以便“+imageNamed:" 可以找到它。

GLKTextureL oader的“-textureWithCGImage:options:error:" 方法会接受个CGImageRef并创建一个新的包 含CGlmageRef的像素数据的OpenGL ES纹理缓存。这个方法看似强大。接受一个CGlmageRef使得图像数据的源可以是任何Core Graphics支持的形式,从一个电影的单个帧到由一个应用绘制的自定义2D图像,再到一个图像文件的内容。“ options:" 参数接受一个存储了用于指定GLKTextureLoader怎么解析加载的图像数据的键值对的NSDictionary。可用选项之一是指示 GLKTextureLoader为加载的图像生成MIP贴图。

GLKTextureLoader会自动调用glTexParameteriO方法来为创建的纹理缓存设置OpenGL ES取样和循环模式。如果使用了MIP贴图,并且GLTEXTURE_MIN_FILTER被设置成GL_LINEAR_MIPMAP_LINEAR,这会告诉OpenGL ES使用与 被取样的S、T坐标最接近的纹素的线性插值取样两个最合适的MIP贴图图像尺寸(细节级别)。然后,来自MIP贴图的两个样本被线性差值来产生最终的片元颜色。GL_LINEAR_MIPMAP_LINEAR过滤器通常会产生高质量的渲染输出,但是会比其他模式需要更多的GPU计算。如果没有使用MIP贴图,GLKTextureLoader会自动设置GL_TEXTURE_MIN_FILTER 为GL LINEAR。GL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T都会被设置为GL_CLAMP_TO_EDGE。

第2章例子中引人的GLKBaseEffect对象提供了对于使用纹理做渲染的内建的支持。在OpenGL ES纹理缓存被创建以后,这个例子设置baseEffect的texture2d0属性使用一个新的纹理缓存。

GLKTextureInfo类封装了与刚创建的纹理缓存相关的信息,包括它的尺寸以及它是否包含MIP贴图,但是这个例子只需要缓存的OpenGLES标识符、名字和用于纹理的OpenGL ES目标。OpenGL ES上下文会为各种缓存分别保存配置信息。帧缓存会被单独从顶点属性数组缓存或者纹理缓存配置。事实上, OpenGL ES的上下文支持多种纹理缓存。例如,一种纹理缓存会包含普通的2D图像数据,然后另一种会保存一个用于特殊效果的特别形状的图像,这些内容会在第8章中介绍。GLKTextureInfo 的target属性指定被配置的纹理缓存的类型。一些OpenGL ES实现还会为1D和3D纹理保持独立 的纹理缓存目标。


// GLKView delegate method: Called by the view controller's view
// whenever cocoa Touch asks the view controller's view to
// draw itself. (In this case, render into a frame buffer that
// shares memory with a Core Animation Layer)

- (void)glkView:(GLKView * )view drawInRect:(CGRect)rect {
    [self.baseEffect prepareToDraw];
    // Clear back frame buffer ( erase previous drawing )
    [(AGLKContext *)view.context clear:GL_COLOR_BUFFER_BIT];
[self.vertexBuffer prepareToDrawWithAttrib:GLKVertexAttribPosition 
    numberOfCoordinates:3
            attriboffset:offsetof(SceneVertex, positionCoords )
            shouldEnable:YES];

[se1f.vertexBuffer prepareToDrawwithAttrib:GLKVertexAttribTexCoordo
    numberOfCoordinates:2
            attriboffset:offsetof(SceneVertex, textureCoords)
        shouldEnable:YES];

// Draw triangles using the first three vertices in the
// currently bound vertex buffer
[self.vertexBuffer      
    drawArraywithMode:GL_TRIANGLES
    startVertexIndex:0
    numberOfVertices:3];
}

在OpenGLES_Ch2_3例子中创建并在这里重用的AGLKVertexAttribArrayBuffer类隐式地支持每个顶点的属性的任意组合。OpenGLES_Ch3_1ViewController 的 “-glkView:drawInRect:” 方法的实现首先告诉vertexBuffer让OpenGL ES为渲染顶点位置做好准备(就像例子OpenGLES_Ch2_3),然后添加第二个对于“-prepareToDraw-WithAttrib:numberOfCoordinatesattribOffset:shouldEnable:”方法的调用。第二个调用告诉vertexBuffer让OpenGLES为每个顶点的两个纹理坐标的渲染做好准备。编译器会用纹理坐标开始的每个SceneVertex结构体内的内存偏移来代替ANSIC的offsetof()宏。

在一个纹理被赋给baseEffect,同时OpenGLES为使用位置和纹理坐标属性做好准备之后,调用AGLKVertexAttribArrayBuffer的“-draw ArrayWithMode:startVertexIndex: numberOfVertices:”方法来指示OpenGL ES去渲染有纹理的三角形。

例子OpenGLES_Ch3_1 对于“-viewDidUnload”方法的实现与例子OpenGLES_Ch2_3的实现保持不变。

results matching ""

    No results matching ""