如何组织WebGL中的顶点数据来制作一帧一帧(非常具体)的动画程序? [英] How Might I organize vertex data in WebGL for a frame-by-frame (very specific) animated program?

查看:158
本文介绍了如何组织WebGL中的顶点数据来制作一帧一帧(非常具体)的动画程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究一个具有非常特殊要求的动画图形项目,经过相当多的搜索和测试编码之后,我发现我可以采取多种方法,但我一直在阅读Khronos和MDN文档,我在这里看到的其他帖子没有回答关于我的特定项目的所有问题。与此同时,我编写了简短的测试程序(设置测试基础设施)。

首先,我应该描述这个项目:

绘制到屏幕上的主要对象是一个由黑色轮廓包围的简单四边形(LINE_LOOP或LINES可能会这样做,尽管我已经遇到了z战斗问题...这将留给另一个问题) 。当用户与程序交互时,只有一个新四边形被创建并立即绘制,但是在一段时间内它的顶点会移动,直到四边形移动到其最终目的地。 (请注意,翻译将不会执行。)随机黑线也被绘制出来,有时这些线条也会移动。



一旦四边形中的一个达到最终点,它再也不会移动。
新的四边形总是位于旧四边形上(靠近屏幕)。这意味着我需要将四边形和线条从最旧到最新层叠。
*这也意味着即使图形在像素坐标中并使用正交矩阵,也可能最好为每个四边形和线条分配z值。大家会同意吗?



给定这些参数,我有几个不同复杂程度的选项:

1>采用面向对象的方法,并为每个四元组分配一个缓冲区,对于随机行也是如此。 - 为每个正在移动的形状创建并销毁缓冲区。我真诚地认为,这是一个可怕的想法,可能只会在较高层次的库中起作用,并且会在底层进行大量优化。这种方法也没有利用几乎每个四元组都保持不变的事实。

  [vertices0] ... ,[verticesN] 
绘制x N(许多小尺寸缓冲区的许多绘图)

2>为每个四边形,轮廓和线条分配一个z值(如上所述)。分配一个巨大的顶点缓冲区和元素缓冲区来存储所有永久在其最终位置的四边形。仅在非常不太可能的情况下才会调整足够长的时间进行互动。创建第二个小缓冲区来存储一个临时移动四元组,并在每一帧中使用 bufferSubData 。当四元组到达其目的地时, bufferSubData 它进入大缓冲区,并在创建下一个四舍五入时覆盖小缓冲区...全部在同一帧上。我在这里的主要问题是:是否可以(安全?)使用 bufferSubData 并在同一个框架上绘制它?另外,我会在两个缓冲区上使用 DYNAMIC_DRAW ,即使较大的更新会发现更少的更新吗?

  [永久顶点... |未初始化(保持计数)] 
bufferSubData - > [tempVerticesForOneQuad]
绘制2x



<3>仍创建大小缓冲区,但是改为在每一帧中使用 bufferSubData ,创建第二个着色器程序并为新的/移动的四边形添加一个属性,明确设置动画的顶点位置(我将传递顶点索引属性)。四边形移动时只能用小缓冲区绘制。对于四元组到达目的地时的帧,请绘制大小缓冲区,然后将 bufferSubData 最终坐标绘制到下一个要使用的大永久性缓冲区中 frame。

  switchToShaderProgramA(); 
[永久顶点... |未初始化(保持计数)]
switchToShaderProgramB();
[临时顶点]< - 着色器B接受每个顶点的索引,因此我们可以在顶点着色器中完成所有动画
---最后一帧移动到达:bufferSubData进入永久顶点缓冲区,下一个四元组是创建

我知道第三个选项可能是最好的,但我会喜欢了解是否还有其他一些我没有考虑过的因素。例如,我假设程序切换,附加属性和顶点着色器操作将比仅替换2>中的缓冲区值更快。方法3>(我认为)的优点是,我可以将缓冲区替换推迟到无需绘制任何内容。



不过,我仍然不确定如何与随机出现的线条一起工作。由于行数不能预测,我不能采用单四角顶点缓冲方法。我是否还可以为移动的线条分配一个大缓冲区?那些在四分体移动完成之后也会留下来,尽管我不认为我可以使用顶点着色技巧,因为会有太多的属性需要设置(而不是四个四分体)。我想我可以先创建一个大的永久线数据缓冲区,但是在动画过程中做什么是棘手的,因为线条在移动。也许bufferSubData()+在同一帧上绘制并不可怕?或者它可能是。这是我需要提供建议的地方。



我明白这个问题可能不是太具体的代码明智,但我不相信我会被允许显示该计划的核心。我所有的是典型的WebGL样板文件。



我期待听到人们对我如何进行的想法,以及是否有任何折衷在考虑上述三个选项时。
如果需要澄清,请随时提出任何其他问题。

解决方案

老实说,对于你所描述的,对我而言听起来并不像你选择的那样重要。在现代硬件上,每帧画出几百个四边形和几千行并不会真正对硬件造成太大的影响。

说到这一点,我同意方法1看起来很像效率低下。方法2听起来非常好。您可以安全地在您上传数据的相同框架上绘制缓冲区。对于缓冲区是否使用 DYNAMIC_DRAW STATIC_DRAW 并不重要。我倾向于将动态缓冲区视为你正在更新每一帧的东西。如果你每隔几秒钟或更短时间更新一次,那么静态就很好。方法3也很好。在2到3之间,我会说做哪一个更容易理解和编程。

