Skip to content

Latest commit

 

History

History
284 lines (157 loc) · 14.1 KB

8.GLES类及Matrix类.md

File metadata and controls

284 lines (157 loc) · 14.1 KB

8.GLES类及Matrix类

GLES作为我们与着色器连接的工具类提供了丰富的api。了解一些常用API的意思能更方便后面的学习,这里就简单整理列了一些常用的部分:

  • glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)

    为颜色缓冲区指定清除值

  • glClear(GLbitfileld mask)

    清除预设值的缓冲区,参数分别为GL_COLOR_BUFFER_BIT(当前启用了颜色写入的缓冲区) GL_DEPTH_BUFFER_BIT(深度缓冲区) GL_STENCIL_BUFFER_BIT(模板缓冲区)

  • glActiveTexture(GLenum texture)

    激活纹理单元。参数指定要激活的纹理单元,参数texture必须是GL_TEXTUREi之一,初始值为GL_TEXTURE0。

  • glBindTexture(GLenum target, GLunit texture)

    将一个特定的纹理ID绑定到一个纹理目标上

  • glGenTextures(GLsizei n, GLunit * textures)

    生成纹理ID,参数n是指定要生成的纹理ID的数量,textures是指定存储生成的纹理ID的数组

  • glCreateShader(GLenum shaderType)

    创建一个空的着色器对象,类型分别为GL_VERTEX_SHADER和GL_FRAGMENT_SHADER

  • glCompileShader(GLunit shader)

    编译一个着色器对象。创建后要先编译才能运行。

  • glAttachShader(GLunit program, GLunit shader)

    将着色器对象附加到program对象

  • glCreateProgram()

    创建一个空的program对象并返回一个可以被引用的program id。

  • glEnableVertexAttribArray(GLunit index)/glEnableVertexAttribArray(GLunit index)

    启用或禁用通用定点属性数组。参数为指定要启用或禁用的通用顶点属性的索引。

  • glDrawArrays(GLenum mode, GLinit first, GLsizei count)

    参数mode为指定要渲染的图元类型,如GL_POINTS,GL_LINE_STRIP,GL_LINE_LOOP。first为指定已启用阵列中的起始索引。count为指定要渲染的索引数。在调用该方法前,可以使用glVertexAttribPointer预先指定单独的顶点、位置和颜色数组等信息。

  • glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)

    mode是指定要渲染的图元类型,可以为GL_POINTS,GL_LINE_STRIP,GL_LINES等,count指定要渲染的元素数,type指定indices中的类型,必须是GL_UNSIGNED_BYTE或GL_UNSIGNED_SHORT。indices指定指向存储索引的位置的指针。使用该方法前也是需要使用glVertexAttribPointer来预先指定单独的顶点位置和颜色数据等信息。

  • void glGetUniformfv(GLunit program, GLinit location, GLfloat *params)

    通过params的形式返回指定统一变量的值,参数program指定要查询的program对象,location指定要查询的统一变量的位置,params返回指定的统一变量的值。

  • void glGetVertexAttribfv(GLunit index, GLenum pname, GLFloat *params)

    以params形式返回通用顶点属性参数的值。参数index是指定要查询的通用顶点的属性参数,pname是指定要查询的顶点属性参数的符号名称。可接受的值为GL_VERTEX_ATTRIB_ARRAY_BFFER_BINGDING等。

  • void glGetVertexAttribPointerv(GLunit index, GLenum pname, GLvoid **pointer)

    以**pointer返回指定的通用顶点属性的指针信息。参数index为要返回单额通用顶点属性采参数,pname是指定要返回的通用顶点属性参数的符号名称,必须是GL_VERTEX_ATTRIB_ARRAY_POINTER。

  • glLinkProgram(GLunit program)

    链接program指定的program对象,指定要链接的program对象的句柄。

  • glTexImage2D(GLenum target, Glint level, GLinit internalformat, GLsizei width, GLsizei height, GLinit border, GLenum format, GLenum type, const GLvoid *data)

    指定一个二维的纹理图片。纹理将指定纹理图像的一部分映射到纹理化为活动的每个图形基元。

  • void glUniform1f(GLinit location, GLfloat v0)

  • void glUniformxx(GLinit l n,b njiu[uyi77u777uocation, GLfloat v0)

  • void glUniformMatrix1fx(GLinit location, GLsizei countM, GLboolean transpose, const GLfloat *valueM)

    修改统一变量或统一变量数组的值。参数location为指定要修改的统一变量的位置,可以由glGetUniformLocation返回,v就是用于指定统一变量的新值。

    count是指定要修改的元素数,value是指定指向将用于更新指定统一变量的count值数组的指针。countM指定要修改的矩阵数。

  • glUseProgram(GLunit program)

    使用程序对象program作为当前渲染状态的一部分。

  • glVertexAttrib(GLunit index, GLFloat vo ...)

    指定通用顶点属性的值

  • glVertexAttribPointer(GLunit index, GLinit size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer)

    指定索引index处的通用顶点属性数组的位置和数据格式,以便在渲染时使用。

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

mPostionHandler = GLES30.glGetAttribLocation(mProgram, "aPosition"):获取着色器程序中,指定为attribute类型的变量idmMatrixHnadler = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix"):获取着色器程序中,指定为uniform类型的变量id

向着色器传递数据

上面获取到指向着色器中相应数据成员的各个id后,就能将我们要设置的顶点数据、颜色数据等传递到着色器中了。

// 将最终变换矩阵传入shader程序
GLES30.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
// 顶点位置数据传入着色器
GLES30.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 20, mRectBuffer);
// 顶点颜色数据传入着色器中
GLES30.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false, 4*4, mColorBuffer);
// 顶点坐标传递到顶点着色器
GLES30.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, 20, mRectBuffer);

