一 二 三 四 Opengles2.0渲染管线 简单画图步骤 着色器语言简单介绍 镜像技术 一 OpenGLES2.0渲染管线 1.基本处理 初始化3D空间中物体的 顶点坐标,顶点对应的颜色,顶点的纹理坐标等属性 1.1 顶点缓冲对象(可选):缓冲顶点数据,提高渲染效率 2.顶点着色器:
顶点变换,法向量计算,纹理坐标变换,光照与材质的应用 3.图元装配
3.1 图元组装:组装点,线,三角形 3.2 图元处理:主要是裁剪 4.光栅化:将投影结果离散化为一个个小片元 5.片元着色器:纹理处理,颜色求和,雾效果 6.剪裁测试:丢弃在帧缓冲位置不在剪裁窗口中的片元 7.深度测试与模板测试: 深度测试就是判断新片元的深度是否小于深度缓冲区里面的片元深度,小于则能通过 深度测试,否则新片元将被丢弃。 深度就是指物体距照相机的位置,深度缓冲区的片元深度,是指第一个被绘制的物体 的片元深度,新的通过深度测试的片元,将会成为深度缓冲区的片元深度。 镜像技术一定要关闭深度检测。 8.颜色缓冲混合 9.抖动 10.帧缓冲 二 简单绘图步骤 绘制一个用户可以旋转的三角形的步骤如下: 1.用 GLSurfaceView and GLSurfaceView.Render创建一个Activity,为 GLSurfaceView子类增加onTouchEvent事件 2.初始化顶点坐标,颜色坐标并缓冲坐标数据 3.编写顶点着色器,片元着色器语言并加载,编译顶点,片元shader 4.创建着色器程序,并关联shader 5.产生摄像机9参数位置矩阵 6.产生透视投影矩阵 7.产生最终的模型视图投影矩阵,绘制三角形 步骤二:初始化顶点坐标,颜色坐标并缓冲坐标数据 顶点坐标 float triangleCoords[] = { // X, Y, Z -1.0f, 1.0f, 0.0f, // 0, Top Left -1.0f, -1.0f, 0.0f, // 1, Bottom Left 1.0f, -1.0f, 0.0f, // 2, Bottom Right 1.0f, 1.0f, 0.0f, // 3, Top Right }; ByteBuffer vbb = ByteBuffer.allocateDirect( vbb.order(ByteOrder.nativeOrder()); FloatBuffer triangleVB = vbb.asFloatBuffer(); ByteBuffer triangleVB.put(triangleCoords); triangleVB.position(0); 步骤三:编写顶点着色器,片元着色器语言并加载,编译顶点,片元shader ? private final String vertexShaderCode = ? // This matrix member variable provides a hook to manipulate ? // the coordinates of the objects that use this vertex shader ? "uniform mat4 uMVPMatrix; \n" + ? "attribute vec4 aColor;\n" + ? "varying vec4 vColor;\n" + ? "attribute vec4 vPosition; \n" + ? "void main(){ \n" + ? // the matrix must be included as a modifier of gl_Position ? " gl_Position = uMVPMatrix * vPosition; \n" + ? " vColor = aColor;\n" + ? "} \n"; ? ? private final String fragmentShaderCode = ? "precision mediump float; \n" + ? "varying vec4 vColor;\n" + ? "void main(){ \n" + ? " gl_FragColor = vColor; \n" + ? "} \n"; 步骤四:创建着色器程序,并关联shader mProgram = GLES20.glCreateProgram(); GLES20.glAttachShader(mProgram, vertexShader GLES20.glAttachShader(mProgram, fragmentShader); GLES20.glLinkProgram(mProgram); // 从OpenGLES引擎里面获取vPosition属性的句柄,便于下面赋值 maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); // 从OpenGLES引擎里面获取aColor属性的句柄,便于下面赋值 maColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor"); 步骤五:产生摄像机9参数位置矩阵 Matrix.setLookAtM(mVMatrix, 0, 0f, 0f, 7f, 0f, 0f, 0f, 0.0f, 1.0f, 0.0f); 步骤五:产生透视投影矩阵 //为投影矩阵赋值,ratio为设备屏幕的宽高比, Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7); //获取最终的模型视图投影矩阵uMVPMatrix的句柄, muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 视景体的如下: 步骤七:产生最终的模型视图投影矩阵,绘制三角形 public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); // 重 绘背景色 GLES20.glUseProgram(mProgram);//把着色器程序添加到OpenGL环境中 // 将顶点数据缓冲里面的数据赋值给opengl引擎里面的顶点位置句柄 GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 12, triangleVB); GLES20.glEnableVertexAttribArray(maPositionHandle);//启用该顶点位置属性 // 将颜色缓冲数据赋值给引擎的颜色句柄 GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false, 16, colorBuffer); GLES20.glEnableVertexAttribArray(maColorHandle);//启用该顶点颜色位置属性 //根据模型旋转角度为模型矩阵赋值 Matrix.setRotateM(mMMatrix, 0, mAngle, 0, 0, 1.0f); //将模型矩阵和视图矩阵合并为一个矩阵 Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0); //再和投影矩阵合并,最终形成模型视图投影矩阵 Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0); GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);、 //绘制三角形 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); } 三 着色器语言简单介绍 OpenGL ES着色语言时一种高级的过程语言,基于C/C++语言。 数据类型: 向量:由同样类型的标量组成,标量为bool,int,float。每个向量可以有2个,3个或者4 个相同的标量组成。例如: Vec4:包含了四个浮点数的向量 ivec2:包含了两个整数的向量 矩阵:3D场景中物体的移位,旋转,缩放等变换都是有矩阵的运算来实现的。 例如:Mat2:2x2的浮点矩阵 mat4:4x4的浮点矩阵 限定符: Attribute:一般用于每个顶点都不相同的量,如顶点坐标,颜色,纹理坐标,法向量等 该限定符只用于顶点着色器。 Uniform:一般用于对同一组顶点组成的单个3D物体中所有顶点都相同的量,如当前的 光源位置。该限定符可用于顶点着色器和片元着色器。 Varying:用于从顶点着色器传递到片元着色器的量。 内建变量: 顶点着色器的内建输出变量: gl_Position:在顶点着色器里面为其赋值后,该变量传递到渲染管线供后续处理。 片元着色器的内建输出变量: gl_FragColor:在片元着色器里面为其赋值后,该变量传递到渲染管线供后续处理。 四 镜像技术 形成镜像的原因是反射,经过反射形成的像与其对应的实体相对于反射面是对称 的,因此可以根据实体和反射面的位置计算出镜像的位置。 镜像效果的绘制顺序最好为:首先绘制反射面,其次绘制镜像体,最后绘制实体。 最关键的就是要关闭深度测试。 在打开深度测试后,会开不见镜像体的原因: 如果先绘制里照相机较近的反射面,则此时在深度缓冲区里面会记录较小的深度 值,当绘制里照相机较远的镜像体时,因为其片元的深度值大于此时缓冲区 里面的值,于是将不会通过深度测试,片元将被丢弃。 如果先绘制镜像体然后绘制反射面的话,深度测试能够通过,但是反射面过大会 覆盖镜像体的片元,导致镜像体被部分或全部遮挡。 关闭深度测试后,也要先绘制反射面,再绘制镜像体,此时在混色时镜像体能够 可见,否则,反射面将完全遮挡镜像体。 对于实体的绘制最好放在最后,具体原因有待考证。