OpenGL ES之八——GLES20类和Matrix类

概述

这是一个系列的Android平台下OpenGl ES介绍,从最基本的使用最终到VR图的展示的实现,属于基础篇。(后面针对VR视频会再有几篇文章,属于进阶篇)

OpenGL ES之一——概念扫盲
OpenGL ES之二——Android中的OpenGL ES概述
OpenGL ES之三——绘制纯色背景
OpenGL ES之四——绘制点,线,三角形
OpenGL ES之五——相机和投影,绘制等腰三角形
OpenGL ES之六——绘制矩形和圆形
OpenGL ES之七——着色器语言GLSL
OpenGL ES之八——GLES20类和Matrix类
OpenGL ES之九——相机和投影
OpenGL ES之十——纹理贴图(展示一张图片)
OpenGL ES之十一——绘制3D图形
OpenGL ES之十二——地球仪和VR图

本篇概述

上面对于GLSL也有了一定的了解,并且通过之前编程过程,我们基本了解了GLSL语言的特色和通过调用Java语言编写的SDK来完成一些基本操作。下面总结一下GLES20和Matrix(GLES30或者更高这里就不一一列举了,由于是继承自GLES20所以好多直接使用的其中的)
重点:

GLES20作为我们和着色器连接的工具类提供了丰富的api。
同时由我们从前面的编程过程中也发现要想实现各种效果Matrix工具类是必不可少的

一 GLES20获取着色器程序内成员变量的id(句柄、指针)

GLES20.glGetAttribLocation方法:获取着色器程序中,指定为attribute类型变量的id。
GLES20.glGetUniformLocation方法:获取着色器程序中,指定为uniform类型变量的id。

如:

// 获取指向着色器中aPosition的index
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
// 获取指向着色器中uMVPMatrix的index
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

二 向着色器传递数据

使用上一节获取的指向着色器相应数据成员的各个id,就能将我们自己定义的顶点数据、颜色数据等等各种数据传递到着色器当中了。

// 使用shader程序
GLES20.glUseProgram(mProgram);
// 将最终变换矩阵传入shader程序
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
// 设置缓冲区起始位置
mRectBuffer.position(0);
// 顶点位置数据传入着色器
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 20, mRectBuffer);
// 顶点颜色数据传入着色器中
GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false, 4*4, mColorBuffer);
// 顶点坐标传递到顶点着色器
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, 20, mRectBuffer);
// 允许使用顶点坐标数组
GLES20.glEnableVertexAttribArray(maPositionHandle);
// 允许使用顶点颜色数组
GLES20.glDisableVertexAttribArray(maColorHandle);
// 允许使用定点纹理数组
GLES20.glEnableVertexAttribArray(maTextureHandle); 
// 绑定纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
// 图形绘制
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);

2.1 定义顶点属性数组

void glVertexAttribPointer (int index, int size, int type, boolean normalized, int stride, Buffer ptr )

参数含义:
index 指定要修改的顶点着色器中顶点变量id;
size 指定每个顶点属性的组件数量。必须为1、2、3或者4。如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a));
type 指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT;
normalized 指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE);
stride 指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。如果normalized被设置为GL_TRUE,意味着整数型的值会被映射至区间-1,1,或者区间[0,1](无符号整数),反之,这些值会被直接转换为浮点值而不进行归一化处理;
ptr 顶点的缓冲数据。

2.2 启用或者禁用顶点属性数组

调用GLES20.glEnableVertexAttribArray和GLES20.glDisableVertexAttribArray传入参数index。

GLES20.glEnableVertexAttribArray(glHPosition);
GLES20.glEnableVertexAttribArray(glHCoordinate);

如果启用,那么当GLES20.glDrawArrays或者GLES20.glDrawElements被调用时,顶点属性数组会被使用。

2.3 选择活动纹理单元。

void glActiveTexture (int texture)

texture指定哪一个纹理单元被置为活动状态。texture必须是GL_TEXTUREi之一,其中0 <= i < GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,初始值为GL_TEXTURE0。
GLES20.glActiveTexture()确定了后续的纹理状态改变影响哪个纹理,纹理单元的数量是依据该纹理单元所被支持的具体实现。

三 Matrix

3.1 矩阵和向量的重要性:

