Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5413814
  • 博文数量: 763
  • 博客积分: 12108
  • 博客等级: 上将
  • 技术积分: 15717
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-28 21:21
个人简介

业精于勤,荒于嬉

文章分类

全部博文(763)

文章存档

2018年(6)

2017年(15)

2016年(2)

2015年(31)

2014年(14)

2013年(87)

2012年(75)

2011年(94)

2010年(190)

2009年(38)

2008年(183)

2007年(28)

分类: C/C++

2010-01-30 10:23:23

改变loadTexture[]
第一件需要做的是就是改变 loadTexture[]. 基本上,我们可以改变调用如下:

- (void)loadTexture:(NSString *)name intoLocation:(GLuint)location;

向前看。我们改变 loadTexture[] 函数让它知道加载纹理的名词和路径就可以加载纹理. 现在改变 loadTexture[] 函数如下:

- (void)loadTexture:(NSString *)name intoLocation:(GLuint)location {

    CGImageRef textureImage = [UIImage imageNamed:name].CGImage;

不要忘记删除 @”checkerplate.png” 取而带之的是我们的文件名. 删除 glGenTextures() 函数并且改变 glBindTexture() 函数如下:

glBindTexture(GL_TEXTURE_2D, location);

就是这样,现在这个方法更加的有用,我们将调用glGenTextures() 在我们的 initWithCoder[] 函数里。当我们要加载某个纹理的时候,我们就调用 loadTexture[] ,在本教程里,我们将加载6个纹理, 所以在 initWithCoder[] 里调用完 setupView, 我们增加如下的函数:

        [self setupView];
        glGenTextures(6, &textures[0]);
        [self loadTexture:@"bamboo.png" intoLocation:textures[0]];
        [self loadTexture:@"flowers.png" intoLocation:textures[1]];
        [self loadTexture:@"grass.png" intoLocation:textures[2]];
        [self loadTexture:@"lino.png" intoLocation:textures[3]];
        [self loadTexture:@"metal.png" intoLocation:textures[4]];
        [self loadTexture:@"schematic.png" intoLocation:textures[5]];

另外,切换到头文件,改变纹理如下:

GLuint textures[6];

获得渲染
好,回到drawView[]. 删除有关金字塔的所有东西。我们已经不需要再使用它了。删除我们使用的颜色。所以看起来就如下:

    // Our new drawing code goes here
    rota += 0.2;
    
    glPushMatrix();
    {
        glTranslatef(0.0, 0.0, -4.0);        // Change this line
        glRotatef(rota, 1.0, 1.0, 1.0);
        glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
        
        // Draw the front face
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        
        // Draw the top face
        glDrawArrays(GL_TRIANGLE_FAN, 4, 4);
        
        // Draw the rear face
        glDrawArrays(GL_TRIANGLE_FAN, 8, 4);
        
        // Draw the bottom face
        glDrawArrays(GL_TRIANGLE_FAN, 12, 4);
        
        // Draw the left face
        glDrawArrays(GL_TRIANGLE_FAN, 16, 4);
        
        // Draw the right face
        glDrawArrays(GL_TRIANGLE_FAN, 20, 4);
    }
    glPopMatrix();

你可以不需要使用 glPushMatrix() 和 glPopMatrix() .如果你想你的代码100%的优化,就可以删除它。

现在我们已经获得了一些改变,让我们第二次停下来,思考OpenGL的状态。

好了,记得刚才我们加载过纹理,我们可以使用 glBindTexture()来告诉OpenGL我们希望那个纹理工作。所以,再加载完6个纹理以后,OpenGL将默认使用最后一个加载的纹理,如果你点击 “Build and Go”, 你将看到一个只有单一纹理的立方体。

因为我们想每个面都有一个纹理,我们需要告诉OpenGL我们想使用那个纹理来绘制,在我们调用glDrawArrays()之前。所以,我们的纹理代码如下:

    glPushMatrix();
    {
        glTranslatef(0.0, 0.0, -4.0);
        glRotatef(rota, 1.0, 1.0, 1.0);
        glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
        
        // Draw the front face
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        
        // Draw the top face
        glBindTexture(GL_TEXTURE_2D, textures[1]);
        glDrawArrays(GL_TRIANGLE_FAN, 4, 4);
        
        // Draw the rear face
        glBindTexture(GL_TEXTURE_2D, textures[2]);
        glDrawArrays(GL_TRIANGLE_FAN, 8, 4);
        
        // Draw the bottom face
        glBindTexture(GL_TEXTURE_2D, textures[3]);
        glDrawArrays(GL_TRIANGLE_FAN, 12, 4);
        
        // Draw the left face
        glBindTexture(GL_TEXTURE_2D, textures[4]);
        glDrawArrays(GL_TRIANGLE_FAN, 16, 4);
        
        // Draw the right face
        glBindTexture(GL_TEXTURE_2D, textures[5]);
        glDrawArrays(GL_TRIANGLE_FAN, 20, 4);
    }
    glPopMatrix();

点击 “Build and Go”

西蒙iphone-OpenGL ES 教程 -11 - 勇者之尊 - 等待

回答一个问题,那些代码完成了如上的功能。

纹理包装
下一节就是我一直在说的重复和包装纹理。重复纹理只是简单的多次重复相同的纹理。这是非常有用的内容,用较小的纹理组成一面墙。(必须是要整齐的纹理)

我们要做的是绘制我们的立方体的一个面,使用一个纹理重复四次。我要用这个竹子纹理改变正面,你可以做你任意喜欢的一个面。

这非常容易,你还记得OpenGL是如何从图片中抽取像素去渲染对象的吗?它使用了纹理坐标数组,之前我都告诉你,使用0.0-1.0。如果我要使图像出现两次,我之要将1.0改变为2.0,重复的纹理就会出现了。


所以,在我们的纹理数组里,改变如下:

   const GLshort squareTextureCoords[] = {
        // Front face
        0, 2,       // top left
        0, 0,       // bottom left
        2, 0,       // bottom right
        2, 2,       // top right
        
        // Top face
        0, 1,       // top left
        0, 0,       // bottom left
        1, 0,       // bottom right
        1, 1,       // top right

点击 “Build and Go”:

西蒙iphone-OpenGL ES 教程 -11 - 勇者之尊 - 等待

我只是修改了前面,如果你喜欢,你可以把其他面都做修改。

这是OpenGL默认的纹理映射状态,当纹理坐标数组里的值大于1.0的时候。如果你想改变这个状态,你也可以调用 glTexParameterf().比如,你可以改变如下:

        // Draw the front face
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

上面的代码,在加载纹理坐标中数组大于1以后,就会出现如下效果

  
西蒙iphone-OpenGL ES 教程 -11 - 勇者之尊 - 等待


纹理的边缘像素一直延伸到左上角。这就是GL_CLAMP_TO_EDGE.

让我快速解释这两行代码:

   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

我们调用了 glTexParameterf() 当我们加载纹理的时候设置纹理过滤。像一般的OpenGL函数,它具有“双重功能”。有三个参数,但是在OpenGL ES只有两个有效果。第一个参数一般使 GL_TEXTURE_2D ,OpenGL ES 只支持它。

第二个参数是告诉OpenGL什么“变量”是我们要改变的,一般来说,是 GL_TEXTURE_WRAP_x.

这第三个参数就是我们要设置的。

OpenGL 通过设置 “变量” or “设置” GL_TEXTURE_WRAP_S t到GL_CLAMP_TO_EDGE, 我们告诉 OpenGL 不要重复纹理而是延伸s 坐标 (什么是 “s”, 后面会说). 我们也做了相同的t坐标,等下运行下模拟器,看看是什么样的。

这里设置的默认值是 GL_REPEAT.

s t 坐标?
不,不是玩笑。OpenGL在它的纹理中使用了s t 坐标系统。它确实存在,以避免混淆,因为你必须记住我们的纹理并不是真实存在于我们的3d世界,他们只是我们放置到3d世界的某些东西。所以,你可以认为 s 是横向,t 是纵向.但你旋转它的时候,它是不是一样的使用?
阅读(2516) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~