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;
我将 camPos
和 camNormal
的值存储在一个新的游戏对象中。后来,我抓取这些值并将它们应用到我的相机上。
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
以外的任何值都会移动您的平面,否则它将始终与您的对象中心点相交。
如何解决问题
在我们提出四元数之前,我们需要将 planePosition
和 planeNormal
作为向量。 planePosition
由您决定,因此此答案的其余部分将集中在 planeNormal
.
鉴于
- 平面的法向量是平面上任意两个向量的垂直向量
- 我们可以通过求两个向量的叉积来找到垂直向量。
- 我们可以用任意两点做一个向量。
- 您已经有了我们需要的 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)
为了一个学习项目,我正在 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;
我将 camPos
和 camNormal
的值存储在一个新的游戏对象中。后来,我抓取这些值并将它们应用到我的相机上。
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
以外的任何值都会移动您的平面,否则它将始终与您的对象中心点相交。
如何解决问题
在我们提出四元数之前,我们需要将 planePosition
和 planeNormal
作为向量。 planePosition
由您决定,因此此答案的其余部分将集中在 planeNormal
.
鉴于
- 平面的法向量是平面上任意两个向量的垂直向量
- 我们可以通过求两个向量的叉积来找到垂直向量。
- 我们可以用任意两点做一个向量。
- 您已经有了我们需要的 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)