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

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

西蒙iphone-OpenGL ES 教程-06   

OpenGL ES 06 – 3D坐标里的物体





到目前为止,我们已经对2d物体做了很好的说明。现在是开始创建3d物体的时候了。虽然我们不需要太多的改变,它们需要更多的顶点(如果你创建并使用顶点数组)或者更多的坐标转换,如果你想使用多个平面来创建一个立方体。

也许我该先介绍点和线,但是至今我们已经介绍了一些纹理映射矩形及彩色的三角形,我们不必要去研究那些不够有趣的形状!

另外,我们需要回头去看坐标转换,并且介绍关于旋转的更多细节。并且初学者的东西我不需要在解释。那么,这所有的一切都意味着,我还有更多的教程都没有写。

首先, 贯穿 drawView 函数
对我们艰难的代码工作说88吧。是时候让drawView函数回到最基本的状态了。

将 drawView 函数做成如下:


- (void)drawView {

// Our new object definition code goes here

    [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);

// Our new drawing code goes here

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
    [self checkGLError:NO];
}

你应该感谢我之前为3d空间做的一切,因为我们不需要对深度缓冲做解释或者增加许多新的代码了。这些你已经非常熟悉了。

定义一个3d物体
我们将产生一个立方体,因为它们构件很容易,是很常见的3d图形,并且看起来很cool的3d旋转及纹理映射。在我们绘制一个3d立方体之前,我们需要知道3d立方体是由6个我们一直在使用的矩形组成的。这很容易,但我将会把你以前的定义都打破。让我们先来定义正面。

    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)
        
请注意,我绘制顶面的方向和我绘制正面的方向不是一样的。(正面是逆时针,而顶面不是)但是我在同一地点开始绘制?如果我们将立方体沿x轴旋转90度,那么第一个点在左上,跟下来是右上?

接下来,后面:

        // 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,            // Bottom left front
        1.0, -1.0, 1.0,             // right front
        1.0, -1.0, -1.0,            // right rear
        -1.0, -1.0, -1.0,           // left rear

逆可以看到,我用同样的方法和起点。在你的头脑里面想像如何旋转这些面,看到点排列的方式。

最后,我们完成左面和右面:

           // Left face
        -1.0, 1.0, -1.0,            // top left
        -1.0, 1.0, 1.0,             // top right
        -1.0, -1.0, 1.0,            // bottom right
        -1.0, -1.0, -1.0,           // bottom left
        
        // Right face
        1.0, 1.0, 1.0,              // top left
        1.0, 1.0, -1.0,             // top right
        1.0, -1.0, -1.0,            // right
        1.0, -1.0, 1.0              // left

这里是立方体的完整定义:


   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
    };   


如果你对坐标系统有问题,你最好在你的脑海里去想像它。如果你的思维还停留在2d平面上,那你真的要努力了,我们已经开始3d了。

将 cubeVertices 放到 drawView 函数,并且说明 “New object definition goes here”.

OK, 现在我们要开始绘制这个棒棒糖(不是翻译错误)。

绘制立方体
最简单的办法就是你用你以前看过的代码直接去绘制立方体。不过现在,我们要使用一些先进的(你理解了,它就很简单)的方法来绘制3d物体。然而,现在,让我来介绍如何在3d中绘制图形。

我们开始的代码不需要在解释了。在我们的注释之下,添加如下代码:
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -6.0);
    glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
    glEnableClientState(GL_VERTEX_ARRAY);

这里没有任*****的代码。我们在开始的重置了我们的矩阵,移动我们的立方体到屏幕里以让我们可以看到,告诉OpenGL将要使用的顶点数组的格式及数据存储位置。

后面的代码几乎和你之前用过的相同:

// Draw the front face in Red
glColor4f(1.0, 0.0, 0.0, 1.0);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

这里没有新的代码,我们告诉OpenGL将红色作为绘制颜色,提取从0开始的4个顶点来绘制一个矩形。现在,用我们数组里面的下4个顶点来绘制顶面。

// Draw the top face in green
glColor4f(0.0, 1.0, 0.0, 1.0);
glDrawArrays(GL_TRIANGLE_FAN, 4, 4);

