注册 登录
主题 : 西蒙iphone-OpenGL ES 教程-07
级别: 侠客

UID: 1030
精华: 1
发帖: 52
可可豆: 1420 CB
威望: 1420 点
在线时间: 476(时)
注册时间: 2008-10-14
最后登录: 2016-07-21
0 楼:  发表于: 2009-08-06 09:35    发自: Web Page
来源于 3D图形 分类

西蒙iphone-OpenGL ES 教程-07   

OpenGL ES 07 – 对物体进行独立的转换









起初,我想下一章介绍光照的,但是我又想到别的。我们依然有很多基本对象及转换没有完成,特别是我们在不同的坐标系中对不同的物体进行转换。

记得我们如何在整个屏幕内使用 glTranslatef() 和 glRotatef ()?如果我想作一些不同的事情,我就会使用一个很方便的函数: glLoadIdentity().但是 glLoadIdentity()是“代价昂贵”在屏幕渲染技术中,所以现在,我会采用更有效的方法。

要作到这点,我将介绍一个新的对象。我们将增加一个金字塔,并且使用 glTranslatef()来移动它,使用 glRotatef()来旋转它。和立方体独立开,并且不使用 glLoadIdentity() 来重置矩阵。

在我们的世界里增加一个金字塔
这不是仅仅增加一个三角形,让我们坚持使用3d物体,我们会增加一个金字塔(想像一下Giza平原上的大石头)

有件事,我在以前的教程中避免去说明的,就是我们创建的立方体事一个复杂对象,即物体是由一个以上的原点组成的。从技术上来说,我们的矩形也是一个复杂物体,但我们只使用了单一的OpenGL的函数去绘制它,我们可以将其看为一个简单物体,我避免说明复杂物体是因为我不想让我们的工作看起来是一个“艰苦的工作”

现在你已经完成了一个复杂物体了。恭喜你!并且,现在是时候建立第二个了。

金字塔不是难事。它是由一个矩形以及会聚到这个矩形上面的中心点的4个三角形组成的。一旦你将物体可以分解为你所认知的简单图元,任何复杂的物体都不是问题。唯一的变化是你物体中图元的数目而已。

好,开启Xcode并且开启上个教程的工程。这次不要删除任何东西,我们增加代码来构成一个平行线。