定义顶点属性数组

/**
 * glVertexAttribPointer()方法的参数分别为: 
 * index:顶点属性的索引.(这里我们的顶点位置和颜色向量在着色器中分别为0和1)layout (location = 0) in vec4 vPosition; layout (location = 1) in vec4 aColor;
 * size: 指定每个通用顶点属性的元素个数。必须是1、2、3、4。此外,glvertexattribpointer接受符号常量gl_bgra。初始值为4(也就是涉及颜色的时候必为4)。
 * type:属性的元素类型。(上面都是Float所以使用GLES30.GL_FLOAT);
 * normalized:转换的时候是否要经过规范化,true:是;false:直接转化;
 * stride:跨距,默认是0。(由于我们将顶点位置和颜色数据分别存放没写在一个数组中,所以使用默认值0)
 * ptr: 本地数据缓存(这里我们的是顶点的位置和颜色数据)。
 */
GLES30.glVertexAttribPointer(1, 4, GLES30.GL_FLOAT, false, 0, colorBuffer);

启用或禁用顶点属性数组

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

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

Matrix

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

我们知道OpenGl中实现图形的操作大量使用了矩阵,在OpenGL中使用的向量为列向量,我们通过利用矩阵与列向量(颜色、坐标都可看做列向量)相乘,得到一个新的列向量。
利用这点,我们构建一个的矩阵,与图形所有的顶点坐标坐标相乘,得到新的顶点坐标集合,当这个矩阵构造恰当的话,新得到的顶点坐标集合形成的图形相对原图形就会出现平移、旋转、缩放或拉伸、抑或扭曲的效果。
Matrix是专门为处理4*4矩阵和4元素向量设计的,其中的方法都是static的,不需要初始化Matrix实例。

OpenGL ES中使用的是列向量。列向量和矩阵相乘实现变换时,只能再列向量前面乘以矩阵。
而行向量则反之,否则乘法没有意义。

  • multiplyMM

    两个4x4矩阵相乘,并将结果存储到第三个4x4矩阵中。

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

    将一个4x4矩阵和一个四元素向量相乘,得到一个新的四元素向量

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

    获取逆矩阵

相机

顶点着色器可赋予程序员一次操作一个顶点(“按顶点”处理)的能力,片段着色器(稍后会看到)可赋予程序员一次操作一个像素(“按片段”处理)的能力,几何着色器可赋予程序员一次操作一个图元(“按图元”处理)的能力。

到目前为止,我们所接触的变换矩阵全都可以在3D空间中操作。但是,我们最终需要将3D空间或它的一部分展示在2D显示器上。

