webgl中绑定缓冲区的逻辑是什么?

2024-05-12

有时我发现自己在以不同顺序声明缓冲区(使用 createBuffer/bindBuffer/bufferdata)和在代码的其他部分(通常在绘制循环中)重新绑定它们之间挣扎。

如果我在绘制数组之前不重新绑定顶点缓冲区,控制台会抱怨尝试访问超出范围的顶点。我怀疑最后一个绑定对象是在指针处传递的,然后传递给绘图数组,但是当我更改代码开头的顺序时,没有任何变化。有效的方法是在绘制循环中重新绑定缓冲区。所以,我无法真正理解其背后的逻辑。什么时候需要重新绑定?为什么需要重新绑定? attribute0指的是什么?


我不知道这是否有帮助。正如有些人所说,GL/WebGL 有一堆内部的state。您调用的所有函数都会设置状态。当一切都设置完毕后,你可以打电话drawArrays or drawElements所有这些状态都用来绘制东西

这已在 SO 的其他地方进行了解释,但绑定缓冲区只是在 WebGL 内设置 2 个全局变量中的 1 个。之后,您可以通过其绑定点来引用缓冲区。

你可以这样想

gl = function() {
   // internal WebGL state
   let lastError;
   let arrayBuffer = null;
   let vertexArray = {
     elementArrayBuffer: null,
     attributes: [
       { enabled: false, type: gl.FLOAT, size: 3, normalized: false, 
         stride: 0, offset: 0, buffer: null },
       { enabled: false, type: gl.FLOAT, size: 3, normalized: false, 
         stride: 0, offset: 0, buffer: null },
       { enabled: false, type: gl.FLOAT, size: 3, normalized: false, 
         stride: 0, offset: 0, buffer: null },
       { enabled: false, type: gl.FLOAT, size: 3, normalized: false, 
         stride: 0, offset: 0, buffer: null },
       { enabled: false, type: gl.FLOAT, size: 3, normalized: false, 
         stride: 0, offset: 0, buffer: null },
       ...
     ],
   }
   // these values are used when a vertex attrib is disabled
   let attribValues = [
     [0, 0, 0, 1],
     [0, 0, 0, 1],
     [0, 0, 0, 1],
     [0, 0, 0, 1],
     [0, 0, 0, 1],
     ...
   ];
   ...

   // Implementation of gl.bindBuffer. 
   // note this function is doing nothing but setting 2 internal variables.
   this.bindBuffer = function(bindPoint, buffer) {
     switch(bindPoint) {
       case gl.ARRAY_BUFFER;
         arrayBuffer = buffer;
         break;
       case gl.ELEMENT_ARRAY_BUFFER;
         vertexArray.elementArrayBuffer = buffer;
         break;
       default:
         lastError = gl.INVALID_ENUM;
         break;
     }
   };
...
}();

之后其他 WebGL 函数引用这些函数。例如gl.bufferData可能会做类似的事情

   // implementation of gl.bufferData
   // Notice you don't pass in a buffer. You pass in a bindPoint. 
   // The function gets the buffer one of its internal variable you set by
   // previously calling gl.bindBuffer

   this.bufferData = function(bindPoint, data, usage) {

     // lookup the buffer from the bindPoint
     var buffer;
     switch (bindPoint) {
       case gl.ARRAY_BUFFER;
         buffer = arrayBuffer;
         break;
       case gl.ELEMENT_ARRAY_BUFFER;
         buffer = vertexArray.elemenArrayBuffer;
         break;
       default:
         lastError = gl.INVALID_ENUM;
         break;
      }

      // copy data into buffer
      buffer.copyData(data);  // just making this up
      buffer.setUsage(usage); // just making this up
   };

与这些绑定点分开的是许多属性。默认情况下,属性也是全局状态。它们定义如何从缓冲区中提取数据以提供给顶点着色器。呼唤gl.getAttribLocation(someProgram, "nameOfAttribute")告诉您顶点着色器将查看哪个属性以从缓冲区中获取数据。

因此,您可以使用 4 个函数来配置属性如何从缓冲区获取数据。gl.enableVertexAttribArray, gl.disableVertexAttribArray, gl.vertexAttribPointer, and gl.vertexAttrib??.

他们有效地实施了这样的事情

this.enableVertexAttribArray = function(location) {
  const attribute = vertexArray.attributes[location];
  attribute.enabled = true;  // true means get data from attribute.buffer 
};

