百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 博客教程 > 正文

一看就懂的OpenGL ES教程——这或许是你遇过最难画的三角形(四)

connygpt 2024-11-18 10:42 8 浏览

你知不知道

你知不知道

我等到花儿也谢了

绘制三角形已经到了第四篇了,然而三角形还是等不到踪影,不少读者已经开始按耐不住内心的躁动了,好消息来了,本文就将完成绘制三角形的任务

通过阅读本文,你将获得以下收获:

1.如何使用OpenGL es基本图元绘制点、线、三角形

2.如何使用OpenGL es更高级的图元绘制更复杂的图形

上篇回顾

上一篇博文一看就懂的OpenGL ES教程——这或许是你遇过最难画的三角形(三)重点介绍了图元和片段着色器以及OpenGL渲染指令,憋了这么久,今天开始,让我们一起体验渲染的快感~~

绘制图形

回顾下前几篇真正执行渲染的代码:

/**        此处开始将数据传入图形渲染管线              **/
    static float triangleVer[] = {
            0.8f, -0.8f, 0.0f,
            -0.8f, -0.8f, 0.0f,
            0.0f, 0.8f, 0.0f,
    };
    
     GLuint apos = static_cast<GLuint>(glGetAttribLocation(program, "aPosition"));
    glEnableVertexAttribArray(apos);
    glVertexAttribPointer(apos, 3, GL_FLOAT, GL_FALSE, 0, triangleVer);
    
     /**        此处结束将数据传入图形渲染管线              **/
     
      /**        此处开始将图像渲染到屏幕              **/

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
   
    eglSwapBuffers(display, winSurface);
    
     /**        此处结束图像渲染              **/

这里是渲染三角形的代码,glDrawArrays方法传入的图元类型是GL_TRIANGLE_STRIP,但是路要一步一步走,我们就先从最基本的绘制开始吧。

在前几篇给的代码中,使用的都是直接获取着色器变量名的方式: GLuint apos = static_cast<GLuint>(glGetAttribLocation(program, "aPosition"));

还记得在一看就懂的OpenGL ES教程——这或许是你遇过最难画的三角形(二)GLSL一章节中曾经提到过layout修饰符:

layout是GLSL的几个修饰符中的一个,一般用来指定变量布局的,可以说是着色器和客户端程序或者其他阶段着色器的通信接口

何为变量的位置?你可以想象每一个着色器程序是一层楼,每个需要对接外部的变量住在一个个房间中,假如你现在是客户端的C++程序,你想给着色器里面某个变量传参,然后你又不知道变量名字,如果此时你知道变量所在的房间编号,那你照样还是可以将数据传给变量,就像一个蹑手蹑脚的间谍,偷偷打开对应location的房门,偷偷将一份机密文件交给里面的人(location对应变量)。所以layout加location的作用已经很明显了,你不需要房间里面住着谁(不用知道变量名称),只需要知道房间号(location),也能按成变量数值的传递

(直到今日,我依旧想为我当初的比喻点赞)

于是在今天的例子,我们统一使用这个新特性吧~

C++音视频学习资料免费获取方法:关注音视频开发T哥,+「链接」即可免费获取2023年最新C++音视频开发进阶独家免费学习大礼包!

绘制点

点的图元类型为:

GL_POINTS

表示每个顶点在屏幕上都是单独的点(想想一个点确实也玩不出其他花了)

于是渲染代码变为:

//三个点坐标
    static float pointsVer[] = {
            0.8f, -0.8f, 0.0f,
            -0.8f, -0.8f, 0.0f,
            0.0f, 0.8f, 0.0f,
    };

//旧的传输数据方式,已经out了
//    GLuint apos = static_cast<GLuint>(glGetAttribLocation(program, "aPosition"));

//通过layout传输数据,传给了着色器中layout为0的变量
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, pointsVer);
    //打开layout为0的变量传输开关
    glEnableVertexAttribArray(0);

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
//从第0个顶点开始,取三个顶点,绘制成三个点到后备缓冲区
    glDrawArrays(GL_POINTS, 0, 3);
    //窗口显示,交换后备缓冲区到前台
    eglSwapBuffers(display, winSurface);

