Unity:平面由三点定义为四元数

Unity: plane defined by three points to quaternions

为了一个学习项目,我正在 Unity 中处理一个 3D 文件。目的是放置三个标记,通过三个标记绘制一个平面并使用该平面进行截面切割。 我能够定义标记、添加平面并进行剖面切割。但是,由于截面切割需要用四元数描述平面,所以我必须以某种方式从我拥有的平面转换值,但我不知道如何做。

定义平面的标记(样本值):

Vector3 p1 = new Vector3(1.1f, 2.6f, 3.5f);
Vector3 p2 = new Vector3(.4f,  4.5f, 2.5f);
Vector3 p3 = new Vector3(6.1f, 6.9f, 1.4f);
Plane cut  = new Plane(p1, p2, p3);

目前,我使用 new Plane but I am willing to define it differently (e.g., using PrimitiveType.Plane) 定义平面。我只用这架飞机作为参考。 接下来,我使用 existing shader. However, this shader requires a PlaneNormal and a PlanePosition with four values, see the shader screenshot.

添加截面

简而言之,我的问题是:如何将我拥有的三个坐标转换为着色器所需的八个值? 或者,如果另一个着色器更适合这里,那也很好。

解决方案

在您的回答的帮助下,我找到了解决方案。 使用三个点,我定义了一个平面并将其法线存储为 Vector4。

Plane finger = new Plane(p1, p2, p3);
Vector3 normal = (finger.normal);
Vector4 planeNormal = Vector4.zero;
planeNormal.x = normal.x;
planeNormal.y = normal.y;
planeNormal.z = normal.z;
digitNormals[digit-1] = planeNormal;

同样,我将位置定义为三个点的平均值。因此,我写了一个函数AvgVector(),取x、y、z轴的平均值。

Vector3 position = AvgVector(p1, p2, p3);
Vector4 planePosition = Vector4.zero;
planePosition.x = position.x;
planePosition.y = position.y;
planePosition.z = position.z;
Quaternion camNormal = Quaternion.LookRotation(normal);
digitPlanes[digit-1] = planePosition;

我将 camPoscamNormal 的值存储在一个新的游戏对象中。后来,我抓取这些值并将它们应用到我的相机上。

rend.material.SetVector("_PlaneNormal", digitNormals[dig-1]);
rend.material.SetVector("_PlanePosition", digitPlanes[dig-1]);
SectionCamera.transform.position = section.transform.position;
SectionCamera.transform.LookAt(clone.transform);
RelocateMarker(c, 3);

我知道我使用了很多变量,这可能会限制这些片段的实用性。但是,整个代码很快就会在 https://github.com/TimJohDij/marker-maker.

上线

TL;DR:这些字段不被解释为四元数。只需将您的平面位置和平面法线插入这些字段,就好像它们是 Vector3 的一样,忽略 w 字段。如果您不确定如何获取这些向量,请阅读下文。

我们先来看看着色器要求的两个四元数。

平面法线

planeNormal 是平面面对的方向或背离平面的向量。 因此,如果您想使用此着色器将对象完全水平切片,planeNormal 将是代表 Vector3.Up 的四元数。更深入的解释是平面的法向量是平面上任意两个向量的垂直向量。

平面位置

planePosition是平面的中心点。将其视为切片偏移量。将此设置为 Quaternion.identity 以外的任何值都会移动您的平面,否则它将始终与您的对象中心点相交。

如何解决问题

在我们提出四元数之前,我们需要将 planePositionplaneNormal 作为向量。 planePosition 由您决定,因此此答案的其余部分将集中在 planeNormal.

鉴于

  1. 平面的法向量是平面上任意两个向量的垂直向量
  2. 我们可以通过求两个向量的叉积来找到垂直向量。
  3. 我们可以用任意两点做一个向量。
  4. 您已经有了我们需要的 3 个点来制作位于您的平面上的两个向量(我们将重复使用 1 个点)。

所以我们需要从您用来定义平面的三个点生成 2 个向量,我们将对这两个向量进行叉积,得到的向量将是我们的法向量。

Vector3 vec1 = p1 - p3;
Vector3 vec2 = p2 - p3;
Vector3 normalVec = Vector3.Cross(vec1, vec2);

现在,在使用着色器后,我发现那些字段实际上只是具有额外值的 Vector3。据我所知,w 值被忽略了,所以一旦找到法向量,就可以将其值插入 x、y 和 z 字段。

但要真正回答您的问题,将向量转换为四元数的最简单方法是使用 LookRotation().

Quaternion planeNormal = Quaternion.LookRotation(normalVec)