为了帮助你组成金字塔,我们需要分解它的各个组成部分,让我们开始:

    const GLfloat pyramidVertices[] = {
        // Our pyramid consists of 4 triangles and a square base.
        // We'll start with the square base
        -1.0, -1.0, 1.0,            // front left of base
        1.0, -1.0, 1.0,             // front right of base
        1.0, -1.0, -1.0,            // rear left of base
        -1.0, -1.0, -1.0,           // rear right of base

因此,我们创建了一个新的物体,和我们作的一样。这个矩形是底座,所有的y坐标都是-1.0。

现在,我们可以创建金字塔的正面,这次我们创建的三角形而不是矩形。

        // Front face
        -1.0, -1.0, 1.0,            // bottom left of triangle
        1.0, -1.0, 1.0,             // bottom right
        0.0, 1.0, 0.0,              // top centre -- all triangle vertices
                                    //     will meet here

这是我们创建的唯一的真实三角形,这个三角形的角在矩形的前边,然后向后倾斜,上面的点在矩形的中心上面(在x轴线上)

我们继续创建其他的三个三角形,使用相同的方法,下面是完整的顶点数组。


// Our new object definition code goes here
    const GLfloat pyramidVertices[] = {
        // Our pyramid consists of 4 triangles and a square base.
        // We'll start with the square base
        -1.0, -1.0, 1.0,            // front left of base
        1.0, -1.0, 1.0,             // front right of base
        1.0, -1.0, -1.0,            // rear left of base
        -1.0, -1.0, -1.0,           // rear right of base
        
        // Front face
        -1.0, -1.0, 1.0,            // bottom left of triangle
        1.0, -1.0, 1.0,             // bottom right
        0.0, 1.0, 0.0,              // top centre -- all triangle vertices
                                    //     will meet here
        
        // Rear face
        1.0, -1.0, -1.0,   // bottom right (when viewed through front face)
        -1.0, -1.0, -1.0,           // bottom left
        0.0, 1.0, 0.0,              // top centre
        
        // left face
        -1.0, -1.0, -1.0,           // bottom rear
        -1.0, -1.0, 1.0,            // bottom front
        0.0, 1.0, 0.0,              // top centre
        
        // right face
        1.0, -1.0, 1.0,             // bottom front
        1.0, -1.0, -1.0,            // bottom rear
        0.0, 1.0, 0.0               // top centre
    };


增加金字塔的定义到 drawView 方法里和 cubeVerticies[] 的定义在一起。

在我们继续前,我想先说明下金字塔的定义。

首先,这是第一个我们同时提供了三角形及矩形的对象。这个金字塔是由一个矩形和4个三角形组成的。因为我们调用glDrawArrays()为每个单独的图元,但这不防碍我们每次使用单独的定义来绘制不同的图元。那么,当我们绘制金字塔,一切都变的清楚了。

第2,再一次的提醒。我已指定所有的顶点是逆时针的。即使后面看起来似乎是顺时针的,但是从OpenGL的角度看,它还是逆时针的。

其实,我想在我3d图形教学结束前,我们会一直讨论这个问题。

绘制金字塔
现在低头去找立方体的代码。首先,删除glLoadIdentity() 这行,它已经不需要了。

在rota+=0.5以后,我们增加绘制金字塔的代码。现在,我们要在不影响立方体的情况下,使用glTranslatef() 去移动金字塔,并且使用 glRotatef() 去旋转金字塔。为了做到这点,我们需要在不影响其他图元的情况下使用 glTranslatef() 和 glRotatef().

OpenGL 为我们使用这两个函数提供了快捷的方法。

    glPushMatrix();

    // Translation and drawing code goes here....

    glPopMatrix();

OpenGL 告诉我们如果要将我们的矩阵变换放如到堆栈中就要使用 glPushMatrix().我将我们的pyramidVertices[] 和 cubeVertices[] 目标 “推” 到 OpenGL’s 的堆栈中.

Note: 如果你不明白我说的堆栈是什么意思,那么你可能需要一本c或者object c 的工具书。

所以,我们的数据复制是安全的,我们可以象其他OpenGL大师一样进行转换了。让我们开始绘制这个金字塔吧!

    glPushMatrix();
    {
        glTranslatef(-2.0, 0.0, -8.0);
        glRotatef(rota, 1.0, 0.0, 0.0);
        glVertexPointer(3, GL_FLOAT, 0, pyramidVertices);
        glEnableClientState(GL_VERTEX_ARRAY);

首先要指出的是, glPushMatrix()后面的那个{.这个不是必要的,但是你在学习的时候最好加上它,{}内表示了被推入堆栈和弹出堆栈之间做的工作。

在 glPushMatrix() 后面的四行,我马上解释给你听. 所有我们所做的就是要求glTranslatef ( )把金字塔远离( 0 , 0 , 0 )的左侧和回8点到屏幕(进一步远离观众) 。那么我们的金字塔周围旋转的X轴,而不是所有三个轴计算的立方体的例子在过去的教程。最后,我们只要告诉OpenGL的有关数据,并使它能够被使用。

好了,在我们做好坐标转换以后,我们开始绘制金字塔。

        // Draw the pyramid
        // Draw the base -- it's a square remember
        glColor4f(1.0, 0.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

前四个坐标表示了我们金字塔的底部。我们将它的颜色设置为红色(也可以进行纹理映射),并且使用 GL_TRIANGLE_FAN 来绘制矩形。我们是从(pyramidVerticies[0~3]),使用4个的顶点。

Ok,我们完成矩形了,现在开始绘制第一个正面的三角形。

        // Front Face
        glColor4f(0.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 4, 3);

除里改变颜色,我们改变绘制模式为 GL_TRIANGLES的原因是显然的,我们已经从数组的第4个(pyramidVerticies[4~6])开始,延伸3个顶点来绘制。所以,你可以看到,一个矩形和一个三角形可以很容易的共存于一个数据结构里。

下一步,我们继续绘制我们其他三个三角形:

        // Rear Face
        glColor4f(0.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 7, 3);
        
        // Right Face
        glColor4f(1.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 10, 3);
        
        // Left Face
        glColor4f(1.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 13, 3);
    }
    glPopMatrix();

每次,我们只是改变颜色,并改变开始的偏移值。OpenGL知道每个顶点是由三个坐标组成的,通过我们的 glVertexPointer() 函数。

最后,我们关闭},并且调用 glPopMatrix().

现在,在这点上我们可以绘制立方体。但是,请注意,你可以一遍又一遍的重复绘制,只需要将绘制函数放在 glPushMatrix() 和 glPopMatrix()中间.

绘制立方体-修订
这里是绘制立方体的完整代码。最大的改变就是代码头尾的函数 glPushMatrix() 和 glPopMatrix()



    glPushMatrix();
    {
        glTranslatef(2.0, 0.0, -8.0);
        glRotatef(rota, 1.0, 1.0, 1.0);
        glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
        
        // Draw the front face in Red
        glColor4f(1.0, 0.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        
        // Draw the top face in green
        glColor4f(0.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 4, 4);
        
        // Draw the rear face in Blue
        glColor4f(0.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 8, 4);
        
        // Draw the bottom face
        glColor4f(1.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 12, 4);
        
        // Draw the left face
        glColor4f(0.0, 1.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 16, 4);
        
        // Draw the right face
        glColor4f(1.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 20, 4);
    }
    glPopMatrix();

其他的变化只有 glTranslatef 的参数。
这里是完整的drawView函数。


- (void)drawView {
    
    // Our new object definition code goes here
    const GLfloat pyramidVertices[] = {
        // Our pyramid consists of 4 triangles and a square base.
        // We'll start with the square base
        -1.0, -1.0, 1.0,            // front left of base
        1.0, -1.0, 1.0,             // front right of base
        1.0, -1.0, -1.0,            // rear left of base
        -1.0, -1.0, -1.0,           // rear right of base
        
        // Front face
        -1.0, -1.0, 1.0,            // bottom left of triangle
        1.0, -1.0, 1.0,             // bottom right
        0.0, 1.0, 0.0,              // top centre -- all triangle vertices
                                    //     will meet here
        
        // Rear face
        1.0, -1.0, -1.0,     // bottom right (when viewed through front face)
        -1.0, -1.0, -1.0,           // bottom left
        0.0, 1.0, 0.0,              // top centre
        
        // left face
        -1.0, -1.0, -1.0,           // bottom rear
        -1.0, -1.0, 1.0,            // bottom front
        0.0, 1.0, 0.0,              // top centre
        
        // right face
        1.0, -1.0, 1.0,             // bottom front
        1.0, -1.0, -1.0,            // bottom rear
        0.0, 1.0, 0.0               // top centre
    };
    
    const GLfloat cubeVertices[] = {
        
        // Define the front face
        -1.0, 1.0, 1.0,             // top left
        -1.0, -1.0, 1.0,            // bottom left
        1.0, -1.0, 1.0,             // bottom right
        1.0, 1.0, 1.0,              // top right
        
        // Top face
        -1.0, 1.0, -1.0,            // top left (at rear)
        -1.0, 1.0, 1.0,             // bottom left (at front)
        1.0, 1.0, 1.0,              // bottom right (at front)
        1.0, 1.0, -1.0,             // top right (at rear)
        
        // Rear face
        1.0, 1.0, -1.0,             // top right (when viewed from front)
        1.0, -1.0, -1.0,            // bottom right
        -1.0, -1.0, -1.0,           // bottom left
        -1.0, 1.0, -1.0,            // top left
        
        // bottom face
        -1.0, -1.0, 1.0,
        -1.0, -1.0, -1.0,
        1.0, -1.0, -1.0,
        1.0, -1.0, 1.0,
        
        // left face
        -1.0, 1.0, -1.0,
        -1.0, 1.0, 1.0,
        -1.0, -1.0, 1.0,
        -1.0, -1.0, -1.0,
        
        // right face
        1.0, 1.0, 1.0,
        1.0, 1.0, -1.0,
        1.0, -1.0, -1.0,
        1.0, -1.0, 1.0
    };
    
    const GLshort squareTextureCoords[] = {
        // Front face
        0, 1,       // top left
        0, 0,       // bottom left
        1, 0,       // bottom right
        1, 1,       // top right
        
        // Top face
        0, 1,       // top left
        0, 0,       // bottom left
        1, 0,       // bottom right
        1, 1,       // top right
        
        // Rear face
        0, 1,       // top left
        0, 0,       // bottom left
        1, 0,       // bottom right
        1, 1,       // top right
        
        // Bottom face
        0, 1,       // top left
        0, 0,       // bottom left
        1, 0,       // bottom right
        1, 1,       // top right
        
        // Left face
        0, 1,       // top left
        0, 0,       // bottom left
        1, 0,       // bottom right
        1, 1,       // top right
        
        // Right face
        0, 1,       // top left
        0, 0,       // bottom left
        1, 0,       // bottom right
        1, 1,       // top right
    };
    
    [EAGLContext setCurrentContext:context];    
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glViewport(0, 0, backingWidth, backingHeight);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glMatrixMode(GL_MODELVIEW);
    
    glTexCoordPointer(2, GL_SHORT, 0, squareTextureCoords);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
    // Our new drawing code goes here
    rota += 0.5;
    
    glPushMatrix();
    {
        glTranslatef(-2.0, 0.0, -8.0);
        glRotatef(rota, 1.0, 0.0, 0.0);
        glVertexPointer(3, GL_FLOAT, 0, pyramidVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
        
        // Draw the pyramid
        // Draw the base -- it's a square remember
        glColor4f(1.0, 0.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        
        // Front Face
        glColor4f(0.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 4, 3);
        
        // Rear Face
        glColor4f(0.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 7, 3);
        
        // Right Face
        glColor4f(1.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 10, 3);
        
        // Left Face
        glColor4f(1.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLES, 13, 3);
    }
    glPopMatrix();
    
    glPushMatrix();
    {
        glTranslatef(2.0, 0.0, -8.0);
        glRotatef(rota, 1.0, 1.0, 1.0);
        glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
        
        // Draw the front face in Red
        glColor4f(1.0, 0.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        
        // Draw the top face in green
        glColor4f(0.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 4, 4);
        
        // Draw the rear face in Blue
        glColor4f(0.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 8, 4);
        
        // Draw the bottom face
        glColor4f(1.0, 1.0, 0.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 12, 4);
        
        // Draw the left face
        glColor4f(0.0, 1.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 16, 4);
        
        // Draw the right face
        glColor4f(1.0, 0.0, 1.0, 1.0);
        glDrawArrays(GL_TRIANGLE_FAN, 20, 4);
    }
    glPopMatrix();
    
    
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
    
    [self checkGLError:NO];
}



请注意,我们并没有为金字塔添加一个新的纹理坐标数组。我们可以使用相同的坐标数组,因为它依然为这个范例工作。

改变好了以后,点击”Build an Go”




你所有需要主要的是,这两个物体正在独立的改变自己。金字塔只沿x轴旋转,而立方体沿3轴旋转。再次说明,颜色只是让你更容易的分辨每个面。

采用3d概念:法线
记不记得我早些时候说过,要保证每个三角形都是逆时针的,即使有些背面的三角形从正面看起来象是顺时针的?

恩,这是因为你要保证你每个面的数据都是“标准”的。简单的说,一个面的法线是一个假想的线从物体的面抽出。为了说明这点,请看下面的图:




在上面的图片里,这个三角形的法线就是一条从面出来的线。当前的三角形的法线表示,这个三角形的3个顶点是逆时针的。我会在介绍光照的那章里说明什么是法线。

(在这里我真的要说说,我真的很佩服这教程的原作者,他居然可以将如此简单的代码说的如此的复杂,请注意,我没有一点的贬义,而是对他非常的敬佩。明明每个教程只有几行代码,他确不怕麻烦的一次又一次的说明其中的概念,解释每一行代码的表面意思和内部的概念。这样细致的工作打个比方来说,就是一个博士生在细心的教幼儿园小朋友唱歌。不是一般人可以做到的。比我们所阅读到的其他OpenGL书籍更加的认真,也更加的细致。这也是我继续翻译下去的主要动力。)

原文地址:
http://web.me.com/smaurice/AppleCoder/iPhone_OpenGL/Entries/2009/4/3_OpenGL_ES_07_-_Translating_Objects_Independently.html

清空我的评分动态本帖最近评分记录: 共可可豆条评分记录
gagaga 贡献值 +5 2008-09-19
隐藏评分记录
级别: 圣骑士

UID: 1168
精华: 0
发帖: 45
可可豆: 5710 CB
威望: 5710 点
在线时间: 5230(时)
注册时间: 2008-10-30
最后登录: 2016-10-18
1 楼:  发表于: 2009-08-06 11:05    发自: Web Page
感谢,支持,建议放wiki一份。
级别: 圣骑士
状态: 连续签到 - [171天]
UID: 7132
精华: 0
发帖: 100
可可豆: 8521 CB
威望: 8150 点
在线时间: 942(时)
注册时间: 2009-07-19
最后登录: 2017-05-30
2 楼:  发表于: 2009-08-08 10:42    发自: Web Page
学习中,强烈支持7
有人说人生最大的幸福是:睡觉睡到自然醒,数钱数到手抽筋。其实我认为最大的幸福是:无论几点睡觉最后一眼看到的是心爱的人,无论几点醒来第一眼看到的是心爱的人。无论赚多少钱,都是和心爱的人一起赚,如论花多少钱,都是和心爱的人一起花。
级别: 新手上路
UID: 7718
精华: 0
发帖: 12
可可豆: 536 CB
威望: 536 点
在线时间: 71(时)
注册时间: 2009-08-10
最后登录: 2015-04-02
3 楼:  发表于: 2009-08-12 14:07    发自: Web Page
支持了,我还以为是楼主写的教程
做游戏应该以销量为目标
级别: 侠客
UID: 5950
精华: 0
发帖: 10
可可豆: 1750 CB
威望: 1750 点
在线时间: 213(时)
注册时间: 2009-05-24
最后登录: 2016-03-25
4 楼:  发表于: 2009-08-18 15:42    发自: Web Page
除了20章了,强顶,楼主辛苦了
级别: 圣骑士
UID: 13184
精华: 0
发帖: 577
可可豆: 2034 CB
威望: 2034 点
在线时间: 428(时)
注册时间: 2010-01-20
最后登录: 2014-08-03
5 楼:  发表于: 2010-04-16 13:49    发自: Web Page
非常好~~~
Never drop yourself in darkness.
级别: 精灵王
UID: 13726
精华: 0
发帖: 465
可可豆: 4721 CB
威望: 4721 点
在线时间: 615(时)
注册时间: 2010-02-03
最后登录: 2014-10-07
6 楼:  发表于: 2010-07-01 09:17    发自: Web Page
老外写的东西就是好啊~
级别: 禁止发言

状态: 连续签到 - [3天]
UID: 42990
精华: 0
发帖: 1729
可可豆: 13269 CB
威望: 13206 点
在线时间: 1968(时)
注册时间: 2010-12-16
最后登录: 2017-12-07
7 楼:  发表于: 2011-03-11 11:16    发自: Web Page
用户被禁言,该主题自动屏蔽!
级别: 新手上路
UID: 53922
精华: 0
发帖: 20
可可豆: 164 CB
威望: 164 点
在线时间: 170(时)
注册时间: 2011-02-28
最后登录: 2016-06-28
8 楼:  发表于: 2011-03-16 15:56    发自: Web Page
很不错, 感觉金字塔底面坐标不是逆时针,不知道正确与否,望指正!
级别: 骑士
UID: 60761
精华: 0
发帖: 252
可可豆: 1860 CB
威望: 1840 点
在线时间: 308(时)
注册时间: 2011-03-31
最后登录: 2015-07-13
9 楼:  发表于: 2011-05-04 10:30    发自: Web Page
开始晕了,开始进步了。
描述
快速回复

关注本帖(如果有新回复会站内信通知您)

发帖、回帖都会得到可观的积分奖励。查看论坛积分规则

按"Ctrl+Enter"直接提交
    顶部