零蚀
前言
- 步骤如下:
-
step 1:实现一个三色揉合的三角形,从案例出发,解释其用法和原理。
-
step 2:长宽比问题。利用矩阵完成正投影。
-
色彩设置
-
介绍
-
之前都是直接限定死了一个元素对象的色彩,比如之前的三角形,线,点,在这一篇里会设置它不同颜色糅合的情况,然后还会设置阴影。之前我们是如何限定死只渲染了一种颜色的呢?首先我们在顶点着色器里面定义了一个
v_Color
,这个是干嘛的,它是控制顶点着色的,然后这个参数,会将色值传递给片段着色器的v_Color
,然后再由gl_FragColor = v_Color;
来设置片段着色器的颜色。 -
而我们实在java里
int uColorLocation=glGetUniformLocation
获取了颜色(顶点着色器)的参数,然后通过GLES20.glUniform4f(uColorLocation , Rf, Gf, Bf, Af);
对这个v_Color
进行赋值。 -
Opengl给我们一种相对而言不损耗过多性能的方案,就是,通过设置图形的每个点颜色,来起到颜色平滑过度的效果。我们要让整个桌面看起来有灯照效果,所以要将,平面的中心点的颜色设置起来,这样,就可以通过中点到四周呈光亮度降低的感觉。
代码上我们一刻这么写
// one 0, 0, -0.5f, -0.5f, 0.5f, -0.5f, // two 0, 0, 0.5f, -0.5f, -0.5f, 0.5f, // three 0 ,0, 0.5f, 0.5f, -0.5f, 0.5f, // four 0.0f,0.0f, -0.5f, 0.5f, -0.5f, -0.5f,
-
然后我们可以重新定义我们桌子的顶点,除了正常的xy之外,还要添加RGB来控制每个点的颜色,我们以一个三角形为例,大致结果如下所示:
-
-
代码&解释
-
首先我们需要设置我们的三角形的顶点的坐标和颜色,修改之前的坐标样式,这里每一行5个参数,代表一个坐标点,坐标的含义对应着 x,y,r, g 。(Android中的颜色例如Color.red色值范围是(0-255),而opengl中的色值是(0-1))
static float tableVertices[] = { // Triangle one 0f, 0f, 0f, 1f, 1f, -0.5f, -0.5f, 1f, 0f, 1f, 0.5f, -0.5f, 0f, 1f, 1f, }
-
OpenGL ES 三种类型修饰
uniform
,attribute``````varying
。-
1、
uniform
它是application通过glUniform**
进行赋值的,它相当于一个常量,shader只能用不能改动,uniform
修饰的变量在vertex和fragment中完全是一样的话,则说明这个变量是在vertex和fragment之间进行共享,相当于他们之间的全局变量, -
2、
attribute
只能在vertex中使用,一般它用来描述一个顶点的数据,如顶点坐标,纹理坐标,法线,顶点颜色.etc,用glBindAttribLocation
来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer()为每个attribute变量赋值。 -
3、
varying
变量是vertex和fragment shader之间做数据传递用的,一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值,因此varying变量在vertex和fragment shader二者之间的声、明必须是一致的。application不能使用此变量(uniform是外部传入,这个是内部传入)
-
-
然后我们来看一下OpenGL里面关于着色器的设置:
-
片段着色器:这里我们改变固定的uniform传入的数据,改用varying,让顶点着色器来传递色值。
precision mediump float; //uniform vec4 v_Color; varying vec4 v_Color; void main() { gl_FragColor = v_Color; }
-
顶点着色器:这里我们除了需要坐标的位置,还需要传递的颜色值,传递的着标点的颜色给fragment后,opengl会根据这些坐标值进行计算,构建出光滑的颜色过渡。
attribute vec4 a_Position; attribute vec4 a_Color; varying vec4 v_Color; void main() { v_Color = a_Color; gl_Position = a_Position; gl_PointSize = 20.0; }
-
然后我们需要获取到OpenGL的参数
a_Color
,将参数传递给它,由它通知顶点和片段着色器来实现颜色的揉合,所以我们可以获取一下我们需要的颜色参数:// ShaderHelp public static final String A_COLOR="a_Color"; public static int getAColorLocation(int programId){ return GLES20.glGetAttribLocation(programId,A_COLOR); }
-
然后就是Renderer里面的参数配比了,我们这里的坐标有5个点,前两个是坐标,后三个是颜色,所以,我们要告诉OpenGL从哪开始读,然后隔多少位继续读(偏移量),所以,之前我们设置了坐标positoin的元素个数
POSITION_COMPONENT_COUNT=2
,我们还要添加色彩的元素个数的参数COlOR_COMPONENT_COUNT=3
,这样我们就有了最基本的两个记录位置的。 -
那么我们如何告诉OpenGL绘制的方式,他怎么知道前两个是坐标,后三个是颜色呢?,我们在
onSurfaceCreated
里面可以实现如下的代码:@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(0.0f,0.0f,0.0f,0.0f); int program =ShaderHelp.linkShader(context); if(program!=0){ // 坐标点的设置 vertexBuffer.position(0); int positionLocation = ShaderHelp.getPositionLocation(program); GLES20.glVertexAttribPointer( positionLocation, POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, BYTES_FLOAT*(POSITION_COMPONENT_COUNT+COlOR_COMPONENT_COUNT), vertexBuffer); GLES20.glEnableVertexAttribArray(positionLocation); // 坐标颜色的设置 vertexBuffer.position(POSITION_COMPONENT_COUNT); // int aColorLocation = ShaderHelp.getAColorLocation(program); // 抛弃v_Color赋值 uColorLocation = ShaderHelp.getColorLocation(program); // 关联java和OpenGl的数据 GLES20.glVertexAttribPointer( aColorLocation, COlOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, BYTES_FLOAT*(POSITION_COMPONENT_COUNT+COlOR_COMPONENT_COUNT), vertexBuffer); GLES20.glEnableVertexAttribArray(aColorLocation); } }
-
这里首先我们开始坐标点的设置,我们要告诉opengl 坐标的读取是从头开始读取的
position(0)
,且读取的偏移量(跨度)为BYTES_FLOAT*(POSITION_COMPONENT_COUNT+COlOR_COMPONENT_COUNT)
这是xyRGB的字节长度(一个坐标点),然后呢,我们可以看到,第一个赋值的是a_Position
,把数组里的位置坐标传递了过去,每次赋值长度为POSITION_COMPONENT_COUNT
,然后我们设置了颜色的读取位置position(POSITION_COMPONENT_COUNT)
是从坐标之后开始读取,然后每次读取也是一个坐标的字节长度,然后把数值传递给了a_Color
,到此OpenGL已经拿到了数值&颜色值,我们不需要再传任何数值过去了, -
这里我们不需要在通过
glUniform4f
来给v_Color
赋值设置固定的颜色,所以我们可以注掉相关的代码,也不需要glGetUniformLocation
来获取v_Color
。所以我们的渲染类onDrawFrame
代码里只需要下列的代码就可以了。@Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); }
-
如此我们可以获取上面的一个三色杂糅的三角形了。
-
-
比例
-
一个问题
-
其实在我们绘制的时候opengl知道了要如何去绘制,但是,在一些情况下,比如绘制结束,横屏竖屏的情况下,由于长宽比不同而导致,图像变形的问题。如下图所示,我们的三角形被压扁了。
-
在解决问题前,我们要了解一些知识,1、正投影:它是正向对物体的投影,无论远近都不会改变问题的形状和比例。2、单位矩阵:任何向量✖️单位矩阵都是向量本身,3、转换矩阵:利用向量和矩阵的乘积来改变向量的结果。具体的内容就不解释了,感兴趣,网上有很多。
-
首先为了解决问题,我们需要设置一个正投影,通过更新着色器,给着色器添加矩阵来设置我们的位置。我们在顶点着色器来控制我们的正投影的矩阵(4x4)。
// simple_vertex_shader.glsl attribute vec4 a_Position; attribute vec4 a_Color; varying vec4 v_Color; uniform mat4 u_Matrix; void main() { v_Color = a_Color; gl_Position = u_Matrix * a_Position;; gl_PointSize = 20.0; }
-
然后我们获取这个参数
//ShaderHelp private static final String U_MATRIX = "u_Matrix"; public static int getMatrixLocation(int programId){ return GLES20.glGetUniformLocation(programId, U_MATRIX); }
-
我们还需要在java中创建一个矩阵来传递参数给我们的opengl,
// Renderer private final float[] projectionMatrix = new float[16]; @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { ..... // 获取到u_Matrix在java中的对象 matrixLocation = ShaderHelp.getMatrixLocation(program); ..... }
-
将我们坐标变化的参数值传递给我们的矩阵,这里用到了
android.opengl.Matrix
里的方法orthoM,参数不说,都有提示,然后这个aspectRatio是宽高比,也就是无论横竖屏都是这个值,我们把短的那一边定义为1(防止图像溢出),那么长的一边的坐标长度就是[-aspectRatio,aspectRatio],这个区间,所以我们可以如下设置,将后面的参数设置放入第一个参数的矩阵中。@Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0,0,width,height); final float aspectRatio = width > height ? (float)width/(float)height:(float)height/(float)width; if(width>height){ // 横屏 landscapes Matrix.orthoM(projectionMatrix,0,-aspectRatio,aspectRatio,-1f, 1f, -1f, 1f); }else{ // 竖屏 portrait Matrix.orthoM(projectionMatrix,0,-1f, 1f, -aspectRatio,aspectRatio,-1f, 1f); } }
-
最后我们根据矩阵描绘出图形,这里也是运用了
glUniformMatrix4fv
将矩阵信息传给了OpenGL然后由OpenGL绘制出矩阵对应的图像。@Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20.glUniformMatrix4fv(matrixLocation, 1, false, projectionMatrix, 0); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); }
-
🔗 前言
🔗 OpenGL ES 篇
🔗 NO.1 OpenGL ES 前言
🔗 NO.2 从OpenGL与GC的矛盾说起
🔗 NO.3 OpenGl 着色器-绘制
🔗 NO.5 OpenGl 第三维度
🔗 NO.6 OpenGl 纹理