如何计算盒子的法线?

时间:2017-08-10 02:26:19

标签: algorithm graphics

我正在尝试创建一个计算模型/网格法线的算法。人们一直在告诉我使用两个向量之间的交叉产品,这些看起来好像是个好主意,直​​到我发现它可能并不总是有效。例如,想象一个盒子,其正面位于原点,背面朝向Z轴。这是一张图片:

enter image description here

我为写不好的手写道歉,但这不应该有任何意义。如你所见,我越过v和u使法线指向正z轴。但是,如果我使用相同的计算来计算背面的法线,那么显然法线将是指向形状内部的矢量。结果是我有不准确的法线来计算灯光的亮度。我希望法线在任何时候都远离模型。

我知道有更好的方法来计算正常情况,但我不知道它是什么。任何人都可以向我建议另一种计算正常的算法来解决这个问题吗?如果没有,则必须有一种方法来检查法线是否面向对象/模型内部。如果是这样,那么你可以在答案中建议它,我会在哪里找到解释,因为我希望对这些方法的工作方式有直觉。

2 个答案:

答案 0 :(得分:1)

大多数软件包遵循三角形索引的可配置循环排序 - 顺时针或逆时针。因此,它们导出的所有网格都具有自洽的排序,只要您的程序使用相同的约定,您就不必担心。

话虽如此,我想你想知道在索引排序不一致的假设(?)情况下该怎么做。

我们可以使用的一种方法是 ray-intersection 。重要的定理是一条光源,它的光源在网格之外只会与网格相交偶数次,如果在内部,则是奇数。

为此,我们可以执行以下操作:

  • 计算&#34;正常&#34;使用上面的交叉产品(并将其标准化)=&gt; public async Task<ActionResult> DoSomeAsyncStuff() { var model = new MyModel(); await Task.Delay(20000);//My long-running process is getting data from an API with "HttpWebRequest". model.Name = "Something"; //Assigning other model properties return PartialView("_InnerView", model); }
  • 取三角形上的任意一点(最好是中点)
  • 通过一些小的 epsilon 值沿法线递增此点(取决于您的浮点格式和模型的大小 - 我说N表示单1e-4 }} for double precision)=&gt; 1e-8
  • 将此光线P与网格中的所有三角形相交(一个好的算法是Möller–Trumbore
  • 如果交叉点的数量是偶数,则光线从网格外部开始;这意味着网格中的法线点向外(因为您从表面上的点增加了它的源)。 - 当然,反之亦然。

次要(-ish?)题外话题:对于上面的一种天真的方法,循环遍历网格中的所有三角形,将是[dir = N, src = P] - 因此整个过程会有< em>二次时间复杂度。这对于非常约20个三角形的小网格(例如一个盒子)来说非常好,但对于任何更大的三角形都不是理想的!

您可以使用空间细分技术来降低此交叉步骤的成本:

  • KD树/八叉树:这些需要O(n)(对于最佳算法,即 - Ingo Wald's paper)来构建,但交叉点保证为{{1如果做得好的话。总体复杂性将是O(n log n),这几乎是你能得到的最好的
  • 网格:这只是将搜索空间和三角形分成更小的框。构造是O(log n)并且内存效率更高。交点时间仍为O(n log n),但常数因子 小于天真方法的

答案 1 :(得分:0)

交叉产品不可交换,因此v x uu x v不同。事实上,他们恰恰相反。

对于正面,您需要u x v(假设您在r ight-hand coordinate system中),以及您想要越过v x u的背面。

有关交叉向量如何工作的详细信息,请参阅right-hand rule