看看这里的 glDrawArrays()函数. 如果你还记得我对你描述过的,我说,第二个参数是数据开始的偏移。是的,因为我们是绘制立方体的第二个面,我们需要告诉OpenGL从要偏移4个值(也就是 cubeVertices[4], 0-3是第一个面),然后我们用之后的4个顶点来绘制。(老外的教程说的真仔细,我看过3d很多本书了,这是第一次了解第二个参数的意义)

现在,我们来绘制后面:

    // Draw the rear face in Blue
    glColor4f(0.0, 0.0, 1.0, 1.0);
    glDrawArrays(GL_TRIANGLE_FAN, 8, 4);

同样的定义,我们从 cubeVertices[8]开始绘制. 用同样的方法来绘制其他三个面:

    // 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);

我们改变了每个面的颜色,并且为 glDrawArrays ()改变了偏移值。

现在,如果你点击了“Build and Go”,你只会得到一个红色的矩形。为了看到所有的6个面,让我们来一起旋转三个轴。

在 glLoadIdentity()之前,添加下面的代码。

        rota += 0.5;

我们的老朋友rota先生回来了。(这作者在搞笑,不太高明)。现在我们需要其他的老朋友 glRotatef() 。在 glTranslatef()函数之后,添加下面:

        glRotatef(rota, 1.0, 1.0, 1.0);

以前,我们只需要使用 glRotatef() 来旋转一个轴,现在我们需要三轴同时旋转。

现在我们点击 “Build and Go” 来看看你得到的:


欢迎你,3d物体。

如何对它进行纹理映射?
我认为,我们现在需要的不只是一个纯色的物体的。让我们使用上个教程里的纹理来纹理映射六个面来使得这个立方体更加的精彩。

好了,我们保持我们工程里面的纹理加载函数。我们只需要修改我们的drawView函数。现在,我带你们去看看如何一次性的快速纹理映射。

首先,你还记得这个吗,在上个教程里的

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

恩,我们可以很容易的纹理映射一个面。我们需要扩充它。然而,这是很容易的。想起来我在确定立方体的各个面是如何使用一样的排列方式的吗?(顺时针规范顶点)现在我们来找到这是为什么。

当OpenGL绘制一个纹理到立方体的一个面的时候,因为我们绘制每个面的时候都使用了偏移(4,8,或者12),纹理映射的时候也会采用相同的偏移。所以,为了纹理映射六个面,我们需要重复之前的4个坐标5遍。



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
    };


数据的剪切和粘贴工作完成了!

现在,我们只需要使用几行代码来纹理映射我们的立方体。

在绘制第一个面之前,添加下面代码:

    glTexCoordPointer(2, GL_SHORT, 0, squareTextureCoords);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

这是很简单,别删除颜色处理那段。看看新的生成结果;



嘿,这就象魔法一样。一个纹理映射过的3d物体在3d空间中旋转。

在纹理映射图片中的一个概念
在上个教程里,我忘记了说明这个概念了。虽然我建议你使用自己的纹理来进行纹理映射,但是纹理的尺寸必须是2的 幂数。图片的宽和高必须是  1, 2, 4, ... 32, ... 512, 1024.这个宽和高不相同也可以,但必须是2的 幂数。所以32 x 512同64 x 64一样是正确的尺寸。而30 x 30不是。

glRotatef()和你物体顶点的一个概念

同样,我鼓励你创建你自己的物体。你有没有注意到,我一直把0,0,0作为我三角形,矩形及立方体的中心?这是因为当我们旋转的时候,OpenGL将会以0,0,0作为模型矩阵的中心。它不会调整自己的模型到0,0,0在旋转。如果你的物体不是以0,0,0为中心来创建的,你旋转的时候就知道什么叫“lop-sided”.

原文地址:
http://web.me.com/smaurice/AppleCoder/iPhone_OpenGL/Entries/2009/4/1_OpenGL_ES_06_-_Objects_in_3D.html
[ 此帖被ally1981在2009-08-06 09:40重新编辑 ]

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

