OpenGL ES 着色器(5)

OpenGL ES 着色器(5)

简述

着色器是在GPU上运行的程序,它会对每一个点都执行一次程序,并且计算出每个像素需要渲染的颜色,我们主要关注着色器的怎么传递数据,在OpenGL ES中,着色器传递数据分几种场景,一种是Cpu传递数据给GPU,一种是顶点缓冲区的数据传递到着色器,还有一种是顶点着色器数据传递给片段着色器。
着色器主要有三种类型传递数据参数:

  • attribute,用于顶点缓冲区数据传递到着色器中。
  • uniform,统一变量,由CPU将数据传递到GPU。
  • varying,用于顶点着色器数据向片段着色器传递。

着色器使用

我们以实现一个颜色渐变的圆形来介绍着色器的使用。
我们之前说过OpenGL渲染都是以三角形为基础的,那应该怎么渲染圆形呢,我的第一反应就是高数里微积分,通过无数个三角形拼接起来,不过这个方案有个问题,我们需要使用多少个三角形才合适,才能让圆形足够圆滑。
虽然GPU更善于执行计算,但是其实GPU也是可以处理逻辑的,所以其实只需要在着色器里做一个简单的逻辑就可以了。
所以我们的思路就是绘制一个正方形,在片段着色器里判断坐标,如果坐标在圆形范围内则为白色, 否则就配置透明的颜色,这样就可以渲染出一个圆形了。

在开始之前,我们需要了解用到的顶点着色器和片段着色器。

顶点着色器

顶点着色器主要用于获取顶点数据,一般是从顶点缓冲区中获取,里面有内置变量gl_Position作为顶点位置的输出,顶点着色器在读取顶点数据并且做预处理后,可以将坐标信息给gl_Position作为输出。
顶点着色器会对每一个顶点都执行一次。

片段着色器

片段着色器用于计算输出的颜色,有一个内置变量gl_FragColor,作为颜色的输出,片段着色器会对每一个像素都执行一次,然后返回该像素需要显示的颜色。
片段着色器可以获取从顶点着色器中获取数据,这里传递数据有两种模式,区别为是否插值,默认是平滑的,会插值的。(就是说几个顶点中的数据会根据坐标线性平滑的渐变,我们之前在顶点缓冲区章节的渐变色三角形demo就是这个原理)

我们想要实现圆形的判断逻辑,需要在片段着色器中处理逻辑,因为片段着色器会对每个像素执行一次。

顶点数据

我们顶点数据为四个顶点,每个顶点7个数据,前三个是坐标,后四个是颜色。
使用索引缓冲区,这里和之前绘制正方形的demo差不多,这里坐标覆盖了全屏幕,作用相当于画板,获取我们会通过一个统一变量来控制圆形半径。

private float[] vertexArray = new float[] {-1.0f, -1.0f, 0.0f, 1f, 1f, 1f, 1f,1.0f, -1.0f, 0.0f, 1f, 1f, 1f, 1f,-1.0f, 1.0f, 0.0f, 1f, 1f, 1f, 1f,1.0f, 1.0f, 0.0f, 1f, 1f, 1f, 1f
};private short[] indexArray = new short[] {0,1,2,1,2,3
};

着色器代码

顶点着色器逻辑:
两个属性,vPosition是坐标,除了直接传给gl_Position外,还通过一个varying的变量传给片段着色器vertexPosition,我们说过这个参数传递默认是会插值的,所以片段着色器拿到的值相当于每个点的坐标。
属性inputColor是从顶点缓冲区中拿的数据,用作颜色,这里通过一个varying变量outputColor传给片段着色器。

private final String vertexShaderCode ="attribute vec4 vPosition;" +"attribute vec4 inputColor;" +"varying vec4 outputColor;" +"varying vec4 vertexPosition;" +"void main() {" +"  gl_Position = vPosition;" +"  vertexPosition = vPosition;" +"  outputColor = inputColor;" +"}";

