OpenGL ES入门教程(三)之为平面桌子添加混合色

2023-12-03 16:28

本文主要是介绍OpenGL ES入门教程(三)之为平面桌子添加混合色,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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的颜色。

  • 三角形平面实现混合色,只需要给定三角形三个顶点的颜色,三角形内部其余的颜色都是由这三个顶点线性插值而得。对于三角形内任何给定的点,从那个点向每个顶点所对应的点画一条直线就可以生成三个内部三角形。这三个内部三角形的面积的比例决定了那个点上每种颜色的权重。如下图所示三角形,那个点上黄色的强度就取决于黄色顶点相对的那个内部三角形的面积。距离黄色顶点越近的点,它相对的三角形就越大,在那个点的片段就越显黄。
    在这里插入图片描述
    三角形内每个点的混合色线性插值的计算公式如下:
    在这里插入图片描述

说到底,就是最普通的线性插值,只是插值插的是颜色值而已,与我们上学时数学课上的线性插值一样(z=ax+by),相信稍微思考下就明白啦~,而且下面的混合色实现也不需要我们写公式,OpenGL都封装好了。

一、修改绘制的桌子结构

我们要实现效果类似在桌子中心上面吊一盏灯,越靠近桌子中心颜色越亮白,越远离桌子中心颜色越暗灰。那我们就要在桌子的中心放置一个顶点,且该处顶点颜色是纯白色,因此,长方形平面桌子应该有如下图所示的4个三角形组成,而上一篇文章中我们实现的平面桌面是由两个三角形组成的,因此我们应该先修改桌面的结构。在这里插入图片描述

1. 三角形扇介绍

一个三角形扇以一个中心顶点作为起始,使用相邻的两个顶点创建第一个三角形,接下来的每个顶点都会创建一个三角形,围绕起始的中心点按扇形展开。为了使这个扇形闭合,我们只需要在最后重复第二个点。

三角形扇完全可以实现我们上面所提到的由4个三角形构成的长方形,该三角形扇包含的顶点如下图所示,一共由5个顶点组成。
在这里插入图片描述

2. 基于三角形扇结构绘制平面桌子

  1. 上面提到三角形扇需要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};
  1. 调用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);}
  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,w)a_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_PointSize:OpenGL特定的变量名,用于存储点的大小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_FLOAT:OpenGL采用的数据类型,因为我们定义的是浮点数数组,所以采用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);//获取顶点着色器中代表顶点位置的属性(attribute)aPositionLocation = 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,切到本篇文章所讲解内容的完整示例代码。

这篇关于OpenGL ES入门教程(三)之为平面桌子添加混合色的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/450075

相关文章

Weex入门教程之4,获取当前全局环境变量和配置信息(屏幕高度、宽度等)

$getConfig() 获取当前全局环境变量和配置信息。 Returns: config (object): 配置对象;bundleUrl (string): bundle 的 url;debug (boolean): 是否是调试模式;env (object): 环境对象; weexVersion (string): Weex sdk 版本;appName (string): 应用名字;

Weex入门教程之3,使用 Vue 开发 Weex 页面

环境安装 在这里简略地介绍下,详细看官方教程 Node.js 环境 Node.js官网 通常,安装了 Node.js 环境,npm 包管理工具也随之安装了。因此,直接使用 npm 来安装 weex-toolkit。 npm 是一个 JavaScript 包管理工具,它可以让开发者轻松共享和重用代码。Weex 很多依赖来自社区,同样,Weex 也将很多工具发布到社区方便开发者使用。

Weex入门教程之2,Android Studio安装Weex插件

插件位置及描述 https://plugins.jetbrains.com/idea/plugin/8460-weex 貌似对windows还不是很支持,先放着吧。 安装 插件功能 先预览下都有什么功能 安装完成Weex插件后,如果在main toolbar找不到这些功能图标,那么就需要手动添加到main toolbar 添加到main toolbar 红框内就是

Weex入门教程之1,了解Weex

【资料合集】Weex Conf回顾集锦:讲义PDF+活动视频! PDF分享:链接:http://pan.baidu.com/s/1hr8RniG 密码:fa3j 官方教程:https://weex-project.io/cn/v-0.10/guide/index.html 用意 主要是介绍Weex,并未涉及开发方面,好让我们开始开发之前充分地了解Weex到底是个什么。 以下描述主要摘取于

ElasticSearch的DSL查询⑤(ES数据聚合、DSL语法数据聚合、RestClient数据聚合)

目录 一、数据聚合 1.1 DSL实现聚合 1.1.1 Bucket聚合  1.1.2 带条件聚合 1.1.3 Metric聚合 1.1.4 总结 2.1 RestClient实现聚合 2.1.1 Bucket聚合 2.1.2 带条件聚合 2.2.3 Metric聚合 一、数据聚合 聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。例如:

求空间直线与平面的交点

若直线不与平面平行,将存在交点。如下图所示,已知直线L过点m(m1,m2,m3),且方向向量为VL(v1,v2,v3),平面P过点n(n1,n2,n3),且法线方向向量为VP(vp1,vp2,vp3),求得直线与平面的交点O的坐标(x,y,z): 将直线方程写成参数方程形式,即有: x = m1+ v1 * t y = m2+ v2 * t

OPENGL顶点数组, glDrawArrays,glDrawElements

顶点数组, glDrawArrays,glDrawElements  前两天接触OpenGL ES的时候发现里面没有了熟悉的glBegin(), glEnd(),glVertex3f()函数,取而代之的是glDrawArrays()。有问题问google,终于找到答案:因为OpenGL ES是针对嵌入式设备这些对性能要求比较高的平台,因此把很多影响性能的函数都去掉了,上述的几个函数都被移除了。接

OpenGL ES学习总结:基础知识简介

什么是OpenGL ES? OpenGL ES (为OpenGL for Embedded System的缩写) 为适用于嵌入式系统的一个免费二维和三维图形库。 为桌面版本OpenGL 的一个子集。 OpenGL ES管道(Pipeline) OpenGL ES 1.x 的工序是固定的,称为Fix-Function Pipeline,可以想象一个带有很多控制开关的机器,尽管加工

OpenGL雾(fog)

使用fog步骤: 1. enable. glEnable(GL_FOG); // 使用雾气 2. 设置雾气颜色。glFogfv(GL_FOG_COLOR, fogColor); 3. 设置雾气的模式. glFogi(GL_FOG_MODE, GL_EXP); // 还可以选择GL_EXP2或GL_LINEAR 4. 设置雾的密度. glFogf(GL_FOG_DENSITY, 0

opengl纹理操作

我们在前一课中,学习了简单的像素操作,这意味着我们可以使用各种各样的BMP文件来丰富程序的显示效果,于是我们的OpenGL图形程序也不再像以前总是只显示几个多边形那样单调了。——但是这还不够。虽然我们可以将像素数据按照矩形进行缩小和放大,但是还不足以满足我们的要求。例如要将一幅世界地图绘制到一个球体表面,只使用glPixelZoom这样的函数来进行缩放显然是不够的。OpenGL纹理映射功能支持将