最好在javascript或着色器中乘以矩阵?

时间:2014-01-08 00:05:18

标签: javascript performance webgl

我一直在看几个webgl示例。考虑MDN's tutorial。它们的顶点着色器将顶点乘以透视矩阵和世界位置矩阵:

gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);

但是uMVMatrix本身就是javascript中借助一些矩阵库计算的几种变换(平移,旋转等)的产物。

似乎直接在着色器中计算产品会更快;肯定比在.js中做得更快。他们选择这种方法有什么理由吗?

现在,我猜你可以用这种方式以任意顺序堆叠任意数量的变换,这样更灵活。但是说不需要灵活性,有没有理由避免在着色器中直接进行变换?像

这样的东西

gl_Position = uPMatrix * uRotationMatrix * uScaleMatrix * uTranslationMatrix * vec4(aVertexPosition, 1.0);

e:要添加一些上下文,在我的特定情况下,我只会渲染2D矩形实体(主要是精灵),所以顶点的数量总是只有4个。

考虑到引入库来执行快速.js矩阵乘法的开销,似乎将这些计算推入着色器绝对是我个人情况的方法。

(另外,即使它在平衡中比在javascript中做得慢,将计算分流到GPU本身也是值得的!)

2 个答案:

答案 0 :(得分:8)

取决于....

如果在着色器中执行此操作,则会对每个顶点(顶点着色器)或每个像素(片段着色器)执行此操作。即使GPU没有无限速度,所以假设你正在绘制100万个顶点。这可能是JavaScript中的一组矩阵数学计算与GPU上的100万次矩阵计算,JavaScript将获胜。

当然你的milage可能非常。每个GPU都不同。有些GPU比其他GPU快。一些驱动程序在CPU上进行顶点计算。有些CPU比其他CPU快。

您可以测试,不幸的是,因为您正在为网络编写,您不知道用户正在运行什么浏览器,也不知道CPU速度或GPU或驱动程序等等。所以,它确实取决于。

最重要的是,将矩阵传递给着色器也是一种非自由操作。换句话说,调用gl.uniformMatrix4fv一次比你在示例中显示的4倍更快。如果您正在绘制3000个对象,是否有12000个调用gl.uniformMatrix4fv(每个4个矩阵)明显慢于3000个调用(每个1个矩阵),这是您必须测试的内容。

此外,浏览器团队正致力于通过JavaScript更快地制作数学矩阵并尝试使其更接近C / C ++。

我想这意味着除了测试之外没有正确的答案,每个平台/浏览器/ gpu / drivers / cpu的结果会有所不同。

答案 1 :(得分:2)

我认为JayC和gman明白了这一点。

我也想尝试解释一下。

事实1: CPU上的Javascript和GPU上的着色器是两个不同的东西,你必须在脑海中与它们一起工作。我们在WebGL中有两种着色器。顶点着色器和片段着色器。 Vertex对每个顶点进行计算,并且片段为每个像素进行一些计算。着色器计算通常比javascript快得多。

事实2: 每个着色器从javascript获取很少的变量,它将使用它们重新计算顶点/像素参数。这些变量的数量是有限的,每个着色器循环获得相同的变量。

事实3: 着色器代码比javascript代码灵敏得多。导致javascript执行一次,但着色器始终是循环。因此,如果您将两个数字/矩阵4x4相乘,则javascript性能将相同,您将不会注意到任何内容。但着色器会在每个循环中执行此操作,因此一行可以将性能从超高降低到超低。这就是格曼所说的。

现在可以做什么?(我不完全确定这可以通过webgl着色器实现,但我认为可能是这样。)想象一下,你只有几个顶点。像3,5或20,甚至更多,它并不重要。并且您希望为每个顶点进行100000个矩阵乘法运算。所以实际上你可以先把所有100000个东西放在一起,然后用这个结果只对每个顶点进行一次乘法,你得到的结果就像你将每个顶点相乘100000次一样。

你将如何做到。您将选择这些100000矩阵并假设它们是顶点。然后你会写一个着色器,它将使它倍增,你将以某种方式获得一个结果。因此乘法将非常快。现在,您将编写一个着色器,它将使用结果并将使用最终顶点。

但我必须说两件事。我不确定一个着色器循环是否可以从webgl中的另一个循环中获取任何内容。一个循环只能用于一个顶点并且它看不到其他顶点,但我认为您可以使用attribute variable来共享它。我们只有2种着色器。其次,这个任务不需要专家的头脑,而是天才之一。

性能怎么样?想象一下,你不想做100000次乘法。你想要更少,比如2,3或20.那么如果你使用着色器做这项工作,你将不得不使用管道将数据发送到GPU然后再回到CPU,这可能比在javascript中进行计算要慢。

最后......所以即使使用着色器进行图形计算,也可以以不同的方式使用它。但是你的方法必须是不同的,有意识的和足智多谋的,这比简单的javascript乘法更难。希望它能帮到每个人。