片段着色器逻辑:
这里有两个传过来的参数,一个为vertexPosition,为像素点坐标位置,一个为outputColor,作为输出颜色。
还有一个统一变量radius作为圆形半径,我们以(0,0)为圆形,这里一个简单几何逻辑,x * x + y * y < radius * radius的部分就是圆形部分,属于圆形部分颜色输出outputColor,否则输出一个透明色。

private final String fragmentShaderCode ="precision mediump float;" +"varying vec4 vertexPosition;" +"varying vec4 outputColor;" +"uniform float radius;" +"void main() {" +"  if (vertexPosition.x * vertexPosition.x + vertexPosition.y * vertexPosition.y > radius * radius) {" +"    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);" +"  } else {" +"    gl_FragColor = outputColor;" +"  }" +"}";

顶点缓冲区数据填充

这里的逻辑和之前正方形绘制基本一样,就不细说了。

public void onSurfaceCreated(GL10 gl, EGLConfig config) {// 清除颜色GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);// 创建顶点缓冲区int[] idBuffer = new int[2];GLES30.glGenBuffers(2, idBuffer, 0);vertexBufferId = idBuffer[0];elementBufferId = idBuffer[1];// 顶点缓冲区数据填充FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertexArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();vertexBuffer.put(vertexArray);vertexBuffer.position(0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,vertexArray.length * 4,vertexBuffer,GLES30.GL_STATIC_DRAW);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);ShortBuffer indexBuffer = ByteBuffer.allocateDirect(indexArray.length * 4).order(ByteOrder.nativeOrder()).asShortBuffer();indexBuffer.put(indexArray);indexBuffer.position(0);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId);GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,indexArray.length * 4,indexBuffer,GLES30.GL_STATIC_DRAW);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);// shadershaderProgramId = initShaderProgram(vertexShaderCode, fragmentShaderCode);
}

顶点布局以及渲染

配置顶点缓冲区布局,前三个数作为坐标,后4个数作为颜色。
设置统一变量radius,作为圆形半径。

public void onDrawFrame(GL10 gl) {// 清除屏幕GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);// 使能着色器程序GLES30.glUseProgram(shaderProgramId);// 顶点缓冲区每个顶点前3个数作为坐标GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);int positionLocation = GLES30.glGetAttribLocation(shaderProgramId, "vPosition");GLES30.glEnableVertexAttribArray(positionLocation);GLES30.glVertexAttribPointer(positionLocation, 3, GLES30.GL_FLOAT, false, 7 * 4, 0);// 顶点缓冲区每个顶点后4个数作为颜色GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);int inputColorLocation = GLES30.glGetAttribLocation(shaderProgramId, "inputColor");GLES30.glEnableVertexAttribArray(inputColorLocation);GLES30.glVertexAttribPointer(inputColorLocation, 4, GLES30.GL_FLOAT, false, 7 * 4, 3 * 4);// 配置统一变量,圆形半径int radiusLocation = GLES30.glGetUniformLocation(shaderProgramId, "radius");GLES30.glUniform1f(radiusLocation, 0.5f);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId);// 调用DrawCall绘制三角形GLES30.glDrawElements(GLES30.GL_TRIANGLES, 6, GLES30.GL_UNSIGNED_SHORT, 0);// 清除配置GLES30.glDisableVertexAttribArray(positionLocation);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);GLES30.glUseProgram(0);
}

效果

在这里插入图片描述

小结

看完本节的demo,应该对着色器的使用有了一定的,着色器的语法和C语言有一些类似,不过它其实不是C语言,而是自定义的语言,然后会编辑成显卡驱动可以理解的字节码。
OpenGL ES章节更多的都是以一些简单的demo来介绍,这样会更加容易理解,后面我们会介绍纹理,也会需要在片段着色器中做处理。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

简单线性回归分析-基于R语言

本题中&#xff0c;在不含截距的简单线性回归中&#xff0c;用零假设对统计量进行假设检验。首先&#xff0c;我们使用下面方法生成预测变量x和响应变量y。 set.seed(1) x <- rnorm(100) y <- 2*xrnorm(100) &#xff08;a&#xff09;不含截距的线性回归模型构建。 &…

