前言:
前面一直在说OpenglES2.0二维图形的绘制,接下来我们步入三维的世界 ,三维世界远比二维要有趣的多,与此同时复杂性也要高得多,在unity3D中我们可以很容易的就创建
一个立方体,而在OpenglES2.0中这个过程要复杂得多,但是更加有趣 。先来看下我们的整个流程:
摄像机的设置:
想想你的摄像头,它的位置不同,朝向不同,对同一个事物拍摄得到的画面肯定是不同的,Opengl中的摄像头和我们日常生活中的摄像头是一样的道理
(图一)
在Opengl中摄像头包含三部分的信息:
1. 摄像头的位置 ,在三维空间中用 x y z 表示
2. 摄像头的镜头的指向,这里即观察的物体的坐标,一般选取物体的center坐标(通过摄像头的位置与观察的物体的坐标可以确定一个向量,这个向量就可以决定观察的方向)
3. 摄像头的UP方向,摄像机顶端的指向
下面的人眼观察物体的图示更容易帮助我们理解:
(图二 )
可以看出摄像机的位置,朝向,UP方向有很多不同的组合,对于不同的组合观察同一物体会得到不同的结果
为了更好地理解,这里给出国外大牛做的一个demo :
我们先做只需要看gluLookAt , eye 就是我们所说的摄像机的位置,center即摄像头的镜头的指向
我们可以改变这些值,来观察一下右上方的图像的变化。
下载地址:https://download.csdn.net/detail/cassiepython/9541794
透视投影
我们观察物体,会有近大远小的效果,透视投影即为了产生这种效果,和美术中 的透视是一个概念
(图三)
其中,视点指摄像机的位置,近平面指距离视点较近的垂直于观察方向的平面,视景体又叫做视锥体为椎台形区域。
透视投影的投影线互不平行,相较于视点,因此,对于同样尺寸的物体,在近处投影出来大,在远处投影出来小,由此产生近大远小的效果。
(图四)
大家可以继续结合上面的小软件修改参数试下来了解透视投影。
立方体顶点坐标
OK,现在让我们开始着手具体的编程,首先来定义立方体的顶点坐标,此时我们肯定不能只是X ,Y了 ,还要加入一个新的参数 Z ,Z和X, Y的范围是一样的,
也是从 -1 到 1 ,我们看向自己的手机屏幕,想象我们的视线穿过两个平面,前面的为 1 后面的为 -1 。
我们接着上一节的工程来做,在shape包下新建一个类 ——Cube.java ,然后创建顶点数据 ,此时 Cube.java 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
|
我们每个面定义了12个顶点:
每一个面分为4个三角形,每个三角形包含3个点,共12个点(我们打算使用GL_TRIANGLES方式绘制 )
接下来看下我们的着色器代码,顶点着色器我们使用仍然使用上一节的vertex_shader.glsl :
1 2 3 4 5 6 7 |
|
u_Matrix用于我们传入最终的变幻矩阵 (投影矩阵 and 摄像机矩阵)。
然后我们编译链接着色器 此时Cube类代码 (Cube.java ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
|
接下来我们应该定义实现draw方法,在此之前先让我们解决投影矩阵的问题
设置相机和投影
我们来定义一个工具类来获得最终的变幻矩阵 ,我们需要使用两个函数 :
这两个函数的参数的含义与上面我们讲解相机和投影时的那些参数是对应的,大家可以回到前面再看下,这里不再重复。
我们在utils包中定义工具类——MatrixState 然后看我的工具类的代码 (MatrixState.java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
这个工具类中有三个方法,我们在渲染类 (MyRender.java)中的 onSurfaceChanged中调用前两个方法设置摄像机和投影矩阵,在Cube的draw方法中就可以通过第三个方法
getFinalMatrix 来获取最终的变换矩阵 然后传入着色器程序。 (我们注意multiplyMM函数,这个函数工作是将我们的投影矩阵和摄像机矩阵进行矩阵的乘法运算,存储在
mMVPMatrix中,这个mMVPMatrix即为我们最终的变换矩阵,即我们需要传入着色器程序的矩阵。
OK,看下完整的 Cube.java 类 和 MyRender.java :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
|
然后我们回到MainActivity 设置屏幕显示方式为竖屏,全屏 ,此时MainActivity代码如下 (MainActivity.java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
快来运行一下 :
一个全红的立方体诞生了~~(大家还可以尝试用线段的绘制方式来绘制一个 " 空心 " 的立方体),可是这样看起来根本看不出来它的一些边 ,我们来想办法给它美化一下,在这节先不考虑纹理贴图,我们把每个面设置成不同的颜色。
OK,先来看下我们接下来的过程 :
在Cube类中定义顶点坐标,并转化为FloatBuffer类型 ,此时代码如下 (Cube.java ) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
|
创建新的顶点着色器和片段着色器程序 (vertex_shader_cube.glsl 和fragment_shader_cube.glsl ):
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 |
|
去点原来的引入颜色的相关代码,加入当前要传递的颜色相关的代码,此时Cube类如下 (Cube.java ) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
|
运行一下看看结果 :
哈 现在我们的立方体就完成了 ,是不是很漂亮 。 关于颜色设置,这里用到了OpenglEs 的平滑着色 ,如果有不明白的
可以去按照 “opengl es 平滑着色 ” 这个关键字搜索一下 。这里不再讲解。