我们知道OpenGl中实现图形的操作大量使用了矩阵,在OpenGL中使用的向量为列向量,我们通过利用矩阵与列向量(颜色、坐标都可看做列向量)相乘,得到一个新的列向量。利用这点,我们构建一个的矩阵,与图形所有的顶点坐标坐标相乘,得到新的顶点坐标集合,当这个矩阵构造恰当的话,新得到的顶点坐标集合形成的图形相对原图形就会出现平移、旋转、缩放或拉伸、抑或扭曲的效果。
在这里插入图片描述
Matrix:专门为处理4*4矩阵和4元素向量设计的,其中的方法都是static的,不需要初始化Matrix实例。其实其中的方法也是比较少的共有18个(其中部分是native的调用本地代码),这里不一一详细介绍,重点是让大家了解各个方法的功能。

3.2 Matrix作用

Matrix就是专门设计出来帮助我们简化矩阵和向量运算操作的,里面所有的实现原理都是线性代数中的运算

3.3 变换矩阵

下面是几种常用的标准变换矩阵
在这里插入图片描述
在这里插入图片描述

3.4 Matrix中具体方法

下面矩阵的处理方法中参数不少是相同的并且含义也是相同的,所以只是将少数一些参数含义做了解释说明,未说明的参照已有说明都可以理解。

下面是Matrix中的15种类型的方法:

计算两个矩阵乘法

1 multiplyMM

public static native void multiplyMM(float[] result, int resultOffset,
            float[] lhs, int lhsOffset, float[] rhs, int rhsOffset);

将两个4x4矩阵相乘,并将结果存储在第三个4x4矩阵中。以矩阵表示法表示:结果=lhs x rhs。
参数含义:

参数含义
resultThe float array that holds the result. 保存结果的浮点数数组。
resultOffsetThe offset into the result array where the result is stored。结果数组中存储结果的偏移量。
lhsThe float array that holds the left-hand-side matrix. 保存左侧矩阵的浮点数数组。
lhsOffsetThe offset into the lhs array where the lhs is stored 左侧数组中存储结果的偏移量。
rhsThe float array that holds the right-hand-side matrix. 保存右侧矩阵的浮点数数组
rhsOffsetThe offset into the rhs array where the rhs is stored.右侧数组中存储结果的偏移量。

我们并不陌生了在使用投影矩阵和相机视图矩阵获取变换矩阵的时候使用过。

		//计算变换矩阵
        Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);

关于数组,多维数组和偏移量的问题不在这里展开说明,他是一个数学问题,请自行搜索。

利用一个变换矩阵和向量相乘获取新向量

2 multiplyMV

将一个4*4矩阵和一个四元素向量相乘获取一个新的四元素向量。

public static native void multiplyMV(float[] resultVec,int resultVecOffset,
			 float[] lhsMat, int lhsMatOffset,
            float[] rhsVec, int rhsVecOffset);

获取转置矩阵

3 transposeM

矩阵的转置处理:

public static void transposeM(float[] mTrans, int mTransOffset, float[] m, int mOffset)

获取逆矩阵

4 invertM

获取逆矩阵

public static boolean invertM(float[] mInv, int mInvOffset, float[] m, int mOffset)

正交投影和透视投影

5 orthoM

计算正交投影矩阵

public static void orthoM(float[] m, int mOffset,
        				float left, float right,
        				 float bottom, float top,
       					 float near, float far) 

6 frustumM

计算透视投影矩阵:以六个裁剪平面定义投影矩阵。

public static void frustumM(float[] m, int offset,
            					float left, float right,
            					float bottom, float top,
            					float near, float far) 

7 perspectiveM

根据视场角度、纵横比和Z裁剪平面定义投影矩阵。

public static void perspectiveM(float[] m, int offset,
          						float fovy, float aspect, 
          						float zNear, float zFar)

向量长度

8 length

计算向量长度

public static float length(float x, float y, float z)

定义单位矩阵

9 setIdentityM

创建单位矩阵

public static void setIdentityM(float[] sm, int smOffset) 

缩放矩阵

10 scaleM

按x、y和z缩放矩阵m,将结果放入sm。

public static void scaleM(float[] sm, int smOffset,
				            float[] m, int mOffset,
				            float x, float y, float z)

将m矩阵自身按照x,y,z进行缩放。

public static void scaleM(float[] m, int mOffset,
           					 float x, float y, float z) 

平移矩阵

11 translateM

将m矩阵按照x,y,z平移得到tm矩阵

