Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Opengl 如何按给定方向旋转向量_Opengl_Matrix_Linear Algebra_Glm Math - Fatal编程技术网

Opengl 如何按给定方向旋转向量

Opengl 如何按给定方向旋转向量,opengl,matrix,linear-algebra,glm-math,Opengl,Matrix,Linear Algebra,Glm Math,我在循环中创建了一些随机向量/方向,作为圆顶形状,如下所示: void generateDome(glm::vec3 direction) { for(int i=0;i<1000;++i) { float xDir = randomByRange(-1.0f, 1.0f); float yDir = randomByRange(0.0f, 1.0f); float zDir = randomByRange(-1.0f, 1.

我在循环中创建了一些随机向量/方向,作为圆顶形状,如下所示:

void generateDome(glm::vec3 direction)
{
    for(int i=0;i<1000;++i)
    {
        float xDir = randomByRange(-1.0f, 1.0f);
        float yDir = randomByRange(0.0f, 1.0f);
        float zDir = randomByRange(-1.0f, 1.0f);

        auto vec = glm::vec3(xDir, yDir, zDir);
        vec = glm::normalize(vec);

        ...
        //some transformation with direction-vector
     }
     ...
}
void生成时间(glm::vec3方向)
{

对于(inti=0;i你需要创建一个旋转矩阵。因此你需要一个单位矩阵。用

glm::mat4 rotationMat(1); // Creates a identity matrix
现在,您可以使用旋转矢量SPACEC

rotationMat = glm::rotate(rotationMat, 45.0f, glm::vec3(0.0, 0.0, 1.0));
这将使矢量空间绕z轴旋转45.0度(如屏幕截图所示)。现在,您的操作即将完成。要旋转
vec
,您可以编写

vec = glm::vec3(rotationMat * glm::vec4(vec, 1.0));
注意:因为你有一个4x4矩阵,所以你需要一个vec4来将它与矩阵相乘。一般来说,在使用OpenGL时总是使用vec4是一个好主意,因为更小维度的向量无论如何都会转换为同构的顶点坐标

编辑:您也可以尝试通过包含

编辑2:当您想“朝”给定方向旋转圆顶时,您可以通过使用圆顶方向和您的“向上”向量之间的叉积来获得旋转轴。假设您想“朝”(1.0,1.0,1.0)旋转圆顶,“向上”方向是(0.0,1.0,0.0)使用:


获取旋转矩阵。叉积返回一个与“向上”和“方向”正交的向量,这就是要旋转的向量。希望这会有所帮助。

通常使用某种偏移(轴角、四元数、欧拉角等)定义旋转从一开始的位置。在我看来,你所寻找的将被更准确地描述为重新定位。幸运的是,这并不太难做到。你需要的是改变基本矩阵

首先,让我们定义我们在代码中使用的内容:

using glm::vec3;
using glm::mat3;

vec3 direction;  // points in the direction of the new Y axis
vec3 vec;        // This is a randomly generated point that we will
                 // eventually transform using our base-change matrix
要计算矩阵,您需要为每个新轴创建单位向量。从上面的示例可以看出,您希望提供的向量成为新的Y轴:

vec3 new_y = glm::normalize(direction);
现在,计算X轴和Z轴会有点复杂。我们知道它们必须相互正交,并且与上面计算的Y轴正交。构造Z轴最合理的方法是假设旋转发生在由旧Y轴和新Y轴定义的平面上。通过使用叉积,我们可以计算延迟该平面的法向量,并将其用于Z轴:

vec3 new_z = glm::normalize(glm::cross(new_y, vec3(0, 1, 0)));
从技术上讲,标准化在这里是不必要的,因为两个输入向量都已经标准化了,但为了清楚起见,我把它留下了。还要注意,当输入向量与Y轴共线时,有一种特殊情况,在这种情况下,上面的叉积是未定义的。解决这一问题的最简单方法是将其视为特殊的CAe、 我们将使用以下方法,而不是目前的方法:

if (direction.x == 0 && direction.z == 0)
{
    if (direction.y < 0) // rotate 180 degrees
       vec = vec3(-vec.x, -vec.y, vec.z);

    // else if direction.y >= 0, leave `vec` as it is.
}
else
{
    vec3 new_y = glm::normalize(direction);

    vec3 new_z = glm::normalize(glm::cross(new_y, vec3(0, 1, 0)));

    // code below will go here.
}
同样,在这种情况下,标准化不是真正必要的,但是如果
y
z
还不是单位向量,那么它就是

最后,我们将新的轴向量组合成一个基变化矩阵:

mat3 transform = mat3(new_x, new_y, new_z);
将点向量(
vec3-vec
)乘以该值,将在相同位置生成一个新点,但该点相对于新的基向量(轴):

对每个随机生成的点执行最后一步,就完成了!无需计算旋转角度或类似的任何东西

作为旁注,生成随机单位向量的方法将偏向远离轴的方向。这是因为选择特定方向的概率与到给定方向上可能的最远点的距离成正比。对于轴,这是
1.0
。对于类似
(1,1,1)
,此距离为
sqrt(3)
。可以通过丢弃位于单位球体之外的任何向量来固定此距离:

glm::vec3 vec;
do
{
    float xDir = randomByRange(-1.0f, 1.0f);
    float yDir = randomByRange(0.0f, 1.0f);
    float zDir = randomByRange(-1.0f, 1.0f);

    vec = glm::vec3(xDir, yDir, zDir);
} while (glm::length(vec) > 1.0f);  // you could also use glm::length2 instead, and avoid a costly sqrt().

vec = glm::normalize(vec);
这将确保所有方向都有相同的概率,代价是,如果你非常不幸,拾取的点可能会一次又一次地位于单位球体之外,并且可能需要很长时间才能生成一个位于单位球体内部的点。如果这是一个问题,可以修改它以限制迭代:
while(++i<4&…)
或通过增加每次迭代接受的点的半径。当它>=
sqrt(3)
时,所有可能的点都将被视为有效点,因此循环将结束。这两种方法都会导致轻微偏离轴,但在几乎任何实际情况下,都无法检测到

将上述所有代码与您的代码结合起来,我们可以得到:

void generateDome(glm::vec3 direction)
{
    // Calculate change-of-basis matrix
    glm::mat3 transform;

    if (direction.x == 0 && direction.z == 0)
    {
        if (direction.y < 0) // rotate 180 degrees
            transform = glm::mat3(glm::vec3(-1.0f, 0.0f  0.0f),
                                  glm::vec3( 0.0f, -1.0f, 0.0f),
                                  glm::vec3( 0.0f,  0.0f, 1.0f));

        // else if direction.y >= 0, leave transform as the identity matrix.
    }
    else
    {
        vec3 new_y = glm::normalize(direction);
        vec3 new_z = glm::normalize(glm::cross(new_y, vec3(0, 1, 0)));
        vec3 new_x = glm::normalize(glm::cross(new_y, new_z));

        transform = mat3(new_x, new_y, new_z);
    }


    // Use the matrix to transform random direction vectors
    vec3 point;
    for(int i=0;i<1000;++i)
    {
        int k = 4; // maximum number of direction vectors to guess when looking for one inside the unit sphere.
        do
        {
            point.x = randomByRange(-1.0f, 1.0f);
            point.y = randomByRange(0.0f, 1.0f);
            point.z = randomByRange(-1.0f, 1.0f);
        } while (--k > 0 && glm::length2(point) > 1.0f);

        point = glm::normalize(point);

        point = transform * point;
        // ...
    }
    // ...
}
void生成时间(glm::vec3方向)
{
//计算基矩阵的变化
glm::mat3变换;
if(direction.x==0&&direction.z==0)
{
如果(方向y<0)//旋转180度
转换=glm::mat3(glm::vec3(-1.0f,0.0f,0.0f),
glm::vec3(0.0f,-1.0f,0.0f),
glm::vec3(0.0f,0.0f,1.0f));
//否则,如果direction.y>=0,则将transform保留为单位矩阵。
}
其他的
{
vec3 new_y=glm::规格化(方向);
vec3 new_z=glm::normalize(glm::cross(new_y,vec3(0,1,0));
vec3 new_x=glm::normalize(glm::cross(new_y,new_z));
变换=mat3(新x、新y、新z);
}
//使用矩阵变换随机方向向量
vec3点;
对于(inti=0;i0&&glm::length2(点)>1.0f);
点=glm::标准化(点);
点=变换*点;
// ...
}
// ...
}

您好。谢谢您的回复。问题是我不知道方向向量。我需要一种计算方法来找出旋转的直角。@Bastl您指的是哪个方向向量?要旋转整个球体,只需使用
glUniformMatrix4fv将旋转矩阵传递给顶点着色器即可(UniformRottMatrix,1,GL_FALSE,glm::value_ptr(rotationMat))
。然后着色器使用该矩阵旋转每个顶点,整个球体将旋转。我有一个生成此圆顶形状的函数。我想传递di
vec = transform * vec;
glm::vec3 vec;
do
{
    float xDir = randomByRange(-1.0f, 1.0f);
    float yDir = randomByRange(0.0f, 1.0f);
    float zDir = randomByRange(-1.0f, 1.0f);

    vec = glm::vec3(xDir, yDir, zDir);
} while (glm::length(vec) > 1.0f);  // you could also use glm::length2 instead, and avoid a costly sqrt().

vec = glm::normalize(vec);
void generateDome(glm::vec3 direction)
{
    // Calculate change-of-basis matrix
    glm::mat3 transform;

    if (direction.x == 0 && direction.z == 0)
    {
        if (direction.y < 0) // rotate 180 degrees
            transform = glm::mat3(glm::vec3(-1.0f, 0.0f  0.0f),
                                  glm::vec3( 0.0f, -1.0f, 0.0f),
                                  glm::vec3( 0.0f,  0.0f, 1.0f));

        // else if direction.y >= 0, leave transform as the identity matrix.
    }
    else
    {
        vec3 new_y = glm::normalize(direction);
        vec3 new_z = glm::normalize(glm::cross(new_y, vec3(0, 1, 0)));
        vec3 new_x = glm::normalize(glm::cross(new_y, new_z));

        transform = mat3(new_x, new_y, new_z);
    }


    // Use the matrix to transform random direction vectors
    vec3 point;
    for(int i=0;i<1000;++i)
    {
        int k = 4; // maximum number of direction vectors to guess when looking for one inside the unit sphere.
        do
        {
            point.x = randomByRange(-1.0f, 1.0f);
            point.y = randomByRange(0.0f, 1.0f);
            point.z = randomByRange(-1.0f, 1.0f);
        } while (--k > 0 && glm::length2(point) > 1.0f);

        point = glm::normalize(point);

        point = transform * point;
        // ...
    }
    // ...
}