同样,对于行,我会使用单独的缓冲区。这听起来像是每帧改变一次,所以我会使用 DYNAMIC_DRAW 。为它分配一个大缓冲区并为每帧执行 glBufferSubData()可能是一个很好的策略。与往常一样,尝试它并分析它会确定地告诉你。


I have been working on an animated graphics project with very specific requirements, and after quite a bit of searching and test coding, I have figured that I could take several approaches, but the Khronos and MDN documentation I have been reading coupled with other posts I have seen here don't answer all of my questions regarding my particular project. In the meantime, I have written short test programs (setting infrastructure for testing).

Firstly, I should describe the project:

The main object drawn to the screen is a simple quad surrounded by a black outline (LINE_LOOP or LINES will do, probably, though I have had issues with z-fighting...that will be left for another question). When the user interacts with the program, exactly one new quad is created and immediately drawn, but for a set amount of time its vertices move around until the quad moves to its final destination. (Note that translations won't do.) Random black lines are also drawn, and sometimes those lines also move around.

Once one of the quads reaches its final spot, it never moves again. A new quad is always atop old quads (closer to the screen). That means that I need to layer the quads and lines from oldest to newest. *this also means that it would probably be best to assign z-values to each quad and line, even if the graphics are in pixel coordinates and use an orthographic matrix. Would everyone agree with this?

Given these parameters, I have a few options with varying levels of complexity:

1> Take the object-oriented approach and just assign a buffer to each quad, and the same goes for the random lines. --creation and destruction of buffers every frame for the one shape that is moving. I truthfully think that this is a terrible idea that might only work in a higher level library that does heavy optimization underneath. This approach also doesn't take advantage of the fact that almost every quad will stay the same.

[vertices0] ... , [verticesN]
Draw x N (many draws for many small-size buffers)

2> Assign a z-value to each quad, outline, and line (as mentioned above). Allocate a huge vertex buffer and element buffer to store all permanently-in-their-final-positions quads. Resize only in the very unlikely case someone interacts for long enough. Create a second tiny buffer to store the one temporary moving quad and use bufferSubData every frame. When the quad reaches its destination, bufferSubData it into the large buffer and overwrite the small buffer upon creation of the next quad...all on the same frame. The main questions I have here are: is it possible (safe?) to use bufferSubData and draw it on the same frame? Also, would I use DYNAMIC_DRAW on both buffers even though the larger one would see fewer updates?

[permanent vertices ... | uninitialized (keep a count)]
bufferSubData -> [tempVerticesForOneQuad]
Draw 2x

3> Still create the large and small buffers, but instead of using bufferSubData every frame, create a second shader program and add an attribute for the new/moving quad that explicitly sets the vertex positions for the animation (I would pass vertex index attributes). Only draw with the small buffer when the quad is moving. For the frame when the quad reaches its destination, draw both large and small buffer, but then bufferSubData the final coordinates into the large permanent buffer to be used in the next frame.

switchToShaderProgramA();
[permanent vertices...| uninitialized (keep a count)]
switchToShaderProgramB();
[temp vertices] <- shader B accepts indices for each vertex so we can do all animation in the vertex shader
---last frame of movement arrives : bufferSubData into the permanent vertices buffer for when the the next quad is created

I get the sense that the third option might be the best, but I would like to learn whether there are some other factors that I did not consider. For example, my assumption that a program switch, additional attributes, and vertex shader manipulation would be faster than just substituting the buffer values as in 2>. The advantage of approach 3> (I think) is that I can defer the buffer substitution to a time when nothing needs to be drawn.

Still, I am still not sure of how to work with the randomly-appearing lines. I can't take the "single quad vertex buffer" approach since the number of lines cannot be predicted. Might I also allocate a large buffer for the moving lines? Those also stay after the quad is finished moving, though I don't think that I could use the vertex shader trick because there would be too many attributes to set (as opposed to the 4 for the one quad). I suppose that I could create a large "permanent line data" buffer first, but what to do during the animation is tricky because the lines move. Maybe bufferSubData() + draw on the same frame is not terrible? Or it could be. This is where I need advise.

I understand that this question might not be too specific code-wise, but I don't believe that I would be allowed to show the core of the program. All I have is the typical WebGL boilerplate ready.

I am looking forward to hearing people's thoughts on how I might proceed and whether there are any trade-offs I might have missed when considering the three options above. Thank you in advance, and please feel free to ask any additional questions if clarification is necessary.

解决方案

Honestly, for what you're describing, it doesn't sound to me like it matters which you choose. On modern hardware, drawing a few hundred quads and a few thousand lines each frame would not really tax the hardware much.

Having said that, I agree that approach 1 seems very inefficient. Approach 2 sounds perfectly fine. You can safely draw a buffer on the same frame that you uploaded the data. I don't think it matters much whether you use DYNAMIC_DRAW or STATIC_DRAW for the buffer. I tend to think of dynamic buffers as being something you're updating every frame. If you only update it every few seconds or less, then static is fine. Approach 3 is also fine. Between 2 and 3, I'd say do whichever is easier for you to understand and program.

Likewise, for the lines, I would use a separate buffer. It sounds like that one changes per frame, so I would use DYNAMIC_DRAW for that. Allocating a single large buffer for it and performing a glBufferSubData() per frame is probably a fine strategy. As always, trying it and profiling it will tell you for sure.

这篇关于如何组织WebGL中的顶点数据来制作一帧一帧(非常具体)的动画程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