7

所以我有一个我用 javascript 和 HTML5 编码的动画(没有库,没有插件,什么都没有,我希望它保持这种状态)。动画使用物理学(基本上是一堆不寻常的弹簧附着在质量上)来模拟一种简单的液体。这部分程序的输出是对象的网格(二维数组),每个对象都有 az 值。这很好用。将数据绘制到 HTML5 Canvas 时出现了我的问题。

这就是它的样子。 相信我,动画效果会更好。

这就是它的样子。相信我,动画效果会更好。

对于每个数据点,程序用 z 值确定的颜色绘制一个圆圈。然而,仅仅画出这些点,网格图案就非常明显,很难看到它所代表的流体。为了解决这个问题,我让圆圈更大更透明,使它们相互重叠并且颜色混合,创建一个简单的卷积模糊。结果既快速又漂亮,但有一个小缺陷:

由于圆圈是按顺序绘制的,它们的颜色值不会均匀叠加,因此后来绘制的圆圈会遮盖早期绘制的圆圈。在数学上,渲染器对圆圈的颜色值进行重复加权平均。这适用于两个圆,每个圆的值为 0.5*alpha_n,但对于三个圆,渲染器取最新圆的平均值和其他两个圆的平均值,给最新圆的值 0.5*alpha_n,但是前面的圆圈每个值为 0.25*alpha_n。随着越来越多的圈子重叠,该过程继续进行,从而产生对新圈子和旧圈子的偏见。相反,我想要的是让三个或更多圆圈中的每一个获得 0.33*alpha_n 的值,这样更早的圆圈就不会被遮挡。

这是 alpha 混合的图像。请注意,后面的蓝色圆圈遮住了之前绘制的红色和绿色圆圈:

后来的蓝色圆圈遮住了之前绘制的圆圈。

这是问题在实际中的样子。 注意肿块左侧的不同外观。

这是问题在实际中的样子。注意肿块左侧的不同外观。

为了解决这个问题,我尝试了各种方法:

  • 使用不同的画布“混合模式”。“乘法”(如上图所示)起到了作用,但造成了不幸的颜色失真。
  • 将绘图调用集中在一起。我没有让每个圆圈成为一个单独的画布路径,而是尝试将它们集中在一起。不幸的是,这与使用单独的填充颜色不兼容,而且,路径根本无法与自身融合,从而创建了哑光、单调的轮廓。
  • 交错绘图顺序。我没有按 0 到 n 的顺序画圆圈,而是先画了偶数,然后画了赔率。这只是部分解决了这个问题,并创造了一种难看的分层模式,其中赔率似乎漂浮在偶数之上。
  • 使用 putImageData 构建我自己的混合模式。我尝试使用 javascript 创建一个手动像素着色器来满足我的需求,但正如预期的那样,它太慢了。

在这一点上,我有点卡住了。我正在寻找解决或绕过这个问题的创造性方法,我欢迎你的想法。我对被告知这是不可能的不是很感兴趣,因为我可以自己解决这个问题。你将如何优雅地从这些数据点中提取流体?

4

2 回答 2

4

嗯,谢谢大家的帮助,伙计们。:) 但是,我明白,这是一个奇怪的问题,很难回答。

我把它放在这里的部分原因是它可以为未来的观众提供资源。我仍然对其他可能的解决方案很感兴趣,所以我希望其他人有任何想法可以发布答案。

无论如何,我自己想出了一个解决方案:在绘制圆圈之前,我对它们进行了梳状排序,以按 z 值将它们排序,然后将它们反向绘制。结果是价值最高的物体(应该更靠近观察者)被最后绘制,因此不会被其他圆圈遮挡。结果是模糊效果仍然存在,但它现在以一种对几何形状有意义的方式发生。这是经过此校正后的模拟效果,请注意它现在是对称的:

正常使用 整体测试

于 2013-07-04T00:37:08.917 回答
4

如果您可以将您的圈子分解为两组(偶数和赔率),这样一组内的圈子之间就没有重叠,那么以下顺序应该会产生预期的效果:

  1. 清除背景
  2. 用 1.0 的 alpha 绘制偶数(不透明)
  3. 用 1.0 的 alpha 绘制赔率(不透明)
  4. 用 0.5 的 alpha 绘制偶数

既不被偶数也不被赔率覆盖的地方将显示背景。那些仅被偶数覆盖的会以 100% 的不透明度显示偶数。被赔率覆盖的将显示 100% 不透明的赔率。两者都涵盖的那些将显示 50% 的混合。

还有其他方法可以用来尝试混合三组或更多组对象,但“精确”地做起来很复杂。如果一个人有三个或更多图像应该根据它们的 alpha 通道均匀混合,另一种方法是在全局 alpha 从 1 衰减到 0 时重复绘制所有图像(请注意,上述过程实际上是这样做的,但它是在数字上只有两个图像时精确)。数值舍入问题限制了该技术的精度,但即使执行两到三遍也可以显着降低排序导致的视觉伪影的严重性,同时使用比精确混合所需的步骤更少的步骤。

顺便说一句,如果混合模式是固定的,则可以通过在单独的画布上绘制偶数和奇数而不是圆形,而是不透明的矩形,并从其中一个画布的 alpha 通道中减去内容,从而大大加快渲染速度一个固定的“千篇一律”的画布或填充图案。如果一个人正确地计算了千篇一律的画布的内容,这种方法可以用于两组以上的画布。确定千篇一律的画布的内容可能有点慢,但只需要完成一次。

于 2014-08-05T17:17:54.217 回答