这里顶点属性数组传入的是6个浮点数,然后通过glVertexAttribPointer方法告知OpenGL如何解析这个顶点属性数组(如有不清楚,请看一看就懂的OpenGL ES教程——这或许是你遇过最难画的三角形(二)中的叙述),在这里,就是将三个顶点属性依次传给顶点着色器中layout为0的变量,那么顶点着色器现在是什么样子的呢:

        #version 300 es
        layout (location = 0) 
        in vec4 aPosition;//输入的顶点坐标,会在程序指定layout将数据输入到该字段

        void main() {
           //直接把传入的坐标值作为传入渲染管线。gl_Position是OpenGL内置的表示坐标的变量
            gl_Position = aPosition;   
            //点的尺寸
            gl_PointSize = 50.0;
        }"

注意这里需要指定点的尺寸,点在这里以正方形呈现,所以指定的就是正方形的边长

片段着色器和上一篇一摸一样,只是给当前片段赋颜色值:

       #version 300 es
       precision mediump float;
       out vec4 FragColor;

        void main() {
           //给当前片段赋颜色值
           FragColor = vec4(1.0,0.5,0.5,1.0);
        }

于是乎顶点着色器执行3次,得到三个顶点的最终坐标传到图形渲染管线中,执行完图元装配,光栅化之后,每个片段都执行一次片段着色器,于是乎再执行完渲染程序,三个小红点便跃然纸上:

那么绘制4个点呢?只要传入的顶点属性数组为4*3个,并通过glVertexAttribPointer方法告知OpenGL有4个顶点属性即可。以此类推~

绘制线段

说起绘制线段,OpenGL就开始展现他武器库之丰富了。

绘制线段的图元类型有3种,分别为:

GL_LINES                         
GL_LINE_LOOP                      
GL_LINE_STRIP   

三者的区别在上一篇文章图元装配一章已经有所提及:

如果现在传入顶点着色器的顶点数组的元素分别为:v0,v1,v2,v3,v4,v5,v6,v7,那么对应的图元效果图如下所示:

相信在做列位看官都能理解它们的区别了,接下来就实践分别瞥一瞥它们各自的风采。

这次传4个点,依次每种图元看看效果:

//四个点坐标
    static float lineVer[] = {
            0.8f, -0.8f, 0.0f,
            -0.8f, -0.8f, 0.0f,
            0.0f, 0.8f, 0.0f,
            0.4f, 0.8f, 0.0f,
    };

不过画线之前,别忘了要指定线段的宽度,不然宽度就是0,即一条抽象到看不见的线段。

//设置线段宽度
glLineWidth(20);

GL_LINES

glDrawArrays(GL_LINES, 0, 4);

从第0个顶点开始,读取4个顶点,每两个组成一对连成线

是屏幕下方两条红色横线,下面一条的顶点分别为0.8f, -0.8f, 0.0f-0.8f, -0.8f, 0.0f,上面的线段顶点分别为0.0f, 0.8f, 0.0f0.4f, 0.8f, 0.0f

GL_LINE_STRIP:

glDrawArrays(GL_LINE_STRIP, 0, 4);

这种是从第一个顶点开始一路连到到最后一个顶点

GL_LINE_LOOP

glDrawArrays(GL_LINE_LOOP, 0, 4);

还是这种给力,一路连成闭环

绘制三角形

画完线段,接下来就是开始令人兴奋的三角形了。而三角形,就更能体现OpenGL就开始展现他武器库之丰富,简直是东风快递、民兵、白杨皆有之。

顶点属性数组改为传入3个顶点属性(当然你要传4个也行,在后面读取的时候指定读取几个就可以了):

static float triangleVer[] = {
        0.8f, -0.8f, 0.0f,
        -0.8f, -0.8f, 0.0f,
        0.0f, 0.8f, 0.0f,
};

三角形的图元类型也是三种,我们也来一一领略一番:

三角形的就比较复杂了:

这是官网的解释:

第一种GL_TRIANGLES是每三个顶点就分别连成一个三角形,也就是说把顶点数组每三个为一组分,互相之间没有瓜葛

第二种GL_TRIANGLE_STRIP就比较牛逼了,从第0个顶点开始,每3个顶点连在一起形成三角形, v0,v1,v2为一个三角形,v1,v2,v3为一个三角形,v2,v3,v4为一个三角形依此类推。