this.disableVertexAttribArray = function(location) {
  const attribute = vertexArray.attributes[location];
  attribute.enabled = false; // false means get data from attribValues[location]
};

this.vertexAttribPointer = function(location, size, type, normalized, stride, offset) {
  const attribute = vertexArray.attributes[location];
  attribute.size       = size;       // num values to pull from buffer per vertex shader iteration
  attribute.type       = type;       // type of values to pull from buffer
  attribute.normalized = normalized; // whether or not to normalize
  attribute.stride     = stride;     // number of bytes to advance for each iteration of the vertex shader. 0 = compute from type, size
  attribute.offset     = offset;     // where to start in buffer.

  // IMPORTANT!!! Associates whatever buffer is currently *bound* to 
  // "arrayBuffer" to this attribute
  attribute.buffer     = arrayBuffer;
};

this.vertexAttrib4f = function(location, x, y, z, w) {
  const attrivValue = attribValues[location];
  attribValue[0] = x;
  attribValue[1] = y;
  attribValue[2] = z;
  attribValue[3] = w;
};

现在,当你打电话时gl.drawArrays or gl.drawElements系统知道您希望如何从您为提供顶点着色器而创建的缓冲区中提取数据。请参阅此处了解其工作原理 http://webglfundamentals.org/webgl/lessons/webgl-how-it-works.html.

由于属性是全局状态这意味着每次你打电话drawElements or drawArrays属性的设置方式决定了它们的使用方式。如果您将属性 #1 和 #2 设置为每个都有 3 个顶点的缓冲区,但您要求绘制 6 个顶点gl.drawArrays你会得到一个错误。同样,如果您创建一个索引缓冲区并将其绑定到gl.ELEMENT_ARRAY_BUFFER绑定点并且该缓冲区的索引 > 2 你会得到index out of range错误。如果你的缓冲区只有 3 个顶点,那么唯一有效的索引是0, 1, and 2.

通常,每次绘制不同的东西时,您都会重新绑定绘制该东西所需的所有属性。绘制一个具有位置和法线的立方体?将缓冲区与位置数据绑定,设置用于位置的属性,将缓冲区与法线数据绑定,设置用于法线的属性,现在绘制。接下来,您绘制一个具有位置、顶点颜色和纹理坐标的球体。绑定包含位置数据的缓冲区,设置用于位置的属性。绑定包含顶点颜色数据的缓冲区,设置用于顶点颜色的属性。绑定包含纹理坐标的缓冲区,设置用于纹理坐标的属性。

唯一不重新绑定缓冲区的情况是多次绘制同一事物时。例如绘制 10 个立方体。您需要重新绑定缓冲区,然后为一个立方体设置制服,绘制它,为下一个立方体设置制服,绘制它,重复。

我还应该补充一点,有一个扩展名 [OES_vertex_array_object] 这也是WebGL 2.0的一个特性。顶点数组对象是上面称为的全局状态vertexArray其中包括elementArrayBuffer和所有属性。

Calling gl.createVertexArray制作新的其中之一。呼唤gl.bindVertexArray设置全局attributes指向绑定的 vertexArray 中的那个。

Calling gl.bindVertexArray那么就会是

 this.bindVertexArray = function(vao) {
   vertexArray = vao ? vao : defaultVertexArray;
 }    

这样做的优点是可以让您在初始化时设置所有属性和缓冲区,然后在绘制时只需 1 个 WebGL 调用即可设置所有缓冲区和属性。

这里有一个webgl状态图 https://webglfundamentals.org/webgl/lessons/resources/webgl-state-diagram.html这可能有助于更好地形象化这一点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

