顶点相对于法线的位置
Vertex position relative to normal
在表面着色器中,给定世界的上轴(以及其他轴)、世界 space 位置和世界中的法线 space ,我们如何才能将世界space位置旋转到法线的space?
也就是说,给定一个上向量和一个非正交的目标上向量,我们如何通过旋转它的上向量来变换位置?
我需要这个,这样我就可以获得仅受对象旋转矩阵影响的顶点位置,我无法访问它。
这是我想做的事情的图形可视化:
- Up 是世界向上矢量
- 目标是世界space正常
- 位置任意
图表是二维的,但我需要解决这个问题以获得 3D space。
未测试,但应该能够输入起始 point
和 axis
。然后你所做的就是改变 procession
这是一个标准化的 (0-1) 沿圆周浮动,你的点将相应更新。
using UnityEngine;
using System.Collections;
public class Follower : MonoBehaviour {
Vector3 point;
Vector3 origin = Vector3.zero;
Vector3 axis = Vector3.forward;
float distance;
Vector3 direction;
float procession = 0f; // < normalized
void Update() {
Vector3 offset = point - origin;
distance = offset.magnitude;
direction = offset.normalized;
float circumference = 2 * Mathf.PI * distance;
angle = (procession % 1f) * circumference;
direction *= Quaternion.AngleAxis(Mathf.Rad2Deg * angle, axis);
Ray ray = new Ray(origin, direction);
point = ray.GetPoint(distance);
}
}
看起来您正试图通过将 up 转换为 [= 的相同旋转来旋转 pos 40=].
使用找到的旋转矩阵here,我们可以使用以下代码旋转pos。这将在表面函数或补充顶点函数中起作用,具体取决于您的应用程序:
// Our 3 vectors
float3 pos;
float3 new_up;
float3 up = float3(0,1,0);
// Build the rotation matrix using notation from the link above
float3 v = cross(up, new_up);
float s = length(v); // Sine of the angle
float c = dot(up, new_up); // Cosine of the angle
float3x3 VX = float3x3(
0, -1 * v.z, v.y,
v.z, 0, -1 * v.x,
-1 * v.y, v.x, 0
); // This is the skew-symmetric cross-product matrix of v
float3x3 I = float3x3(
1, 0, 0,
0, 1, 0,
0, 0, 1
); // The identity matrix
float3x3 R = I + VX + mul(VX, VX) * (1 - c)/pow(s,2) // The rotation matrix! YAY!
// Finally we rotate
float3 new_pos = mul(R, pos);
这是假设 new_up 已标准化。
如果 "target up normal" 是一个常量,R 的计算可以(并且应该)每帧只发生一次。我建议在 CPU 侧执行此操作并将其作为变量传递到着色器中。为每个 vertex/fragment 计算它的成本很高,请考虑您实际需要的是什么。
如果你的pos是一个vector-4,只需要对前三个元素进行上述操作即可,第四个元素可以保持不变(这里没有任何意义)无论如何上下文)。
我远离可以运行着色器代码的机器,所以如果我在上面有任何语法错误,请原谅我。
在表面着色器中,给定世界的上轴(以及其他轴)、世界 space 位置和世界中的法线 space ,我们如何才能将世界space位置旋转到法线的space?
也就是说,给定一个上向量和一个非正交的目标上向量,我们如何通过旋转它的上向量来变换位置?
我需要这个,这样我就可以获得仅受对象旋转矩阵影响的顶点位置,我无法访问它。
这是我想做的事情的图形可视化:
- Up 是世界向上矢量
- 目标是世界space正常
- 位置任意
图表是二维的,但我需要解决这个问题以获得 3D space。
未测试,但应该能够输入起始 point
和 axis
。然后你所做的就是改变 procession
这是一个标准化的 (0-1) 沿圆周浮动,你的点将相应更新。
using UnityEngine;
using System.Collections;
public class Follower : MonoBehaviour {
Vector3 point;
Vector3 origin = Vector3.zero;
Vector3 axis = Vector3.forward;
float distance;
Vector3 direction;
float procession = 0f; // < normalized
void Update() {
Vector3 offset = point - origin;
distance = offset.magnitude;
direction = offset.normalized;
float circumference = 2 * Mathf.PI * distance;
angle = (procession % 1f) * circumference;
direction *= Quaternion.AngleAxis(Mathf.Rad2Deg * angle, axis);
Ray ray = new Ray(origin, direction);
point = ray.GetPoint(distance);
}
}
看起来您正试图通过将 up 转换为 [= 的相同旋转来旋转 pos 40=].
使用找到的旋转矩阵here,我们可以使用以下代码旋转pos。这将在表面函数或补充顶点函数中起作用,具体取决于您的应用程序:
// Our 3 vectors
float3 pos;
float3 new_up;
float3 up = float3(0,1,0);
// Build the rotation matrix using notation from the link above
float3 v = cross(up, new_up);
float s = length(v); // Sine of the angle
float c = dot(up, new_up); // Cosine of the angle
float3x3 VX = float3x3(
0, -1 * v.z, v.y,
v.z, 0, -1 * v.x,
-1 * v.y, v.x, 0
); // This is the skew-symmetric cross-product matrix of v
float3x3 I = float3x3(
1, 0, 0,
0, 1, 0,
0, 0, 1
); // The identity matrix
float3x3 R = I + VX + mul(VX, VX) * (1 - c)/pow(s,2) // The rotation matrix! YAY!
// Finally we rotate
float3 new_pos = mul(R, pos);
这是假设 new_up 已标准化。
如果 "target up normal" 是一个常量,R 的计算可以(并且应该)每帧只发生一次。我建议在 CPU 侧执行此操作并将其作为变量传递到着色器中。为每个 vertex/fragment 计算它的成本很高,请考虑您实际需要的是什么。
如果你的pos是一个vector-4,只需要对前三个元素进行上述操作即可,第四个元素可以保持不变(这里没有任何意义)无论如何上下文)。
我远离可以运行着色器代码的机器,所以如果我在上面有任何语法错误,请原谅我。