如果顶点个数为n,则可以生成n-2个三角形

第三种GL_TRIANGLE_FAN是谁是第一个顶点谁就拥有优先的绘图权(排在第一位的果真是大佬),第一个顶点会和后面每2个顶点为一组绘制三角形。v0,v1,v2为一个三角形,v0,v2,v3为一个三角形,v0,v3,v4为一个三角形依此类推。最后形成一个扇形形状

用代码一一感受它们的风采吧:

首先用最简单的三个点绘制:

static float triangleVer[] = {
        0.8f, -0.8f, 0.0f,
        -0.8f, -0.8f, 0.0f,
        0.0f, 0.8f, 0.0f,
};
//对于三个点来说,GL_TRIANGLES,GL_TRIANGLE_STRIP和GL_TRIANGLE_FAN绘制结果都一样
glDrawArrays(GL_TRIANGLES, 0, 3);

开始玩点好玩的了

将传入的顶点属性数组改为6个元素

static float triangleVer[] = {
        0.8f, 0.8f, 0.0f,
        0.0f, 0.8f, 0.0f,
        0.4f, 0.4f, 0.0f,
        -0.8f, 0.5f, 0.0f,
        -0.4f, 0.8f, 0.0f,
        -0.8f, 0.8f, 0.0f,
};

绘制顶点数目也改为6:

glDrawArrays(GL_TRIANGLES, 0, 6);

尝试下GL_TRIANGLE_STRIP

惊奇发现已经面目全非了,几乎看不到三角形的痕迹了。

再看下GL_TRIANGLE_FAN

更加没有三角形痕迹了,v5还被抛弃了什么鬼。

为什么呢?按照前面对GL_TRIANGLE_FAN的讲解,v0,v4,v5会连成一个三角形,不过仔细看坐标就会发现,它们三个点是在一条直线上的,连不了三角形,索性直接抛弃了v5

其实OpenGL之前是有四边形的图元类型的,但是在OpenGL3.1之后就被移除了,那这次就不讲了,那么问题来了,四边形要怎么绘制呢?

C++音视频学习资料免费获取方法:关注音视频开发T哥,+正在跳转即可免费获取2023年最新C++音视频开发进阶独家免费学习大礼包!

其实答案已经在上面了,通过GL_TRIANGLE_STRIP或者GL_TRIANGLE_FAN,只要给四个任何三个点不共线的点,就可以绘制出来。

三角形是最基本的图形,三角形三个点必然是共面的,所以在OpenGL的世界里,任何图形都可以通过三角形来构建。

举个例子,画个正方形瞧瞧?

static float triangleVer[] = {
        0.8f, 0.8f, 0.0f,
        0.8f, -0.8f, 0.0f,
        -0.8f, 0.8f, 0.0f,
        -0.8f, -0.8f, 0.0f,
};

使用GL_TRIANGLE_STRIP绘制:

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

show you the rectangle:

嗯?说好的正方形怎么变成长方形了。坐标上确实是正方形,但是因为坐标是按照比例系数传的并且手机屏幕是长方形的,所以无奈被拉长。不过也是有办法解决的,后面讲矩阵的博文就告诉你们答案。

总结

本文主要详细介绍了OpenGL es各种基本图元的绘制,通过本文的学习,各种基本图图元的绘制相信不在话下了,而且通过一些图元类型还可以玩出一些花了。现在距离一看就懂的OpenGL ES教程——这或许是你遇过最难画的三角形(一)中绘制三角形的终极任务只差那种看起来酷毙的绚烂的渐变色彩了,别急,还是那句话,*欲知后事如何*,*且听下回分解* 哈哈。下一篇文章一看就懂的OpenGL ES教程——这或许是你遇过最难画的三角形(五)

代码地址

opengl-es-study-demo (不断更新中)

参考

OpenGL官网Primitives Learn OpenGL

作者:半岛铁盒里的猫 链接:https://juejin.cn/post/7144335420644392991 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在开发的路上你不是一个人,欢迎加入C++音视频开发交流群「链接」大家庭讨论交流!

相关推荐

自学Python,写一个挨打的游戏代码来初识While循环