UID: 5709
精华: 2
发帖: 41
可可豆: 4125 CB
威望: 4125 点
在线时间: 1297(时)
注册时间: 2009-05-15
最后登录: 2016-10-23
1 楼:  发表于: 2009-08-06 10:12    发自: Web Page
我也在看这个系列,LZ翻译的挺快啊
级别: 圣骑士
状态: 连续签到 - [171天]
UID: 7132
精华: 0
发帖: 100
可可豆: 8521 CB
威望: 8150 点
在线时间: 942(时)
注册时间: 2009-07-19
最后登录: 2017-05-30
2 楼:  发表于: 2009-08-08 10:42    发自: Web Page
学习中,强烈支持6
有人说人生最大的幸福是:睡觉睡到自然醒,数钱数到手抽筋。其实我认为最大的幸福是:无论几点睡觉最后一眼看到的是心爱的人,无论几点醒来第一眼看到的是心爱的人。无论赚多少钱,都是和心爱的人一起赚,如论花多少钱,都是和心爱的人一起花。
级别: 新手上路
UID: 3635
精华: 0
发帖: 4
可可豆: 110 CB
威望: 110 点
在线时间: 27(时)
注册时间: 2009-03-24
最后登录: 2010-01-29
3 楼:  发表于: 2009-08-19 23:50    发自: Web Page
Good! 学习中
级别: 新手上路
状态: 连续签到 - [31天]
UID: 7917
精华: 0
发帖: 21
可可豆: 813 CB
威望: 730 点
在线时间: 281(时)
注册时间: 2009-08-19
最后登录: 2017-10-12
4 楼:  发表于: 2009-09-05 14:42    发自: Web Page
好东西啊。。。。


https://itunes.apple.com/cn/app/108she-qu/id824097171?mt=8
级别: 精灵王
UID: 13726
精华: 0
发帖: 465
可可豆: 4721 CB
威望: 4721 点
在线时间: 615(时)
注册时间: 2010-02-03
最后登录: 2014-10-07
5 楼:  发表于: 2010-02-26 15:02    发自: Web Page
顶下,学习了±
级别: 圣骑士
UID: 13184
精华: 0
发帖: 577
可可豆: 2034 CB
威望: 2034 点
在线时间: 428(时)
注册时间: 2010-01-20
最后登录: 2014-08-03
6 楼:  发表于: 2010-04-16 11:58    发自: Web Page
好教材,頂!
Never drop yourself in darkness.
级别: 圣骑士
UID: 13184
精华: 0
发帖: 577
可可豆: 2034 CB
威望: 2034 点
在线时间: 428(时)
注册时间: 2010-01-20
最后登录: 2014-08-03
7 楼:  发表于: 2010-04-16 12:01    发自: Web Page
修正:
glRotatef(rota, 1.0, 1.0, 1.0); 要放在glTranslatef(0.0, 0.0, -6.0);之後。
Never drop yourself in darkness.
级别: 新手上路
UID: 21164
精华: 0
发帖: 1
可可豆: 10 CB
威望: 10 点
在线时间: 17(时)
注册时间: 2010-06-03
最后登录: 2010-07-23
8 楼:  发表于: 2010-07-23 16:49    发自: Web Page
我的iphone模拟器是3.0的,
// Draw the front face in Red ,红色的正面
glColor4f(1.0, 0.0, 0.0, 1.0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

// Draw the rear face in Blue,蓝色的背面
glColor4f(0.0, 0.0, 1.0, 1.0);
glDrawArrays(GL_TRIANGLE_FAN, 8, 4);
如果画立方体各面的顺序为:
正面-》顶面-》背面-》底面-》左面-》右面
则正面的红色看不到,无论怎么glRotatef怎么旋转也看不到

背面-》顶面-》正面-》底面-》左面-》右面
则背面的蓝色看不到,无论怎么glRotatef怎么旋转也看不到
级别: 侠客
UID: 9754
精华: 0
发帖: 84
可可豆: 822 CB
威望: 822 点
在线时间: 1038(时)
注册时间: 2009-10-14
最后登录: 2016-09-01
9 楼:  发表于: 2010-09-11 07:30    发自: Web Page
强烈支持楼主,正在努力学习中!
描述
快速回复

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

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

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