您的位置:首页 > 移动开发 > IOS开发

iOS OpenGL ES2.0教程   Lesson03 旋转

2012-06-01 14:17 337 查看
iOS OpenGL ES2.0教程 Lesson03 旋转

注:可供翻译的课程只有前两课。从这节课起,我试着根据我对OpenGL ES的理解写接下去的课程,希望能和大家一起学习。

在上节课中,我们绘制了一个三角形。在这一课里,我们学习如何旋转。我们创建一个正方形,并让它沿Y轴旋转。

绘制一个长方形

首先,我们要在屏幕上绘制一个长方形,如下图所示:





要注意的是,在用OpenGL ES绘制图形的时候,是不能直接绘制矩形或其他多边形的,只能绘制三角形。所以,我们这里需要将通过绘制两个三角形来得到一个长方形。在图中分别绘制由顶点(0, 1, 2)和顶点(2, 3, 0)构成的三角形。

如果我们用上节课所使用的方法,每个三角形需要指定3个顶点的信息,那么两个三角形则需要指定6个顶点。这6个顶点中有重复的数据,实际上只需要指定4个不同的顶点就可以了。我们可以用新的方法来实现这个功能。在文件Lesson03.mm中:

//---------------------------------------------------
//create a rectangle
std::vector<float> geometryData;

//vertex 0, left/buttom
geometryData.push_back(-0.5); geometryData.push_back(-0.5); geometryData.push_back(0.0); geometryData.push_back(1.0);

// 1, right/buttom
geometryData.push_back(0.5); geometryData.push_back(-0.5); geometryData.push_back(0.0); geometryData.push_back(1.0);

// 2, right/ups
geometryData.push_back(0.5); geometryData.push_back(0.5); geometryData.push_back(0.0); geometryData.push_back(1.0);

// 3, left/up
geometryData.push_back(-0.5); geometryData.push_back(0.5); geometryData.push_back(0.0); geometryData.push_back(1.0);

//generate an ID for our geometry buffer in the video memory and make it the active one
glGenBuffers(1, &m_geometryBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_geometryBuffer);

//send the data to the video memory
glBufferData(GL_ARRAY_BUFFER, geometryData.size() * sizeof(float), &geometryData[0], GL_STATIC_DRAW);


指定4个顶点的数据,顶点按照添加的顺序,其索引值分别为0, 1, 2, 3。然后将顶点数据传送给OpenGL,和上一课用的方法一样。屏幕显示范围是从(-1, 1),中心点位置是(0, 0),所以 (0.5,0.5)指的是右上1/4屏幕的中间,其他点以此类推。

//create a color buffer, to make our triangle look pretty
std::vector<float> colorData;

//3 floats define one color value (red, green and blue) with 0 no intensity and 1 full intensity
//each color triplet is assigned to the vertex at the same position in the buffer, so first color -> first vertex

//vertex 0 is red
colorData.push_back(1.0); colorData.push_back(0.0); colorData.push_back(0.0);
// 1 is blue
colorData.push_back(0.0); colorData.push_back(0.0); colorData.push_back(1.0);
// 2 is green
colorData.push_back(0.0); colorData.push_back(1.0); colorData.push_back(0.0);
// 3 is blue
colorData.push_back(0.0); colorData.push_back(0.0); colorData.push_back(1.0);