自学Python的第11天。旋转~跳跃~,我~闭着眼!学完循环,沐浴着while的光芒,闲来无事和同事一起扯皮,我说:“编程语言好神奇,一个小小的循环,竟然在生活中也可以找到原理和例子”,同事也...

常用的 Python 工具与资源,你知道几个?

最近几年你会发现,越来越多的人开始学习Python,工欲善其事必先利其器,今天纬软小编就跟大家分享一些常用的Python工具与资源,记得收藏哦!不然下次就找不到我了。1、PycharmPychar...

一张思维导图概括Python的基本语法, 一周的学习成果都在里面了

一周总结不知不觉已经自学Python一周的时间了,这一周,从认识Python到安装Python,再到基本语法和基本数据类型,对于小白的我来说无比艰辛的,充满坎坷。最主要的是每天学习时间有限。只...

三日速成python?打工人,小心钱包,别当韭菜

随着人工智能的热度越来越高,许多非计算机专业的同学们也都纷纷投入到学习编程的道路上来。而Python,作为一种相对比较容易上手的语言,也越来越受欢迎。网络上各类网课层出不穷,各式广告令人眼花缭乱。某些...

Python自动化软件测试怎么学?路线和方法都在这里了

Python自动化测试是指使用Python编程语言和相关工具,对软件系统进行自动化测试的过程。学习Python自动化测试需要掌握以下技术:Python编程语言:学习Python自动化测试需要先掌握Py...

Python从放弃到入门:公众号历史文章爬取为例谈快速学习技能

这篇文章不谈江流所专研的营销与运营,而聊一聊技能学习之路,聊一聊Python这门最简单的编程语言该如何学习,我完成的第一个Python项目,将任意公众号的所有历史文章导出成PDF电子书。或许我这个Py...

【黑客必会】python学习计划

阅读Python文档从Python官方网站上下载并阅读Python最新版本的文档(中文版),这是学习Python的最好方式。对于每个新概念和想法,请尝试运行一些代码片段,并检查生成的输出。这将帮助您更...

公布了!2025CDA考试安排

CDA数据分析师报考流程数据分析师是指在不同行业中专门从事行业数据搜集、整理、分析依据数据作出行业研究评估的专业人员CDA证书分为1-3级,中英文双证就业面广,含金量高!!?报考条件:满18...

一文搞懂全排列、组合、子集问题(经典回溯递归)

原创公众号:【bigsai】头条号:程序员bigsai前言Hello,大家好,我是bigsai,longtimenosee!在刷题和面试过程中,我们经常遇到一些排列组合类的问题,而全排列、组合...

「西法带你学算法」一次搞定前缀和

我花了几天时间,从力扣中精选了五道相同思想的题目,来帮助大家解套,如果觉得文章对你有用,记得点赞分享,让我看到你的认可,有动力继续做下去。467.环绕字符串中唯一的子字符串[1](中等)795.区...

平均数的5种方法,你用过几种方法?

平均数,看似很简单的东西,其实里面包含着很多学问。今天,分享5种经常会用到的平均数方法。1.算术平均法用到最多的莫过于算术平均法,考试平均分、平均工资等等,都是用到这个。=AVERAGE(B2:B11...

【干货收藏】如何最简单、通俗地理解决策树分类算法?

决策树(Decisiontree)是基于已知各种情况(特征取值)的基础上,通过构建树型决策结构来进行分析的一种方式,是常用的有监督的分类算法。决策树算法是机器学习中的一种经典算法,它通过一系列的规则...

面试必备:回溯算法详解

我们刷leetcode的时候,经常会遇到回溯算法类型题目。回溯算法是五大基本算法之一,一般大厂也喜欢问。今天跟大家一起来学习回溯算法的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~什么是回溯...

「机器学习」决策树——ID3、C4.5、CART(非常详细)

决策树是一个非常常见并且优秀的机器学习算法,它易于理解、可解释性强,其可作为分类算法,也可用于回归模型。本文将分三篇介绍决策树,第一篇介绍基本树(包括ID3、C4.5、CART),第二篇介绍Ran...

大话AI算法: 决策树

所谓的决策树算法,通俗的说就是建立一个树形的结构,通过这个结构去一层一层的筛选判断问题是否好坏的算法。比如判断一个西瓜是否好瓜,有20条西瓜的样本提供给你,让你根据这20条(通过机器学习)建立起...