javascript - 射线追踪启发式算法,用于声音反射仿真

标签 javascript

我是专业的土木设计师,对数学,物理和计算机充满热情。对于我的一个项目,我正在设计一个具有3个直墙和4个弧形墙的房间。声源在左壁附近。

+-------
|        \
| +       |
|        /
+-------


由于有一些空闲时间,我决定尝试使用JavaScript和Canvas API对房间的声学建模。我的目标是计算房间中的每个点:


通过将直接来自声源的声音和墙壁反射(包括弯曲的声音)相加得出的净声音强度。这将包括因平方反比定律引起的衰减和壁吸收。
通过跟踪直接来自光源的路径长度和来自墙壁的反射来跟踪混响特性。如果房间中的某个点在主要信号到达后约0.05秒后接收到反射信号,则可能是回声问题。


我假设画布大小为800x600像素,房间的实际尺寸为45x44英尺(左墙= 44ft,顶/底壁31ft,弯曲壁半径22ft),声源距左壁5ft。我将每堵墙建模为直线或圆弧方程,并编写了一个函数来告诉我点是否在房间内。对于画布中的每个像素,我将其转换为真实世界的坐标,并计算其与源的距离,并使用平方反比法来计算声强。我最终得到的是:

enter image description here

但是,不用说,这仅捕获了源中的主要反弹。它没有捕获任何反射,事实证明这些反射对我而言太难计算了。

我正在寻找有关如何做到这一点的见解。我已经尝试了以下部分:


我没有在网格上迭代房间中的点,而是尝试从源生成射线。计算直壁的反射很容易。但是弯曲的墙壁带来了一些挑战。我遇到的最大问题是:如果我从360射线开始,到光源的最接近点的每个像素点太多,但是当我们向外移动时,这些点变得如此稀疏,以至于它们之间可能存在数十个像素。相邻点。这也意味着,当我反射光线时,它肯定不会落在由主反射创建的点上,并且我无法简单地将它们相加。即使我进行插值,结果也将是不正确的,因为有些点会由于初次弹跳而记录强度,甚至更少的点会由于二次/三次弹跳而记录强度,而许多点则不会记录任何东西。在下面的图片中,我尝试了仅使用一次弹跳的方法。


enter image description here


网格迭代房间。对于房间中的每个点,计算到光源的直接方向以及光源在每面墙中的反射位置。使用这些距离来计算房间中每个采样点的净强度。对于直墙,这很容易做到。但是,对于弯曲的墙,数学对我来说异常复杂且无法解决。


               X
               +


                  +B
  +         +
  A         O


假设A是源,O是曲线的中心,B是我们当前正在测试的房间中的点,并且X是曲线上的点。对于二次弹跳,‹AXO = ‹BXO。我们知道AOB。如果找到X,则需要将BX向后扩展等于AX的距离,并且源图像将位于该位置。问题是找到X是一个非常困难的问题。即使可以做到,它也只能解决二次反弹。三级跳动将更加难以计算。

我认为选择方案2是解决此问题的更好方法。但是我没有足够的数学/计算机技能来独自解决这个问题。在这个时候,我试图解决的不是我的项目,而是我的个人好奇心。如果您能解决这个问题并分享您的解决方案,我将不胜感激。或者,如果您只是可以让我深入了解这个问题,我将很乐意对此做进一步的工作。

我缺乏计算插值和光线跟踪的专业知识(我认为这是解决此问题所必需的)。

谢谢,
阿西姆

最佳答案

所以。有了来自lara的出色指导,并且深入研究了矩阵数学和bresenham的线条渲染算法,我终于能够完成这个爱好项目。 =)对于任何希望遵循此路线以解决类似问题的人,此处概述了这些步骤。


沟代数方程式有利于矩阵数学。沟线有利于参数线。
用射线和圆表示壁。行可以表示为[x y 1] = [x0 y0 1] + t*[dx dy 1]。圆圈可以表示为(X - C)^2 = r^2
从光源向外投射射线。对于每条射线,计算其与墙之一的交点,并调整其大小以使其从起点到交点。
计算交点时,请计算交点处墙的法线向量。对于直墙,计算法线很简单([-dy dx 1])。对于圈子,法线是X - C
使用矩阵将入射光线反射到法线周围。
重复该过程,以根据需要反弹。
将计划所在的世界坐标系映射到一个单元坐标系中,以将世界划分为一个网格单元。每个单元的大小(以英尺为单位)可以为1'-0“ x 1'-0”。再次使用矩阵在两个坐标系之间进行转换。
使用转换矩阵将射线转换为单元坐标系。
使用Bresemham的Line算法确定射线穿过哪些细胞。对于每个单元,使用平方反比定律来计算该单元的射线强度。将此值添加到单元格网格。
最后,使用Canvas API和另一个转换矩阵在“单元坐标系”到“屏幕坐标系”之间进行转换,并在屏幕上呈现单元格。


以下是我使用此功能所获得的一些屏幕截图:

1
从光源发出并与墙壁相交的光线。

2
计算单个光线的多次反射。

3
计算从光源发出的所有光线的单反射。

4
使用Bresenham的Line算法识别射线穿过的细胞并绘制对数强度。

5
仅渲染所有主光线的所有像元。

6
仅渲染所有单元格的反射光线。苛性表面在此处清晰可见。

7
使用颜色编码为主光线和反射光线渲染所有像元。

在这个项目的过程中,我学到了很多非常有趣的数学技能。我现在更加尊重矩阵。在我整个大学期间,我一直在想是否我一生中是否需要使用Bresenham's Line算法,因为所有图形库都内置了线描算法。第一次,我发现我需要直接使用该算法,没有它,该项目将无法实现。

我将很快在GitHub上提供代码。感谢所有为我对这些概念的理解做出贡献的人。

阿西姆

关于javascript - 射线追踪启发式算法,用于声音反射仿真,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57385803/

相关文章:

javascript - 如何在分配给数组索引的对象上调用方法?

javascript - 使用 function.bind 将函数绑定(bind)到 this

JavaScript:split() 但保留逗号、点和其他分隔符

javascript - 为什么这个函数返回-3?

javascript - 下拉菜单显示我的 JSON 文件中的第一个值而不是默认文本

javascript - 最低 IE9 浏览器要求和其他等效浏览器版本

javascript - Backbone.js 访问另一个 View 函数

javascript - 将 Gulp 与 Django manage.py 集成

javascript - jquery scrollTop 弹跳

javascript - 在 Opera 中发出 iframe 的重定向父级问题