相对于法线

时间:2015-08-27 18:54:02

标签: unity3d transform hlsl cg geometry-surface

在表面着色器中,给定世界的上轴(以及其他轴),世界空间位置和世界空间中的法线,我们如何将世界空间位置旋转到正常的空间?

也就是说,给定向上矢量和非正交目标向上矢量,我们如何通过旋转其向上矢量来转换位置?

我需要这个,所以我可以得到仅受对象旋转矩阵影响的顶点位置,我 无法访问。

这是我想要做的图形可视化:

  • 向上是世界向上
  • 目标是世界空间正常
  • Pos是任意的

该图是二维的,但我需要为3D空间解决这个问题。

vector diagram

2 个答案:

答案 0 :(得分:0)

您似乎正在尝试通过将向上转换为 new_up 的相同轮播来旋转 pos

使用找到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
float 3x3 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 已标准化。

如果"目标正常"是一个常数, R 的计算可以(并且应该)每帧只发生一次。我建议在CPU端进行,并将其作为变量传递到着色器中。为每个顶点/片段计算它是昂贵的,考虑你实际需要的是什么。

如果 pos 是vector-4,只需使用前三个元素执行上述操作,第四个元素可以保持不变(无论如何它在这个上下文中并不真正意味着什么)

我远离可以运行着色器代码的机器,所以如果我在上面做了任何语法错误,请原谅我。

答案 1 :(得分:-2)

未经过测试,但应该能够输入起始pointaxis。然后你要做的就是改变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);
    }
}