一篇文章快速学会docker容器技术

目录 一、Docker简介及部署方法 1.1Docker简介 1.1.1什么是docker 1.1.2 docker在企业中的应用场景 1.1.3 docker与虚拟化的对比 1.1.4 docker的优势 二 、部署docker 2.1 容器工作方法 2.2 部署第一个容器 2.2.1 配置软件仓库 2.2.2 安装docker-ce并启动服务 2.2.…

B2B商城交易解决方案:赋能企业有效重塑采购与销售新生态

在电商零售领域&#xff0c;商城系统始终是企业搭建商城的关键利器。 伴随着电商行业的蓬勃发展&#xff0c;各类新模式层出不穷&#xff0c;各种商城系统也应运而生&#xff0c;其中B2B商城更是最为常见的一种。 近年来&#xff0c;得益于电子商务的迅猛发展&#xff0c;B2B商…

宿州儿童自闭症寄宿制学校:培养孩子独立能力的专业机构

在探索自闭症儿童教育的广阔领域里&#xff0c;宿州儿童自闭症寄宿制学校以其专业的教育模式和显著的成效&#xff0c;为众多家庭带来了希望。然而&#xff0c;当我们把目光投向中国南方的繁华都市——广州&#xff0c;会发现另一所同样在自闭症儿童教育领域深耕多年、成果显著…

python如何判断图片路径是否存在

1、在向文件夹中保存数据前&#xff0c;先判断该文件夹(路径)是否存在。 save_path /root/.../image/result if not os.path.exists(save_path):os.makedirs(save_path) 本来路径里只有到image文件夹的&#xff0c;执行完后会自动在image下创建result文件夹。 2、在打开某些图…

一款好用的图像处理软件:Photoshop

Photoshop 常被简称为PS&#xff0c;是图像处理领域里最常用也是很重要的一个工具。在平面广告设计、印刷出版等各领域有有着重要的作用。利用Photoshop图像处理软件&#xff0c;可以设计制作报纸、杂志、书籍、招贴广告、海报、建筑效果图、网页等各种精美的作品&#xff0c;普…

Thinkphp/Laravel基于Vue的重庆旅游网站交互设计与实现

目录 系统介绍具体实现截图技术栈和环境说明开发技术简介解决的思路性能/安全/负载方面数据访问方式PHP核心代码部分展示代码目录结构解析系统测试详细视频演示获取源码方式 系统介绍 本系统的设计与实现共包含12个表:分别是关于我们信息表&#xff0c;配置文件信息表&#xf…

车辆重识别(改进的去噪扩散概率模型)论文阅读2024/9/29

所谓改进的去噪扩散概率模型主要改进在哪些方面&#xff1a; ①对数似然值的改进 通过对噪声的那个方差和T进行调参&#xff0c;来实现改进。 ②学习 这个参数也就是后验概率的方差。通过数据分析&#xff0c;发现在T非常大的情况下对样本质量几乎没有影响&#xff0c;也就是说…

智慧应急指挥平台1+6+N体系建设方案

1. 智慧应急指挥平台概述 智慧应急指挥平台是一个综合性的应急响应体系&#xff0c;旨在通过高效的信息整合和通信技术&#xff0c;提升应急管理的智能化水平。该平台采用“16N”的体系结构&#xff0c;集成了智慧城市、智慧园区、智慧矿山等多个智慧应用&#xff0c;并依托三…

ONVIF、GB28181技术特点和使用场景分析

技术背景 好多开发者希望搞明白ONVIF和GB28181的区别和各自适合的场景&#xff0c;为什么大牛直播SDK只做了GB28181接入端&#xff0c;没有做ONVIF&#xff1f;本文就二者差别&#xff0c;做个大概的介绍。 ONVIF ONVIF&#xff08;Open Network Video Interface Forum&…

16.安卓逆向-frida基础-HOOK类方法2

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要盲目相信。 工…

揭秘网络钓鱼:如何识破并防范这场数字时代的诈骗游戏

网络钓鱼是一种网络攻击&#xff0c;它利用伪装的电子邮件欺骗收件人提供信息、下载恶意软件或采取其他期望的行动。 网络钓鱼是网络害虫&#xff0c;自20世纪90年代初从暗网出现以来&#xff0c;至今仍危害全球。根据SlashNext的报告&#xff0c;2023年平均每天有31,000次网络…

解决$‘r‘ command not found或者文件夹显示’tvsf 33‘$‘r‘

问题现象: 某客户反馈在执行脚本的时候文件夹显示存在问题,如下图: 但是脚本文件中的内容并没有\r字符,如下图: 也有客户反馈如下: 问题分析: $\r’是回车符的转义表示。在Unix和Linux系统中,回车符是一个不可见的控制字符,它通常用于文本文件中的行结尾。以上…

国内ChatGPT镜像网站整理汇总【OpenAI o1/GPT 4o】-2024/10月最新

一、中文镜像站 ①yixiaai.com 支持GPT4、4o以及o1&#xff0c;支持MJ绘画、文件上传 ②chat.lify.vip 支持通用全模型&#xff0c;支持文件读取、插件、绘画、AIPPT ③AI Chat 支持GPT3.5/4&#xff0c;4o以及MJ绘画 1. 什么是镜像站 镜像站&#xff08;mirrored site&am…

NAL 网络提取层(Network Abstraction Layer)

1.NAL全称Network Abstract Layer, 即网络抽象层。 在H.264/AVC视频编码标准中&#xff0c;无论是存储还是网络传输&#xff0c;H264 原始码流是由一个接一个 NALU&#xff08;NAL Unit&#xff09; 组成&#xff0c;整个系统框架被分为两个层面&#xff1a;视频编码层面&#…

敏感内容识别是如何实现的?5大妙招教你快速筛选敏感词!

敏感内容识别是现代信息安全领域的重要课题&#xff0c;其实现依赖于多种技术和策略的综合运用。 以下是五种快速筛选敏感词的妙招&#xff1a; 一、关键词匹配 方法&#xff1a;通过使用安企神这类敏感词识别软件预设敏感词库&#xff0c;将待检测内容与敏感词库进行比对&am…

安达发|纺织行业APS系统中的物料替代解决方案

在纺织行业中&#xff0c;物料替代是应对原材料短缺、成本波动和供应链不确定性的一种重要策略。高级计划与排程系统&#xff08;APS&#xff09;通过集成物料替代功能&#xff0c;可以帮助企业在保持生产效率的同时&#xff0c;灵活应对市场变化。本文将探讨纺织行业在APS系统…

OpenFeign-快速使用-连接池-使用的最佳方案-日志配置

OpenFeign 我们利用Nacos实现了服务的治理,利用RestTemplate实现了服务的远程调用。但是远程调用的代码太复杂了: 其实远程调用的关键点就在于四个: 请求方式 请求路径 请求参数 返回值类型 所以,OpenFeign就利用SpringMVC的相关注解来声明上述4个参数,然后基于动态代理…

PHP人才机遇桥梁招聘求职全能系统小程序源码

人才机遇桥梁 —— 招聘求职全能系统全解析 &#x1f4bc;&#x1f680; &#x1f309; 搭建人才与机遇的桥梁 在这个竞争激烈的职场环境中&#xff0c;找到一份心仪的工作或招募到合适的人才&#xff0c;往往不是一件容易的事。但幸运的是&#xff0c;我们有了“人才机遇桥梁…

JDK1.8 新的特性

一 Lambda 使用 Lambda表达式应用场景&#xff1a;任何有函数式接口的地方&#xff0c;只有一个抽象方法(Object类中的方法除外)的接口是函数式接口。就像Runnable接口中&#xff0c;只有一个run方法。 1、Runnable //在JDK1.8之前的写法new Thread(new Runnable() {public v…