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 Fan
                0f, 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,

                // Mallets
                0f, -0.25f,
                0f,  0.25f
        };
  1. 调用glDrawArrays方法,第一个参数选择GL_TRIANGLE_FAN绘制三角形扇即可,平面桌子的绘制代码如下
	@Override
    public 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 Fan
                0f,    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,//顶点颜色是绿色

                // Mallets
                0f, -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_FLOAT
        vertexData:要关联的本地数据列表
        */
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, 0, vertexData);

但是,现在我们的每个顶点不仅存储了位置坐标数据,同时存储了颜色属性数据,因此,第一个顶点的位置坐标数据和第二个顶点的位置坐标数据之间多个三个颜色属性数据,为了正常的获得每个顶点的位置坐标数据,我们需要把中间的颜色属性数据跨过去,所以,才有了跨度stride这个参数。因为,现在我们每个顶点位置坐标数据直接插入了三个颜色属性数据,因此下一个顶点的位置坐标数据需要跨过上一个顶点中的两个位置坐标数据和3个颜色属性数据,因此跨距stride计算方式如下(跨距的单位是字节):

	//每个float由4个字节组成
	private static final int BYTES_PER_FLOAT = 4;
 	//每个顶点前两个浮点数代表位置:x,y
    private static final int POSITION_COMPONENT_COUNT = 2;
    //每个顶点后三个浮点数代表颜色:r,g,b
    private 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方法为片段设置颜色了,每个片段的颜色都会由顶点插值而得。

	@Override
    public 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,切到本篇文章所讲解内容的完整示例代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/212779.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微前端实战:打造高效、灵活的前端应用架构

文章目录 一、微前端简介二、微前端的优势1. 高度模块化2. 独立部署3. 易于扩展4. 技术栈无关5. 独立升级 三、微前端的原理四、微前端案例思路《微前端实战》编辑推荐内容简介作者简介目录前言/序言 随着互联网行业的快速发展,前端应用的规模和复杂度也在不断增加。…

k8s部署es和skywalking

使用k8s部署es和skywalking skywalking介绍 skywalking架构 整个架构,分成上、下、左、右四部分: 上部分 Agent :负责从应用中,收集链路信息,发送给 SkyWalking OAP 服务器。目前支持 SkyWalking、Zikpin、Jaeger 等…

美甲美睫店预约会员管理小程序作用如何

美甲美睫是美业中较为重要的类目,主要以小摊、门店/连锁形式,随着线上化程度加深,传统线下美业店面临着困境,想要进一步增长及解决痛点,就需要线上数字化运营得到更多生意。 那么通过【雨科】平台搭建美甲美睫店小程序…

CyclicBarrier实战应用——批量数据多线程协调异步处理(主线程执行事务回滚)

😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: CCyclicBarrier实战应用——批量数据多线程协调异步处理(主线程执行事务…

多级缓存自用

1.什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,如图: 存在下面的问题: •请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈 •Redis缓存失效时,会对数据库产生冲击 多级缓存就是充分利用请求处理的每个环节,添加缓…

MDK提示:在多字节的目标代码中,没有此Unicode 字符可以映射到的字符

MDK警告提示在多字节的目标代码中,没有此Unicode 字符可以映射到的字符 警告提示: 在写MDK的工程代码时,发现代码中引入的头文件前方出现一些红色的叉叉,但是编译工程并不报错,功能也能正常执行的,只是提…

使用VC++设计程序实现K近邻中值滤波器(KNNMF)、最小均方差滤波器、矢量中值滤波算法进行滤波

VC实现若干种图像滤波技术2 获取源工程可访问gitee可在此工程的基础上进行学习。 该工程的其他文章: 01- 一元熵值、二维熵值 02- 图像平移变换,图像缩放、图像裁剪、图像对角线镜像以及图像的旋转 03-邻域平均平滑算法、中值滤波算法、K近邻均值滤波器 …

大学程序员的养生之道

呀哈喽,我是结衣。 今天给大家带来的是大学程序员的养生之道! 作为一名大学生还没有深刻的感受到未来的恐怖,但每当我看到这些对程序员的评价还是不禁感慨。 不要让自己的学习之路变成这样啊!程序员的职业发展:某编程语…

微机原理——并行接口8255学习1

目录 并行接口特点 可编程并行接口芯片8255 8255端口地址 8255的三种工作方式 8255的两种命令(方式命令和C端口命令) 由用户扩展的并行接口8255的应用 声光报警器接口设计 步进电机控制接口设计 PA端口实现跑马灯 PB端口实现按键输入 并行接口特…

Python第三方库版本管理(管理虚拟环境)

序言 最近使用python发现会有使用不同项目时需要的三方包依赖版本不同,如果各个项目相互切换,那么会经常需要更新版本。比如numpy当前版本时1.26.2,需要它小于版本1.21,有没有像Java一样通过Maven依赖管理中的版本控制去管理这些…

Linguistic Steganalysis in Few-Shot Scenario论文阅读笔记

TIFS期刊 A类期刊 新知识点 Introduction Linguistic Steganalysis in Few-Shot Scenario模型是个预训练方法。 评估了四种文本加密分析方法,TS-CSW、TS-RNN、Zou、SeSy,用于分析和训练的样本都由VAE-Stego生产(编码方式使用AC编码)。 实验是对比在少样…

JavaWeb(二)

一、SQL简介 结构化查询语言,一门操作关系型数据库的编程语言。英文:Structured Query Language,简称 SQL。 二、Mysql和Oracle关于区分大小写 MySQL在Windows下都不区分大小写。 oracle中分为两种情况,单纯的sql语句不区分大小…

深入理解网络非阻塞 I/O:NIO

🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏&…

非标设计之螺纹螺丝选型二

目录 一、螺丝的表面处理工艺:镀锌工艺:渗锌工艺:热浸锌工艺:达克罗工艺:镀镍工艺:氧化(发黑)工艺:电泳黑工艺:不锈钢螺钉: 二、按照颜色分工艺&a…

掌握视频剪辑技巧,轻松自定义视频速率,打造个性化出彩视频

你是否曾经因为视频节奏平淡而缺乏吸引力而苦恼?现在,我们为你推荐一款视频批量剪辑工具,让你轻松自定义视频速率,实现出彩个性化视频。 首先第一步,我们要打开好简单批量智剪,并登录账号。 第二步&#x…

三十五、Seata的基本架构、部署TC服务、微服务集成Seata

目录 一、基本架构 1、Seata事务中的三个重要角色 2、四种不同的分布式事务解决方案: 二、TC的部署 三、微服务集成Seata 1、引入Seata相关依赖 2、配置yml文件 3、启动服务 一、基本架构 Seata是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决…

centos7 yum安装mysql5.7

1.获取源 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 2.安装源 yum -y install mysql57-community-release-el7-11.noarch.rpm 3.安装mysql yum -y install mysql-server 4.如果出现下面错误,没有错误就忽略 使用以下命令解决…

如何在Rocky Linux中安装nmon

一、环境基础 [rootlocalhost nmon16d]# cat /etc/redhat-release Rocky Linux release 9.2 (Blue Onyx) [rootlocalhost nmon16d]# uname -r 5.14.0-284.11.1.el9_2.x86_64 [rootlocalhost nmon16d]# 二、安装步骤 在Rocky Linux和AlmaLinux等基于RHEL 的发行版上&#xff…

把握生成式AI新机遇,亚马逊云科技助力下一位独角兽

文章目录 前言亚马逊云科技生成式AI创业热潮向应用与工具链集中生成式AI初创生而全球化 赛道更细分、布局更广阔后记 前言 DoNews11月20日消息,当一项新技术出现,并成为行业主流甚至是变革的“敲门砖”时,企业应该如何应对? 202…

Zookeeper 安装与部署

Zookeeper官网 目录 1 配置文件参数解读2 Zookeeper 单点安装3 Zookeeper 分布式安装 1 配置文件参数解读 Zookeeper 中的配置文件 zoo.cfg 中参数含义解读如下: (1)tickTime 2000:通信心跳数,Zookeeper 服务器与客户…