WebGL 同一缓冲区多种数据传入顶点着色器 gl.vertexAttribPointer()的步进和偏移参数

news2024/11/20 2:21:27

目录

目录

为了将顶点坐标传入着色器,需要遵循一下五步:

但是!!!

示例代码:

gl.vertexAttribPointer()的函数规范

stride参数

顶点坐标数据

offset参数 

顶点尺寸数据


首先,分析如何实现下方示例为三个不同大小位置的点

为了将顶点坐标传入着色器,需要遵循一下五步:

1. 创建缓冲区对象

2. 将缓冲区对象绑定到target上

3. 将顶点坐标数据写入缓冲区对象

4. 将缓冲区对象分配给对应的attribute对象

5. 激活开启attribute变量 

当然你可以创建两个缓冲区对象分别存储坐标数据和非坐标数据,随之传给各自对应的着色器变量 a_Position 和 a_pointSize

但是!!!

 使用多个缓冲区对象向着色器传递多种数据,比较适合数据量不大的情况。当程序中的复杂三维图形具有成千上万个顶点时,维护所有的顶点数据是很困难的。想象一下,如果程序中的三维模型有几千几万个顶点会怎样。所以,WebGL允许我们把顶点的坐标和尺寸数据打包到同一个缓冲区对象中,并通过某种机制分别访问缓冲区对象中不同种类的数据。比如,可以将顶点的坐标和尺寸数据按照如下方式交错组织(interleaving),如下图所示:


可见,一旦我们将几种“逐顶点”的数据(坐标和尺寸)交叉存储在一个数组中,并将数组写入一个缓冲区对象。WebGL就需要有差别地从缓冲区中获取某种特定数据(坐标或尺寸),即使用gl.vertexAttribPointer()函数的第5个参数stride和第6个参数offset。下面让我们来看看代码。

示例代码:

// 顶点着色器程序
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute float a_PointSize;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = a_PointSize;\n' +
  '}\n';

// 片元着色器程序
var FSHADER_SOURCE =
  'void main() {\n' +
  '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
  '}\n';

function main() {
  // Retrieve <canvas> element
  var canvas = document.getElementById('webgl');
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log('Failed to get the rendering context for WebGL');
    return;
  }
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }
  // 设置顶点坐标和点的尺寸
  var n = initVertexBuffers(gl);
  if (n < 0) {
    console.log('Failed to set the vertex information');
    return;
  }
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
  var verticesSizes = new Float32Array([
    // 顶点坐标和点的尺寸
     0.0,  0.5,  10.0,  // 第一个点
    -0.5, -0.5,  20.0,  // 第二个点
     0.5, -0.5,  30.0   // 第三个点
  ]);
  var n = 3; // The number of vertices

  // 创建缓冲区对象
  var vertexSizeBuffer = gl.createBuffer();  
  if (!vertexSizeBuffer) {
    console.log('Failed to create the buffer object');
    return -1;
  }
  // 将顶点坐标和尺寸写入缓冲区并开启
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexSizeBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, verticesSizes, gl.STATIC_DRAW);
  var FSIZE = verticesSizes.BYTES_PER_ELEMENT;
  // 获取a_Position的存储位置,分配缓冲区并开启
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return -1;
  }
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 3, 0);
  gl.enableVertexAttribArray(a_Position);  // 开启分配
  // 获取a_PointSize的存储位置,分配缓冲区并开启
  var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
  if(a_PointSize < 0) {
    console.log('Failed to get the storage location of a_PointSize');
    return -1;
  }
  gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, FSIZE * 3, FSIZE * 2);
  gl.enableVertexAttribArray(a_PointSize);  // 开启缓冲区分配
  return n;
}

首先,我们定义了一个类型化数组verticesSizes,接下来:创建缓冲区对象,绑定之,把数据写入缓冲区对象。然后,我们将verticeSize数组中每个元素的大小(字节数)存储到FSIZE中,稍后将会用到它。类型化数组具有BYTES_PER_ELEMENT属性,可以从中获知数组中每个元素所占的字节数。 

注意,这里的verticesSizes参数设置就与单纯的传入顶点坐标有所不同了,因为在缓冲区对象中存储了两种类型的数据:顶点坐标和顶点尺寸。

gl.vertexAttribPointer()的函数规范

stride参数

参数stride表示,在缓冲区对象中,单个顶点的所有数据(这里,就是顶点的坐标和大小)的字节数,也就是相邻两个顶点间的距离,即步进参数。 

顶点坐标数据

在缓冲区只含有一种数据时,例顶点的坐标,我们将其设置为0即可。然而,在这里中,当缓冲区中有了多种数据(比如这里的顶点坐标和顶点尺寸)时,我们就需要考虑参数stride的值,如下图所示:

 如上图所示,每一个顶点有3个数据值(两个坐标数据和一个尺寸数据),因此应该设置为每项数据大小的三倍,即3×FSIZE(Float32Array中每个元素所占的字节数)。

offset参数 

参数offset表示当前考虑的数据项距离首个元素的距离,即偏移参数。在verticesSizes数组中,顶点的坐标数据是放在最前面的,所以应当为0。因此,我们调用gl.vertexAttribArray()函数时,如下所示传入stride参数和offset参数

这样一来,我们就把缓冲区中的那部分顶点坐标数据分配给了着色器中的attribute变量a_Position,并开启了该变量。 

顶点尺寸数据

接下来对顶点尺寸数据采取相同的操作:将缓冲区对象中的顶点尺寸数据分配给a_PointSize。然而在这个例子中,缓冲区对象还是原来那个,只不过这次关注的数据不同,我们需要将参数设置为顶点尺寸数据在缓冲区对象中的初始位置。在关于某个顶点的三个值中,前两个是顶点坐标,后一个是顶点尺寸,因此应当设置为FSIZE*2(参见上面stride解释图)。我们如下调用gl.vertexAttribArray()函数,并正确设置stride参数和offset参数

 在开启已被分配的缓冲区对象的a_PointSize变量之后,剩下的任务就只有调用gl.drawArrays()进行绘制操作了。

再次执行顶点着色器时,WebGL系统会根据stride和offset参数从缓冲区中正确地抽取出数据,依次赋值给着色器中的各个attribute变量,并进行绘制(如下图所示)。

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

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

相关文章

KaiwuDB 助力能源企业实现 4 大价值提升

行业背景 近年来&#xff0c;随着能源行业数字化的不断推进&#xff0c;智能电网、可再生能源发电、分布式发电、微电网等技术蓬勃发展。越来越多的能源企业意识到数据管理与价值挖掘对储能及能源利用有着重大意义&#xff0c;并开始探索一套有效的数据库解决方案以应对分布式…

Chrome小恐龙快跑小游戏——Python实现

目录 视频演示 代码实现 视频演示 Chrome小恐龙快跑小游戏——Python实现 代码实现 import pygame import os import random pygame.init()# Global Constants SCREEN_HEIGHT 600 SCREEN_WIDTH 1100 game_over False SCREEN pygame.display.set_mode((SCREEN_WIDTH, SCR…

电子词典dictionary

一、项目要求&#xff1a; 1.登录注册功能&#xff0c;不能重复登录&#xff0c;重复注册。用户信息也存储在数据库中。 2.单词查询功能 3.历史记录功能&#xff0c;存储单词&#xff0c;意思&#xff0c;以及查询时间&#xff0c;存储在数据库 4.基于TCP&#xff0c;支持多客户…

三、mycat分库分表

第五章 分库分表 一个数据库由很多表的构成&#xff0c;每个表对应着不同的业务&#xff0c;垂直切分是指按照业 务将表进行分类&#xff0c;分布到不同 的数据库上面&#xff0c;这样也就将数据或者说压力分担到不同 的库上面&#xff0c;如下图&#xff1a; 系统被切分成了&…

three.js(四):react + three.js

绘制多个立方体 1.搭建reactts 项目 npx create-react-app basics-demo --template typescriptreactts 的用法可参考此链接&#xff1a; https://react-typescript-cheatsheet.netlify.app/docs/basic/setup 2.安装three依赖 npm install three types/three --save3.安装路…

200 套基于Java开发的Java毕业设计实战项目(含源码+说明文档)

文章目录 简介前言第一部分第二部分部分截图源码咨询 简介 博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 前言 对于java方向的毕业设计题目选题&#xf…

Weblogic漏洞(四)之 CVE-2018-2894 任意文件上传漏洞

CVE-2018-2894 任意文件上传漏洞 漏洞影响 Weblogic受影响的版本&#xff1a; 10.3.6.012.1.3.012.2.1.212.2.1.3 漏洞环境 此次我们使用的是vnlhub靶场搭建的环境&#xff0c;是vnlhub中的Weblogic漏洞中的CVE-2018-2894靶场&#xff0c;我们 cd 到 CVE-2018-2894&#x…

R3LIVE源码解析(6) — R3LIVE流程详解

目录 1 R3LIVE框架简介 2 R3LIVE的launch文件 3 R3LIVE的r3live_config文件 4 R3LIVE从哪开始阅读 1 R3LIVE框架简介 R3LIVE是香港大学Mars实验室提出的一种融合imu、相机、激光的SLAM方法&#xff0c;R3LIVE由两个子系统组成&#xff0c;一个激光惯性里程计&#xff08;L…

【无标题】8.31在华清

可以登录但是不能跳转

怎么用postman连接websocket

点击右侧栏的Collections&#xff0c;然后点击旁边的New&#xff0c;然后点击其中的WebSocket Request,然后输入Url&#xff0c;点击Connection&#xff0c;这里需要注意的是Url不能加上http://&#xff0c;因为这个不是http协议。

23062网络编程day5

根据select TCP服务器流程图编写服务器 #include <myhead.h> #define ERR_MSG(msg) do{\fprintf(stderr,"__%d__:",__LINE__);\perror(msg);\ }while(0)#define PORT 8888 #define IP "192.168.114.104"int keyboard_events(void); int cliConnect_…

美国纽约10日游

一、前言 我有两周断更了&#xff0c;原因是去纽约只顾着玩&#xff0c;没时间写&#xff0c;今天有时间正好和大家分享一下去纽约的攻略 二、以下是一个10天去美国纽约旅游的攻略&#xff0c;十万以内&#xff0c;包括机票、酒店、交通、餐饮和景点门票等费用&#xff1a; 第…

Leetcode ->206 反转链表

题目 算法思路及代码实现 #include <iostream> using namespace std;struct ListNode {int val; //当前节点的值ListNode *next;

目标检测笔记(十二):如何通过界面化操作YOLOv5完成数据集的自动标注

文章目录 一、意义二、修改源码获取三、自动标注前期准备四、开始自动标注五、可视化标注效果六、XML转换TXT 一、意义 通过界面化操作YOLOv5完成数据集的自动标注的意义在于简化数据标注的流程&#xff0c;提高标注的效率和准确性。 传统的数据集标注通常需要手动绘制边界框…

通信笔记:RSRP、RSRQ、RSNNR

0 基础概念&#xff1a;RE、RS和RB RE (Resource Element)&#xff1a;资源元素是 LTE 和 5G 网络中的最小物理资源单位。一个资源元素对应于一个子载波的一个符号周期。 RS (Reference Signal)&#xff1a;参考信号是在 LTE 和 5G 网络中用于多种目的的特定类型的信号。它们可…

PyCharm切换虚拟环境

PyCharm切换虚拟环境 为了满足不同任务需要不同版本的包&#xff0c;可以在Anaconda或者Miniconda创建多个虚拟环境文件夹&#xff0c;并在PyCharm下切换虚拟环境。 解决方案 1、打开Ananconda Prompt 2、创建自己的虚拟环境 格式&#xff1a;conda create -n 虚拟环境名字…

SSH远程连接macOS服务器:通过cpolar内网穿透技术实现远程访问的设置方法

文章目录 前言1. macOS打开远程登录2. 局域网内测试ssh远程3. 公网ssh远程连接macOS3.1 macOS安装配置cpolar3.2 获取ssh隧道公网地址3.3 测试公网ssh远程连接macOS 4. 配置公网固定TCP地址4.1 保留一个固定TCP端口地址4.2 配置固定TCP端口地址 5. 使用固定TCP端口地址ssh远程 …

《华为认证》二层EVPN的配置

步骤1&#xff1a;配置PE和P设备的IGP以及mpls、mpls ldp&#xff08;略&#xff09; 步骤2&#xff1a;配置evpn实例&#xff0c;并且绑定到BD中&#xff0c;配置evpn的源ip地址 PE1: evpn vpn-instance 1 bd-mode //指定创建BD模式EVPN实例 route-distinguisher 100:1 vpn-…

【Leetcode】130.被围绕的区域

一、题目 1、题目描述 给你一个 m x n 的矩阵 board ,由若干字符 X 和 O ,找到所有被 X 围绕的区域,并将这些区域里所有的 O 用 X 填充。 示例1: 输入:board = [[“X”,“X”,“X”,“X”],[“X”,“O”,“O”,“X”],[“X”,“X”,“O”,“X”],[“X”,“O”,“X”,“…

操作符算数转换题

目录 1.交换两个变量&#xff08;不创建临时变量&#xff09; 2.统计二进制中1的个数 3.打印整数二进制的奇数位和偶数位 4.求两个数二进制中不同位的个数 5.【一维数组】有序序列合并 6.获得月份天数 7.变种水仙花数 8.选择题总结tips 这篇博文主要分享操作符&算…