webgl中绑定缓冲区的逻辑是什么? 的相关文章

  • 单击输入[复选框]的标签将触发父级单击事件两次(淘汰)

    考虑这把小提琴 http jsfiddle net 9rkrahm6 我有一个
  • dojo dijit.form.DateTextBox 约束不起作用,datetextbox

    嗨 我是 javascript 和 dojo 的新手 我正在尝试使用两个带有下拉日历的 dijit DateTextBox 来建立数据库查询的日期范围 一旦选择了开始日期或结束日期 我想限制可用的日期 以便不可能选择按时间顺序排列在开始日期
  • 了解设置 JQuery 变量

    了解设置 JQuery 变量 最近 我通过在 StackOverflow 上遇到的另一个问题寻找帮助 了解到如何设置 JQuery 变量 如下所示 您可以通过简单地调用变量来创建输入字段 并且锚变量似乎也定义了样式 var clicked
  • 从数据 URI 解码 QR 码

    我尝试从数据 uri 中解码二维码 var dataUri data image gif base64 R0lGODdh9gD2AIAAAAAAAP ywAAAAA9gD2AAAC decodeQrCode dataUri cb 我已经尝试
  • 不和谐机器人 |不和谐.js |类型错误:无法读取未定义的属性“长度”

    我正在制作一个 Discord 机器人 并且正在使用 CodeLyon 的视频作为参考 该错误位于我的 message js 文件中 该文件包含以下内容 require dotenv config create cooldowns map
  • 尝试将布尔 C# 变量传递给 javascript 变量并将其设置为 true

    在我的 aspx 页面中 我将布尔变量 C 传递给需要布尔类型的 javascript 函数 但遇到了问题 但是 C 变量返回 True 而 javascript 不喜欢大写 myjavascript 如果我将 c 变量转换为字符串 那么我
  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 解析“流”JSON

    我在浏览器中有一个网格 我想通过 JSON 将数据行发送到网格 但浏览器应该在接收到 JSON 时不断解析它 并在解析时将行添加到网格中 换句话说 在接收到整个 JSON 对象后 不应将行全部添加到网格中 应该在接收到行时将其添加到网格中
  • 如何重置使用 JavaScript 更改的 CSS 属性?

    我的导航按钮的宽度从 100px 增加到 150px 当鼠标悬停在 nav li hover width 150px 但是使用 javascript 我已经做到了 无论选择哪个选项 宽度都将继续为 150px 当选择每个选项时 它会使其他选
  • 使用 Angular 下载具有动态 src 的脚本

    Angular 提供了通过动态名称动态加载模板的方法ng include 该部分中的内联 JS 和 CSS 可以正常加载 但没有一个好的方法来下载带有动态 url 的脚本 我们需要下载脚本 相对于调用它们的 html 部分的路径 即我们有一
  • 在 Wordpress 站点中进行 AJAX 调用时出现问题

    我在使用 Wordpress 站点功能的 AJAX 部分时遇到了一些问题 该功能接受在表单上输入的邮政编码 使用 PHP 函数来查找邮政编码是否引用特定位置并返回到该位置的永久链接 我的第一个问题是关于我构建的表单 现在我的表单操作是空白的
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • Meteor - 从客户端取消服务器方法

    我正在通过服务器方法执行数据库计数 用户可以选择他们希望如何执行计数 然后调用该方法 我的问题是 计数可能需要一些时间 并且用户可能会在方法运行时改变主意并请求不同的计数 有什么方法可以取消调用的方法并运行新的计数吗 我认为 this un
  • 在 webpack 2.x 中使用 autoprefixer 和 postcss

    如何使用autoprefixer使用 webpack 2 x 以前 它曾经是这样的 module loaders test scss loader style css sass postcss postcss gt return autop
  • Electron - 为什么在关闭事件时将 BrowserWindow 实例设置为 null

    The 电子文档 https electronjs org docs api browser window 提供以下代码示例来创建新窗口 const BrowserWindow require electron let win new Br
  • 为 illustrator 导出脚本以保存为 web jpg

    任何人都可以帮我为 illustrator CC2017 编写一个脚本 将文件以 JPG 格式导出到网络 旧版 然后保存文件并关闭 我有 700 个文件 每个文件有 2 个画板 单击 文件 gt 导出 gt 另存为 Web 旧版 然后右键文
  • 为什么在 Internet Explorer 中访问 localStorage 对象会引发错误?

    我正在解决一个客户端问题 Modernizr 意外地没有检测到对localStorageInternet Explorer 9 中的对象 我的页面正确使用 HTML 5 文档类型 并且开发人员工具报告该页面具有 IE9 的浏览器模式和 IE
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 如何在 pg-promise 中设置模式

    我正在搜索的文档pg 承诺 https github com vitaly t pg promise特别是在创建客户端时 但我无法找到设置连接中使用的默认架构的选项 它始终使用public架构 我该如何设置 通常 为数据库或角色设置默认架构
  • 在 React.js 中编辑丰富的数据结构

    我正在尝试为数据结构创建一个简单的基于网格的编辑器 但我在使用 React js 时遇到了一些概念问题 他们的文档对此没有太大帮助 所以我希望这里有人可以提供帮助 首先 将状态从外部组件传输到内部组件的正确方法是什么 是否有可能将内部组件中

随机推荐