为了达成这个目标,我们需要找到一个有利点。
正如我们在现实世界通过眼睛从一点观察一样,我们也必须找到一点并确立观察方向作为我们观察虚拟世界的窗口。这个点叫作视图或视觉空间,或“合成相机”(简称相机)。

观察3D世界需要:

  • 将相机放入世界的某个位置;
  • 调整相机的角度,通常需要一套它自己的直角坐标轴u、v、n(由向量U,V,N构成);
  • 定义一个视体(view volume);将视体内的对象投影到投影平面(projection plane)上。

image

OpenGL有一个固定在原点(0,0,0)并朝向z轴负方向的相机,如下图所示:

image

为了应用OpenGL相机,我们需要将它移动到适合的位置和方向。我们需要先找出在世界中的物体与我们期望的相机位置的相对位置。
给定世界空间中的点PW,我们需要通过变换将它转换成相应相机空间中的点,从而让它看起来好像是从我们期望的相机位置CW看到的样子。

当我们设置好相机之后,就可以学习投影矩阵了。我们需要学习的两个重要的投影矩阵:透视投影矩阵和正射投影矩阵。
透视投影通过使用透视概念模仿我们看真实世界的方式,尝试让2D图像看起来像是3D的。物体近大远小,3D空间中有的平行线用透视法画出来就不再平行。我们可以通过使用变换矩阵将平行线变为恰当的不平行线来实现这个效果,这个矩阵叫作透视矩阵或者透视变换。

在正射投影中,平行线仍然是平行的,即不使用透视,如下图所示。正射与透视相反,在视体中的物体不因其与相机的距离而改变,可以直接投影。正射投影是一种平行投影,其中所有的投影过程都沿与投影平面垂直的方向进行。 image

我们最后要学习的变换矩阵是LookAt矩阵。当你想要把相机放在某处并看向一个特定的位置时,就需要用到它了,LookAt矩阵的元素如下图所示。
当然,用我们已经学到的方法也可以实现LookAt变换,但是这个操作非常频繁,因此为它专门构建一个矩阵通常比较有用。 image

  • invertM

    计算正交投影和透视投影

  • orthoM

    计算正交投影矩阵

  • frustumM

    计算透视投影矩阵

  • perspectiveM

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

  • length

    计算向量长度

  • setIdentityM(float[] sm, int smOffset)

    用来创建一个单位矩阵。其中第一个参数是创建出来的单位矩阵存储的地方,是一个float类型的一维数组。第二个参数是存储的数据位置的偏移量,也就是说从哪里开始存储。生成的结果先按照列优先存储的,也就是说先存放第一列的数据,再存放第二列的数据,以此类推。前面理论部分已经提到,所有变换都是基于单位矩阵的基础上进行的,所以第一步创建单位矩阵是必须的。

  • scaleM(float[] m, int mOffset, float x, float y, float z)

    用来进行图像的缩放,第一个参数是需要变换的矩阵;第三、四、五个参数分别对应x,y,z 方向的缩放比例,当x方向缩放为0.5时,相当于向x方向缩放为原来的0.5倍,其他类似。

  • translateM( float[] m, int mOffset, float x, float y, float z)

    用来进行图像的位移,第一个参数是需要变换的矩阵;第二个参数是偏移量;第三、四、五个参数分别对应x,y,z 方向的位移量。其以图像自身x,y,z方向为单位,也就是说当x方向位移量为0.5时,相当于向右移动0.5个身位,其他类似。

  • rotateM(float[] m, int mOffset, float a, float x, float y, float z)

    用来进行旋转变换的。第一个参数是需要变换的矩阵;第二参数是偏移量;第三个参数是旋转角度,这边是以角度制,也就是说是0-360这个范围;第四、五、六个参数分别代表旋转轴向量的x,y,z值。如果x=0,y=0,z = 1 就相当于以z轴为旋转轴进行旋转,其他类似。

  • setLookAtm

    定义相机视图

旋转

OpenGL ES中,旋转角度的正负可以用右手螺旋定则来确定。 所谓右手螺旋定则是指:右手握住旋转轴,使大姆指指向旋转轴的正方向,4指环绕的方向即为旋转的正方向,也就是旋转角度为正值。