//generate an ID for the color buffer in the video memory and make it the active one
glGenBuffers(1, &m_colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
//send the data to the video memory
glBufferData(GL_ARRAY_BUFFER, colorData.size() * sizeof(float), &colorData[0], GL_STATIC_DRAW);


指定4个顶点的颜色,并将数据传递到VBO中。

//create vertex indices
std::vector<GLubyte> indexData;

//3 byte define 1 triangle
indexData.push_back(0); indexData.push_back(1); indexData.push_back(2);
indexData.push_back(2); indexData.push_back(3); indexData.push_back(0);

m_indexNumber = indexData.size();

//generate an ID for the index buffer in video memory
glGenBuffers(1, &m_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
//send data to video memory
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData.size() * sizeof(GLubyte), &indexData[0], GL_STATIC_DRAW);


要注意这里新添加的内容。新创建一个数组indexData, 保存的是组成每个三角形的顶点的索引。比如第一个三角形由顶点0,1,2组成,第二个三角形由
顶点2,3,1组成,注意顶点的指定顺序要按照逆时针次序。定义了一个变量m_indexNumber,用来保存绘制图形一共需要使用的元素的数目。
然后在图像内存中生产一个缓冲区,绑定这个缓冲区。这里用的是GL_ELEMENT_ARRAY_BUFFER,表示之后用glDrawELements绘制图元的时候,会到这个缓冲区来
获得顶点的索引值。

//initiate the drawing process, we want a triangle, start at index 0 and draw 3 vertices
glDrawArrays(GL_TRIANGLES, 0, 3);

//initiate the drawing process
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
glDrawElements(GL_TRIANGLES, m_indexNumber, GL_UNSIGNED_BYTE, 0);


在draw()方法中,我们不再使用前一课用的glDrawArray()方法,而是调用glDrawElement()方法,从索引数据来绘制图元。
函数需要四个参数:第一个参数是要绘制的图元,我们这里画的是三角形,选择GL_TRIANGLES。第二个参数是要绘制的元素的数目,即是索引数组的元素数目,
这里我们用m_indexNumber。第三个参数是索引数组中元素的类型。最后一个参数是指向索引数组的指针。因为我们之前已经把索引数组传送到OpenGL的
GL_ELEMENT_ARRAY_BUFFER缓冲区里去了,所以这里我们直接用0。

编译运行程序,长方形就显示出来了。





旋转

下面,我们要让这个长方形沿X轴正方向移动0.5,然后沿Y轴旋转。

首先,看shader.vert文件:

// modelview
uniform mat4 modelview;

//the shader entry point is the main method
void main()
{
colorVarying = color; //save the color for the fragment shader

gl_Position = modelview * position; //copy the position
}


我们增加了一个变量modelview,是一个4*4的矩阵。限定符uniform表示这个变量是从应用程序传递给着色器的,并且在绘制图元时保持为常量。
现在gl_Position的值是变换矩阵modelview乘给定的顶点位置。

注:关于这部分使用到的向量和矩阵库,来源于raywenderrlich写的OpenGL ES2.0 iphone开发指引,最初来源于Cocos3d框架。( http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial)
在Lesson03.h中,增加一个变量m_modelview,保存着色器程序中uniform变量modelview的位置。

//modelview uniform in the shader
int m_modelview;


Lesson03.mm:
//get the attachment points for modelview
m_modelview = glGetUniformLocation(m_shader->getProgram(), "modelview");
//check
if (m_modelview < 0) {
NSLog(@"Could not query uniform location");
}


调用glGetUniformLoaction函数,将着色器程序和变量的名字传给函数,函数会返回该变量的位置。这个值我们保存起来,之后要用到。

再来看draw()函数,增加了如下代码:

//modelview

CC3GLMatrix *mvMatrix = [CC3GLMatrix matrix];
[mvMatrix populateFromTranslation:CC3VectorMake(0.2, 0 , 0)];

m_currentRotation += 1.0;
[mvMatrix rotateBy:CC3VectorMake(0, m_currentRotation, 0)];

glUniformMatrix4fv(m_modelview, 1, 0, mvMatrix.glMatrix);


首先,创建一个CC3GLMatrix的实例对象。关于CC3GLMatrix类,我也不是太熟悉,现在我们只要知道它有一个property成员 glMatrix,glMatrix表示的是一个4*4的浮点数矩阵数组。
然后,populateFromTranslation函数给glMatrix矩阵提供位置移动的数据,参数为指定的向量vector(x, y, z),表示在x, y, z轴上移动的距离。这样得到的矩阵glMatrix就可以通过矩阵乘法移动指定顶点的位置了。在这里,表示向x轴正方向移动0.5,其他两个方向不动。
rotateBy函数提供在x, y, z轴上的旋转数据。我们设定的值是,只沿y轴旋转,旋转角度为m_currentRotation,每次调用draw()函数,旋转角度增加1度。
最后glUniformMatrix4fv函数用我们得到的变换矩阵来更新着色器程序里的uniform变量矩阵modelview。第一个参数是要修改的uniform变量的索引位置,第二个参数是要修改的矩阵数据,这里是1个。第三个参数是第四个参数是按行主序还是列主序指定的,这里我们用GL_FALSE(0),表明是列主序指定的。最后一个参数是我们前面设定的变换矩阵。

现在,编译并运行程序,我们就可以在屏幕上看到程序运行的结果了。长方形沿x轴正方向移动了0.2,并且沿Y轴旋转。附件是教程的工程文件。

还有一个问题,旋转角度在180-360度之间时,看不到我们的长方形了。那是因为在那个范围里时,按照我们顶点的指定顺序,这两个三角形的顶点都是按顺时针方向指定的,OpenGL认为这个面是背向我们的,就没有让它显示了。下一课,我们把它改造成3D的。

本文出自 “周晶的博客” 博客,请务必保留此出处http://jimmyzhouj.blog.51cto.com/2317513/884763
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: