iOS OpenGL ES 2.0教程 Lesson04--3D空间
2012-06-04 11:35
591 查看
iOS OpenGL ES 2.0教程 Lesson04--3D空间
IOS Lesson 04 – 3D空间
在这一课里,我们使用三角形创建3D物体。我们将创建一个立方体,并让它旋转起来。
创建一个立方体
要创建一个立方体,需要指定8个顶点,绘画出前/后/左/右/上/下6个面。
首先修改程序Lesson03.mm:
指定8个顶点的坐标。顶点0-3的坐标不变,增加了顶点4-7,其坐标是分别将顶点0-3沿z轴负方向移动1个单位后得到的坐标值。
指定8个顶点的颜色。顶点0-3设定为蓝色,4-7设定为红色。
指定顶点索引数组。因为有6个面要画,需要指定12个三角形的顶点索引。
现在编译程序运行,就可以看到一个立方体在旋转了。
增加投影
现在,我们加入投影变换。投影变换的目的是定义一个视景体(viewing volume)。视景体的作用有两个,一是决定了一个物体是如何映射到屏幕上的(通过定义是投射投影还是正投影)。二是定义了物体的哪些部分会被裁减掉,不在最终的图像上显示。
我们在这里使用了透视投影。它的特点是物体离照相机越远,它在最终图像中看上去就越小。透视投影的视景体就好象是一个金字塔被截去了顶部的一块。越靠近观察点,视景体的截面大小就越小。所以同样大小的物体越靠近观察点,它就能在视景体中占据较大的区域,最终投影就越大。距离观察点越远的物体,最终投影就越小。
位于视景体之外的物体(或者物体的一部分)将会被裁剪掉,不会出现在最终的图像中,这点要特别注意。
增加一个投射投影,修改shader.vert文件:
我们将uniform变量改为 modelviewprojectionMatrix,这个矩阵包括了我们的投影变化和之前的modelview变换。
看Lesson03.mm中的 draw()函数:
首先,创建一个CC3GLMatrix的实例对象mvpMatrix。然后调用函数populateFromFrustum指定透视投影矩阵。函数创建一个平头截体(frustum),它的近侧裁减平面的左下角的坐标为(-1, -1, -2),右上角的坐标为(1, 1, -2)。从观察点到近侧和远侧裁减平面的距离分别是2和7。
然后translateBy设置顶点移动的数据,这里是沿z轴负方向移动5,x,y轴方向不变。目的是为了让整个物体在旋转过程中始终可以保证在视景体的内部,不会有被裁减的部分。
roteteBy函数提供了旋转数据,我们让立方体同时沿x 轴和y轴旋转。
最后,调用glUniformMatrix4vf函数用我们的变换矩阵来修改着色器程序里的uniform变量 modelviewprojectionMatrix的数值。
现在编译并运行程序,会发现旋转的立方体的尺寸变小了。这是因为投射投影的关系,我们将物体沿z轴负方向移动了5,物体现在处于视景体的比较远的位置,最后投影到屏幕上的尺寸就相应的变小了。
增加深度测试
我们先将Lesson03.mm中,init()方法中的函数glEnable(GL_CULL_FACE) 注释掉,然后编译并运行程序,看看会出现什么现象。
你会发现,可以看到立方体里面的面了!
这是因为,执行glEnable(GL_CULL_FACE)的话,OpenGL会根据顶点的指定顺序,将背对我们的表面(即顶点按照顺时针方向指定)裁剪掉,它们不会显示出来。
如果将它注释掉了,不管是正对我们的表面还是背对我们的表面都会显示出来,又因为我们没有做深度测试,就出现了刚刚的现象了。
我们接下来加上深度测试(depth testing)。启动它以后,OpenGL会跟踪在z轴上的像素。深度缓冲区负责记录观察点和占据这个像素的物体间的距离。在整个场景被渲染时,只有没有被其他物体(像素)遮挡的物体(像素)才会被保留,最终被绘制出来。
首先我们看Lesson03AppDelegate.mm函数,允许增加深度缓存
则在EAGLView.mm 的createFramebuffer函数中,下面的代码就被执行:
首先创建了一个depthRenderbuffer,然后将它绑定到GL_RENDERBUFFER。
我们用glRenderbufferStorage来创建并初始化renderbuffer对象的数据存储空间。第一个参数必须是GL_RENDERBUFFER,第二个参数指定了depth renderbuffer的数据格式。后两个参数是depth renderbuffer的宽度和高度,和之前的其他buffer一样。
最后,调用glFramebufferRenderbuffer,将我们创建的depth buffer关联到framebuffer上。
最后,我们回到Lesson03.mm:
在每一帧的开始,都清除深度缓存glClear(GL_DEPTH_BUFFER_BIT),并启用深度测试。
编译并运行程序,看看最后的效果。
附件里有本教程的完整源代码。本文出自 “周晶的博客” 博客,请务必保留此出处http://jimmyzhouj.blog.51cto.com/2317513/886680
IOS Lesson 04 – 3D空间
在这一课里,我们使用三角形创建3D物体。我们将创建一个立方体,并让它旋转起来。
创建一个立方体
要创建一个立方体,需要指定8个顶点,绘画出前/后/左/右/上/下6个面。
首先修改程序Lesson03.mm:
//front //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); //back //vertex 4, left/buttom geometryData.push_back(-0.5); geometryData.push_back(-0.5); geometryData.push_back(-1.0); geometryData.push_back(1.0); // 5, right/buttom geometryData.push_back(0.5); geometryData.push_back(-0.5); geometryData.push_back(-1.0); geometryData.push_back(1.0); // 6, right/ups geometryData.push_back(0.5); geometryData.push_back(0.5); geometryData.push_back(-1.0); geometryData.push_back(1.0); // 7, left/up geometryData.push_back(-0.5); geometryData.push_back(0.5); geometryData.push_back(-1.0); geometryData.push_back(1.0);
指定8个顶点的坐标。顶点0-3的坐标不变,增加了顶点4-7,其坐标是分别将顶点0-3沿z轴负方向移动1个单位后得到的坐标值。
//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 blue colorData.push_back(0.0); colorData.push_back(0.0); colorData.push_back(1.0); // 1 is blue colorData.push_back(0.0); colorData.push_back(0.0); colorData.push_back(1.0); // 2 is blue colorData.push_back(0.0); colorData.push_back(0.0); colorData.push_back(1.0); // 3 is blue colorData.push_back(0.0); colorData.push_back(0.0); colorData.push_back(1.0); //4 is red colorData.push_back(1.0); colorData.push_back(0.0); colorData.push_back(0.0); //5 is red colorData.push_back(1.0); colorData.push_back(0.0); colorData.push_back(0.0); //6 is red colorData.push_back(1.0); colorData.push_back(0.0); colorData.push_back(0.0); //7 is red colorData.push_back(1.0); colorData.push_back(0.0); colorData.push_back(0.0);
指定8个顶点的颜色。顶点0-3设定为蓝色,4-7设定为红色。
//create vertex indices std::vector<GLubyte> indexData; //front indexData.push_back(0); indexData.push_back(1); indexData.push_back(2); indexData.push_back(2); indexData.push_back(3); indexData.push_back(0); //back indexData.push_back(5); indexData.push_back(4); indexData.push_back(6); indexData.push_back(4); indexData.push_back(7); indexData.push_back(6); //top indexData.push_back(3); indexData.push_back(2); indexData.push_back(6); indexData.push_back(3); indexData.push_back(6); indexData.push_back(7); //buttom indexData.push_back(0); indexData.push_back(4); indexData.push_back(5); indexData.push_back(0); indexData.push_back(5); indexData.push_back(1); //left indexData.push_back(0); indexData.push_back(3); indexData.push_back(4); indexData.push_back(4); indexData.push_back(3); indexData.push_back(7); //right indexData.push_back(2); indexData.push_back(1); indexData.push_back(5); indexData.push_back(2); indexData.push_back(5); indexData.push_back(6);
指定顶点索引数组。因为有6个面要画,需要指定12个三角形的顶点索引。
现在编译程序运行,就可以看到一个立方体在旋转了。
增加投影
现在,我们加入投影变换。投影变换的目的是定义一个视景体(viewing volume)。视景体的作用有两个,一是决定了一个物体是如何映射到屏幕上的(通过定义是投射投影还是正投影)。二是定义了物体的哪些部分会被裁减掉,不在最终的图像上显示。
我们在这里使用了透视投影。它的特点是物体离照相机越远,它在最终图像中看上去就越小。透视投影的视景体就好象是一个金字塔被截去了顶部的一块。越靠近观察点,视景体的截面大小就越小。所以同样大小的物体越靠近观察点,它就能在视景体中占据较大的区域,最终投影就越大。距离观察点越远的物体,最终投影就越小。
位于视景体之外的物体(或者物体的一部分)将会被裁剪掉,不会出现在最终的图像中,这点要特别注意。
增加一个投射投影,修改shader.vert文件:
//modelview projection matrix uniform mat4 modelviewprojectionMatrix; //the shader entry point is the main method void main() { colorVarying = color; //save the color for the fragment shader gl_Position = modelviewprojectionMatrix * position; //copy the position }
我们将uniform变量改为 modelviewprojectionMatrix,这个矩阵包括了我们的投影变化和之前的modelview变换。
看Lesson03.mm中的 draw()函数:
//create mvp matrix CC3GLMatrix *mvpMatrix = [CC3GLMatrix matrix]; //use perspective projection [mvpMatrix populateFromFrustumLeft:-1 andRight:1 andBottom:-1 andTop:1 andNear:2 andFar:7]; //translate in z axis for -5 [mvpMatrix translateBy:CC3VectorMake(0, 0, -5)]; // rotate m_currentRotation += 1.0; [mvpMatrix rotateBy:CC3VectorMake(m_currentRotation, m_currentRotation, 0)]; //modify uniform variable glUniformMatrix4fv(m_mvpMatrix, 1, 0, mvpMatrix.glMatrix);
首先,创建一个CC3GLMatrix的实例对象mvpMatrix。然后调用函数populateFromFrustum指定透视投影矩阵。函数创建一个平头截体(frustum),它的近侧裁减平面的左下角的坐标为(-1, -1, -2),右上角的坐标为(1, 1, -2)。从观察点到近侧和远侧裁减平面的距离分别是2和7。
然后translateBy设置顶点移动的数据,这里是沿z轴负方向移动5,x,y轴方向不变。目的是为了让整个物体在旋转过程中始终可以保证在视景体的内部,不会有被裁减的部分。
roteteBy函数提供了旋转数据,我们让立方体同时沿x 轴和y轴旋转。
最后,调用glUniformMatrix4vf函数用我们的变换矩阵来修改着色器程序里的uniform变量 modelviewprojectionMatrix的数值。
现在编译并运行程序,会发现旋转的立方体的尺寸变小了。这是因为投射投影的关系,我们将物体沿z轴负方向移动了5,物体现在处于视景体的比较远的位置,最后投影到屏幕上的尺寸就相应的变小了。
增加深度测试
我们先将Lesson03.mm中,init()方法中的函数glEnable(GL_CULL_FACE) 注释掉,然后编译并运行程序,看看会出现什么现象。
你会发现,可以看到立方体里面的面了!
这是因为,执行glEnable(GL_CULL_FACE)的话,OpenGL会根据顶点的指定顺序,将背对我们的表面(即顶点按照顺时针方向指定)裁剪掉,它们不会显示出来。
如果将它注释掉了,不管是正对我们的表面还是背对我们的表面都会显示出来,又因为我们没有做深度测试,就出现了刚刚的现象了。
我们接下来加上深度测试(depth testing)。启动它以后,OpenGL会跟踪在z轴上的像素。深度缓冲区负责记录观察点和占据这个像素的物体间的距离。在整个场景被渲染时,只有没有被其他物体(像素)遮挡的物体(像素)才会被保留,最终被绘制出来。
首先我们看Lesson03AppDelegate.mm函数,允许增加深度缓存
[glview setDepthBufferNeeded:TRUE]
则在EAGLView.mm 的createFramebuffer函数中,下面的代码就被执行:
if(useDepthBuffer) { //create a depth renderbuffer glGenRenderbuffers(1, &depthRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); //create the storage for the buffer, optimized for depth values, same size as the colorRenderbuffer glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight); //attach the depth buffer to our framebuffer glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); }
首先创建了一个depthRenderbuffer,然后将它绑定到GL_RENDERBUFFER。
我们用glRenderbufferStorage来创建并初始化renderbuffer对象的数据存储空间。第一个参数必须是GL_RENDERBUFFER,第二个参数指定了depth renderbuffer的数据格式。后两个参数是depth renderbuffer的宽度和高度,和之前的其他buffer一样。
最后,调用glFramebufferRenderbuffer,将我们创建的depth buffer关联到framebuffer上。
最后,我们回到Lesson03.mm:
//drawing a frame void Lesson03::draw() { //clear the color buffer glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST);
在每一帧的开始,都清除深度缓存glClear(GL_DEPTH_BUFFER_BIT),并启用深度测试。
编译并运行程序,看看最后的效果。
附件里有本教程的完整源代码。本文出自 “周晶的博客” 博客,请务必保留此出处http://jimmyzhouj.blog.51cto.com/2317513/886680
相关文章推荐
- iOS OpenGL ES 2.0教程 Lesson04--3D空间
- [jimmyzhouj 翻译] Nehe iOS OpenGL ES 2.0教程 --Lesson 02
- iOS OpenGL ES2.0教程 Lesson03 旋转
- iOS OpenGL ES2.0教程 Lesson03 旋转 投影矩阵,相机矩阵,世界矩阵生效
- [jimmyzhouj 翻译] Nehe iOS OpenGL ES 2.0教程 --Lesson 02
- iOS OpenGL ES2.0教程 Lesson03 旋转
- [ jimmyzhouj 翻译] Nehe iOS OpenGL ES 2.0教程
- 罗朝辉 《OpenGL ES 2.0 iOS教程》完整列表
- Android OpenGL ES 简明开发教程 04 <3D 坐标变换>
- [ jimmyzhouj 翻译] Nehe iOS OpenGL ES 2.0教程
- iOS9 3D Touch iOS 教程 ShortcutItem使用
- Xcode创建的默认iOS OpenGL ES 2.0 project代码分析
- OpenGL ES2.0教程:编写自己的shader
- IOS 中openGL使用教程3(openGL ES 入门篇 | 纹理贴图(texture)使用)
- Android OpenGL ES 简明开发教程 03 <3D绘图基本概念>
- Android OpenGL ES 简明开发教程三:3D绘图基本概念
- Cocos2dx-OpenGL ES2.0教程:编写自己的shader(2)
- photoshop cs5基础教程10增强的3d…
- Direct3D 10教程4:3D空间
- iOS OpenGL ES2.0 开发实例