怎么用优盘做网站登录密钥,叮当app制作官网,山西省建设工程信息网,内蒙古包头做网站的公司OpenGL ES入门教程#xff08;三#xff09;之为平面桌子添加渐变色 前言零、OpenGL ES实现混合色的原理一、修改绘制的桌子结构1. 三角形扇介绍2. 基于三角形扇结构绘制平面桌子 二、为每个顶点添加颜色属性三、修改着色器1. 顶点着色器2. 片段这色器 四、绘制具有混合颜色的… OpenGL ES入门教程三之为平面桌子添加渐变色 前言零、OpenGL ES实现混合色的原理一、修改绘制的桌子结构1. 三角形扇介绍2. 基于三角形扇结构绘制平面桌子 二、为每个顶点添加颜色属性三、修改着色器1. 顶点着色器2. 片段这色器 四、绘制具有混合颜色的平面桌子1. 计算跨度2. 关联顶点位置数据和颜色数据3. 绘制图形 五、完整示例代码下载 前言
上一篇文章我们讲解了OpenGL ES如何绘制一个平面桌子本文在其基础上继续讲解如何使绘制的平面桌子具有混合色效果类似在桌子中心上面吊一盏灯越靠近桌子中心颜色越亮白越远离桌子中心颜色越暗灰。如果是OpenGL ES小白在阅读本篇文章之前一定要搞懂上篇文章OpenGL ES入门教程二之绘制一个平面桌子
零、OpenGL ES实现混合色的原理
首先混合色指的是将两种及以上的颜色进行混合而得出的其它颜色。之前的文章中我们讲过OpenGL只有点线三角形三种基本图元其余图元都是有这三种基本图元构成。很明显只有线和三角形这两种图元有实现混合色的意义混合色最常见的实现方式就是对颜色进行线性插值OpenGL实现混合色的原理也是如此。 一条直线实现混合色只需要给定直线两个顶点的颜色线其余的颜色都是由这两个顶点线性插值而得。混合色结果取决于线上的位置与两个顶点之间的距离线上的位置越接近哪个顶点那混合色就越倾向于哪个顶点的颜色。直线上各个位置通过线性插值计算的混合色的公式如下 可以看到distance_ratio的值越大vertex_1_value所占的比重就越大而对应vertex_0_value所占的比重就越小即distance_ratio的值越大颜色越接近于vertex_1_value的颜色。 三角形平面实现混合色只需要给定三角形三个顶点的颜色三角形内部其余的颜色都是由这三个顶点线性插值而得。对于三角形内任何给定的点从那个点向每个顶点所对应的点画一条直线就可以生成三个内部三角形。这三个内部三角形的面积的比例决定了那个点上每种颜色的权重。如下图所示三角形那个点上黄色的强度就取决于黄色顶点相对的那个内部三角形的面积。距离黄色顶点越近的点它相对的三角形就越大在那个点的片段就越显黄。 三角形内每个点的混合色线性插值的计算公式如下
说到底就是最普通的线性插值只是插值插的是颜色值而已与我们上学时数学课上的线性插值一样zaxby相信稍微思考下就明白啦~而且下面的混合色实现也不需要我们写公式OpenGL都封装好了。
一、修改绘制的桌子结构
我们要实现效果类似在桌子中心上面吊一盏灯越靠近桌子中心颜色越亮白越远离桌子中心颜色越暗灰。那我们就要在桌子的中心放置一个顶点且该处顶点颜色是纯白色因此长方形平面桌子应该有如下图所示的4个三角形组成而上一篇文章中我们实现的平面桌面是由两个三角形组成的因此我们应该先修改桌面的结构。
1. 三角形扇介绍
一个三角形扇以一个中心顶点作为起始,使用相邻的两个顶点创建第一个三角形,接下来的每个顶点都会创建一个三角形围绕起始的中心点按扇形展开。为了使这个扇形闭合我们只需要在最后重复第二个点。
三角形扇完全可以实现我们上面所提到的由4个三角形构成的长方形该三角形扇包含的顶点如下图所示一共由5个顶点组成。
2. 基于三角形扇结构绘制平面桌子
上面提到三角形扇需要5个顶点同时由于为了使得三角形扇闭合我们需要重复第二个顶点使其成为最后一个顶点因此平面桌子的坐标数据修改如下
float[] tableVerticesWithTriangles {/**无论是x还是y坐标OpenGL都会把屏幕映射到[-1,1]的范围内。即屏幕的左边对应x轴的-1右边对应1;屏幕的底边对应y轴的-1顶边对应1*/// Triangle Fan0f, 0f,//三角形扇的中心点坐标-0.5f, -0.5f,//三角形扇第二个顶点坐标0.5f, -0.5f,0.5f, 0.5f,-0.5f, 0.5f,-0.5f, -0.5f,//三角形扇必须封闭因此这个就是第二个顶点坐标// Line 1-0.5f, 0f,0.5f, 0f,// Mallets0f, -0.25f,0f, 0.25f};调用glDrawArrays方法第一个参数选择GL_TRIANGLE_FAN绘制三角形扇即可平面桌子的绘制代码如下 Overridepublic void onDrawFrame(GL10 gl) {glClear(GL_COLOR_BUFFER_BIT);/*绘制桌子*///更新着色器中u_Color的值蓝色glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);//参数1绘制三角形扇参数2从顶点数组的开头开始读顶点参数3读取6个顶点//之前glVertexAttribPointer告诉过OpenGL每个顶点的位置包含两个浮点分量因此OpenGL会使用vertexData中如下12个浮点数glDrawArrays(GL_TRIANGLE_FAN, 0, 6);/*绘制分割线*///更新u_Color的值红色glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f);//参数1绘制直线 参数2从顶点数组的第6个顶点之后即第7个顶点开始读取参数3读取两个顶点glDrawArrays(GL_LINES, 6, 2);/*绘制两个木槌*///更新u_Color的值黑色glUniform4f(uColorLocation, 0.0f, 0.0f, 0.0f, 1.0f);glDrawArrays(GL_POINTS, 8, 1);//更新u_Color的值绿色glUniform4f(uColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);glDrawArrays(GL_POINTS, 9, 1);}此时运行代码结果和上一篇文章绘制的平面桌子效果一致只是长方形的结构由两个三角形组成变成了由4个三角形组成而已。
二、为每个顶点添加颜色属性
我们之前在数组中记录了每个顶点的位置坐标数据同理我们也可以再定义一个数组对应记录每个顶点的颜色数据。但为了数据处理更加高效我们不用另外再定义一个数组存储颜色数据完全可以把顶点的位置数据和颜色数据存储在同一个数组中。包含顶点位置坐标数据和颜色数据的数组如下每个顶点包含x,y两个位置坐标数据紧邻其后是r,g,b三个颜色分量数据。 float[] tableVerticesWithTriangles {/**无论是x还是y坐标OpenGL都会把屏幕映射到[-1,1]的范围内。即屏幕的左边对应x轴的-1右边对应1;屏幕的底边对应y轴的-1顶边对应1*/// Triangle Fan0f, 0f, 1f, 1f, 1f,//前两位是三角形扇的中心点坐标后面三位是代表rgb的颜色分量此处代表的颜色是白色-0.5f, -0.5f, 0.7f, 0.7f, 0.7f,//三角形扇第二个顶点坐标0.5f, -0.5f, 0.7f, 0.7f, 0.7f,0.5f, 0.5f, 0.7f, 0.7f, 0.7f,-0.5f, 0.5f, 0.7f, 0.7f, 0.7f,-0.5f, -0.5f, 0.7f, 0.7f, 0.7f,//三角形扇必须封闭因此这个就是第二个顶点坐标// Line 1-0.5f, 0f, 1f, 0f, 0f,//顶点颜色是红色0.5f, 0f, 0f, 1f, 0f,//顶点颜色是绿色// Mallets0f, -0.25f, 0f, 0f, 1f,//顶点颜色是蓝色0f, 0.25f, 1f, 0f, 0f//顶点颜色是红色};三、修改着色器
1. 顶点着色器
顶点带有颜色属性的顶点着色器代码如下。 加入了a_Color颜色属性和v_Color混合颜色属性a_Color存储顶点的颜色v_Color用于实现颜色的线性插值为片段生成混合色。可以理解为咱们在第零章讲解的混合色原理OpenGL通过varying这种特殊标记实现了。
/*
attribute:属性数据的特定标识
vec4:一种包含4个分量的向量数据类型x,y,z,wa_Position中x,y,z代表顶点的三维位置坐标w是一个特殊坐标后面会讲解
a_Position:变量名称该名称后面OpenGL的glGetAttribLocation方法要用到如果修改后面就要一起修改
*/
attribute vec4 a_Position;//代表位置的属性数据x,y,z,w
attribute vec4 a_Color;//代表颜色的属性数据(r,g,b,a)/*
varying一种特殊的变量类型它把给它的哪些值进行混合并把这些混合的值发送给片段着色器。
其实所谓混合就是通过线性插值方法生成片段中除了顶点之外的其它颜色。
例如生成直线的片段是由两个顶点构成顶点0的a_Color是红色顶点1的a_Color是绿色通过将a_Color赋值给varying这种特殊类型的变量
就可以使得越靠近顶点0的直线片段颜色越红越靠近顶点1的直线片段颜色越绿。
*/
varying vec4 v_Color;//和C语言类似main函数是着色器的入口函数
void main()
{//将颜色数据赋值给varying类型的变量v_Color a_Color;//gl_Position OpenGL特定的变量名用于存储我们定义的顶点数据gl_Position a_Position;//gl_PointSizeOpenGL特定的变量名用于存储点的大小gl_PointSize 10.0;
}
2. 片段这色器
为片段生成混合颜色的片段着色器代码如下。 将uniform标识的一个片段只有一个颜色的属性修改为varying标识的混合颜色属性这个属性与顶点着色器定义的varying属性相对应属性名必须一致。
//OpenGL定义float数据类型的精度lowp;mediump;highp就像java代码中浮点型选择float类型还是double类型。
//精度是以性能为代价的这里选择mediump
precision mediump float;varying vec4 v_Color;//通过线性插值顶点颜色形成混合颜色这个参数名必须与顶点着色器中的参数名一致//和C语言类似main函数是着色器的入口函数
void main()
{gl_FragColor v_Color;
}
四、绘制具有混合颜色的平面桌子
1. 计算跨度
上一篇文章中我们讲解到通过glVertexAttribPointer方法将顶点位置与着色器进行关联该方法中有一个跨度参数stride我们直接赋值为0并没有对其进行详细讲解因为那时数组中只存储了顶点位置坐标数据不包含颜色属性数据因此OpenGL只需要一个顶点数据挨着一个顶点数据的读取就能得到每个顶点的正确位置坐标数据。 //获取顶点着色器中attribute位置属性aPositionLocation glGetAttribLocation(program, A_POSITION);//告诉OpenGL从vertexData中读取a_Position的数据vertexData.position(0);//将缓冲区数据中的指针指向第一个数据即从第一个数据开始读/*public static void glVertexAttribPointer(int indx,int size,int type,boolean normalized,int stride,java.nio.Buffer ptr)将着色器中的位置属性与本地顶点数据相关联。aPositionLocation着色器中定义的位置属性POSITION_COMPONENT_COUNT每次从本地数组中读取两个数据即x,y代表一个顶点坐标GL_FLOATOpenGL采用的数据类型因为我们定义的是浮点数数组所以采用GL_FLOATvertexData要关联的本地数据列表*/glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,false, 0, vertexData);但是现在我们的每个顶点不仅存储了位置坐标数据同时存储了颜色属性数据因此第一个顶点的位置坐标数据和第二个顶点的位置坐标数据之间多个三个颜色属性数据为了正常的获得每个顶点的位置坐标数据我们需要把中间的颜色属性数据跨过去所以才有了跨度stride这个参数。因为现在我们每个顶点位置坐标数据直接插入了三个颜色属性数据因此下一个顶点的位置坐标数据需要跨过上一个顶点中的两个位置坐标数据和3个颜色属性数据因此跨距stride计算方式如下跨距的单位是字节 //每个float由4个字节组成private static final int BYTES_PER_FLOAT 4;//每个顶点前两个浮点数代表位置x,yprivate static final int POSITION_COMPONENT_COUNT 2;//每个顶点后三个浮点数代表颜色r,g,bprivate static final int COLOR_COMPONENT_COUNT 3;//STRIDE代表每个顶点位置之间间隔多少个字节因为现在顶点位置和顶点颜色数据混在一起只有明确跨度才能查找到每个顶点的位置private static final int STRIDE (POSITION_COMPONENT_COUNT COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;2. 关联顶点位置数据和颜色数据
通过glVertexAttribPointer函数将数组中存储的顶点数据与着色器中的属性相关联 //获取顶点着色器中代表顶点颜色的属性aColorLocation glGetAttribLocation(program, A_COLOR);//获取顶点着色器中代表顶点位置的属性attributeaPositionLocation glGetAttribLocation(program, A_POSITION);//告诉OpenGL从vertexData中读取a_Position的数据vertexData.position(0);//将缓冲区数据中的指针指向第一个顶点的位置数据开始的位置glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,false, STRIDE, vertexData);//使能顶点数组glEnableVertexAttribArray(aPositionLocation);//告诉OpenGL从vertexData中读取a_Color的数据vertexData.position(POSITION_COMPONENT_COUNT); //将缓冲区中的指针指向第一个顶点的颜色数据开始的位置glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,false, STRIDE, vertexData);//使能顶点数组glEnableVertexAttribArray(aColorLocation);3. 绘制图形
现在每个顶点都有了自己的颜色并且采用varying实现片段的混合色因此不要再调用glUniform4f方法为片段设置颜色了每个片段的颜色都会由顶点插值而得。 Overridepublic void onDrawFrame(GL10 gl) {glClear(GL_COLOR_BUFFER_BIT);/*绘制桌子*///参数1绘制三角形扇参数2从顶点数组的开头开始读顶点参数3读取6个顶点//之前glVertexAttribPointer告诉过OpenGL每个顶点的位置包含两个浮点分量因此OpenGL会使用vertexData中12个浮点数glDrawArrays(GL_TRIANGLE_FAN, 0, 6);/*绘制分割线*///参数1绘制直线 参数2从顶点数组的第6个顶点之后即第7个顶点开始读取参数3读取两个顶点glDrawArrays(GL_LINES, 6, 2);glLineWidth(10); //设置线宽不设置线宽无法体现线的渐变颜色/*绘制两个木槌*/glDrawArrays(GL_POINTS, 8, 1);glDrawArrays(GL_POINTS, 9, 1);}运行代码绘制图形效果如下图所示
五、完整示例代码下载
完整的代码都上传到了Gitee仓库 OpenGL_ES_DEMO中仓库代码具有详细的提交记录博友可以执行git命令 git reset --hard f5081f05963ed48b4d149d4f9bc8476ee81caac8切到本篇文章所讲解内容的完整示例代码。