public static void translateM(float[] tm, int tmOffset,
            					float[] m, int mOffset,
           						 float x, float y, float z)

将m矩阵自身按照x,y,z进行平移。

public static void translateM(
            float[] m, int mOffset,
            float x, float y, float z)

旋转矩阵

12 rotateM

将矩阵m经过a,x,y,z参数处理形成一个新的rm矩阵。(a单位采用普通角度)

public static void rotateM(float[] rm, int rmOffset,
            float[] m, int mOffset,
            float a, float x, float y, float z)

矩阵m根据a,x,y,z参数处理变成新的矩阵。(a单位采用普通角度)

public static void rotateM(float[] m, int mOffset,
          					  float a, float x, float y, float z) 

13 setRotateM

创造一个新的矩阵rm,根据a,x,y,z参数。(a单位采用普通角度)

public static void setRotateM(float[] rm, int rmOffset,
           						float a, float x, float y, float z)

14 setRotateEulerM

根据欧拉角度变换rm矩阵为新矩阵。

public static void setRotateEulerM(float[] rm, int rmOffset,
           							 float x, float y, float z)

获取相机视图矩阵

15 setLookAtM

定义相机视图

public static void setLookAtM(float[] rm, int rmOffset,
			           float eyeX, float eyeY, float eyeZ,
			            float centerX, float centerY, float centerZ,
			             float upX, float upY, float upZ)

我们平时的开发中都可能用到上面的方法,但是比较常用的是获取相机矩阵和投影矩阵;同时在操作图像使其动起来时,旋转,平移等亦经常用到,在下面文章中都会详细介绍。

上面的相机矩阵和投影矩阵相关由于不好理解并且涉及相关概念,所以在下一篇中专门来说一下。
  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的 OpenGL ES 2.0 线性插值的示例代码,用于在两个顶点之间进行颜色的线性插值渲染: ```java import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; public class MyRenderer implements GLSurfaceView.Renderer { private float[] vertices = { -0.5f, -0.5f, 0.0f, // 左下角顶点 0.5f, -0.5f, 0.0f, // 右下角顶点 0.0f, 0.5f, 0.0f // 顶部顶点 }; private float[] colors = { 1.0f, 0.0f, 0.0f, 1.0f, // 左下角顶点颜色 (红色) 0.0f, 1.0f, 0.0f, 1.0f, // 右下角顶点颜色 (绿色) 0.0f, 0.0f, 1.0f, 1.0f // 顶部顶点颜色 (蓝色) }; private int program; private int positionHandle; private int colorHandle; private int mvpMatrixHandle; private float[] projectionMatrix = new float[16]; @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); program = GLES20.glCreateProgram(); GLES20.glAttachShader(program, vertexShader); GLES20.glAttachShader(program, fragmentShader); GLES20.glLinkProgram(program); positionHandle = GLES20.glGetAttribLocation(program, "vPosition"); colorHandle = GLES20.glGetAttribLocation(program, "vColor"); mvpMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix"); GLES20.glUseProgram(program); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); float ratio = (float) width / height; Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1); } @Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); // 将投影矩阵传递给着色器 GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, projectionMatrix, 0); // 启用顶点位置和颜色属性 GLES20.glEnableVertexAttribArray(positionHandle); GLES20.glEnableVertexAttribArray(colorHandle); // 设置顶点位置数据 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer); // 设置顶点颜色数据 GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 0, colorBuffer); // 执行绘制 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); // 禁用顶点位置和颜色属性 GLES20.glDisableVertexAttribArray(positionHandle); GLES20.glDisableVertexAttribArray(colorHandle); } private int loadShader(int type, String shaderCode) { int shader = GLES20.glCreateShader(type); GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } // 着色器代码 private final String vertexShaderCode = "attribute vec4 vPosition;" + "attribute vec4 vColor;" + "uniform mat4 uMVPMatrix;" + "varying vec4 interpolatedColor;" + "void main() {" + " gl_Position = uMVPMatrix * vPosition;" + " interpolatedColor = vColor;" + "}"; private final String fragmentShaderCode = "precision mediump float;" + "varying vec4 interpolatedColor;" + "void main() {" + " gl_FragColor = interpolatedColor;" + "}"; } ``` 注意,上述代码是一个简化的示例,只绘制了一个三角形,并将顶点的颜色进行了线性插值。你可以根据实际需求进行更复杂的插值操作和渲染效果的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值