使用glm将vec3与mat4相乘

3

目前,我将 vec3 转换成 vec4,与矩阵相乘,然后再转换回 vec3

代码:

glm::vec3 transformed = glm::vec3(matrix * glm::vec4(point, 0.0))

它可以工作,但我认为这不是计算的好方法。是否有可能在不将其转换为vec4并返回的情况下,在vec3上应用mat4

2个回答

5

在使用OpenGL时,坚持使用齐次坐标是非常明智的。对于3D空间,这些是4D向量,其中通常第四个元素等于1。当您这样做时,所有计算都在4维空间中进行,因此无需在任何地方进行转换。

还要注意,在您的示例中,实际上会丢失在变换矩阵中记录的任何平移。如果要保留这一点,需要将第4个元素设为1,而不是0。

《红皮书》附录F描述了OpenGL内部如何以及为什么使用齐次坐标。


我在第四个坐标处看到了0.01.0。哪一个是正确的?零第四个坐标似乎是正确的,例如如果我计算一个向量的长度。 - Iter Ator
在这种情况下,1.0是正确的,否则您将失去转换矩阵的第四列,该列通常包含转换的平移部分。 - wich
据我所知,4D向量的长度定义为:sqrt(x*x+y*y+z*z+w*w) - Iter Ator
确切地说,这是4D空间中4D向量的长度,但它不是由齐次坐标表示的3D点到原点的距离。这些是不同的东西。 - wich
1
如果vec3表示一个点,w应该为1,否则,如果它表示一个方向,w应该为0。 - Liu Hao
显示剩余4条评论

0

mat4是一个4乘4的矩阵,因此您需要一个4维向量来进行乘法运算。

第四个维度对于3D数学非常有用,可以区分3D空间点(1)和3D向量(0)。

这里缺少很多运算符,但我希望您能理解。

class point3
{
public:
    vec4 p;

public:
    point3();
    point3(const point3& rhs);
    point3(const point3& rhs);
    point3(float x, float y, float z);
    point3& operator=(const point3&rhs);
    vector3 operator-(const point3&rhs);
    point3 operator+(const vector3&rhs);
    point3& operator+=(const vector3&rhs);
};

point3::point3():p.x(0), p.y(0), p.z(0), p.w(1)
{

}
point3::point3(const point3& rhs):p(rhs.p)
{

}
point3::point3(const point3& rhs):p(rhs.p)
{

}
point3::point3(float x, float y, float z):p.x(x), p.y(y), p.z(z), p.w(1)
{

}
point3& point3::operator=(const point3&rhs)
{
    return (p=rhs.p);
}
vector3 point3::operator-(const point3&rhs)
{
    vector3 result;
    result.p=(p-rhs.p);
    return result;
}
point3 point3::operator+(const vector3&rhs)
{
    point3 result;
    result.p=(p+rhs.p);
    return result;
}
point3& point3::operator+=(const vector3&rhs)
{
    p=(p+rhs.p);
    return p;
}

class vector3
{
public:
    vec4 p;

public:
    vector3();
    vector3(const vector3& rhs);
    vector3(const vector3& rhs);
    vector3(float x, float y, float z);
    vector3& operator=(const vector3&rhs);
    vector3 operator-(const vector3&rhs);
    point3 operator-(const point3&rhs);
    point3 operator+(const point3&rhs);
    vector3 operator+(const vector3&rhs);
    vector3& operator+=(const vector3&rhs);
};
vector3::vector3():p.x(0), p.y(0), p.z(0), p.w(0)
{
}
vector3::vector3(const vector3& rhs):p(rhs.p)
{
}
vector3::vector3(const vector3& rhs):p(rhs.p)
{
}
vector3::vector3(float x, float y, float z):p.x(x), p.y(y), p.z(z), p.w(0)
{
}
vector3& vector3::operator=(const vector3&rhs)
{
    p=rhs.p;
    return p;
}
vector3 vector3::operator-(const vector3&rhs)
{
    vector3 result;
    result.p=(p-rhs.p);
    return result;
}
point3 vector3::operator-(const point3&rhs)
{
    point3 result;
    result.p=(p-rhs.p);
    return result;
}
point3 vector3::operator+(const point3&rhs)
{
    point3 result;
    result.p=(p+rhs.p);
    return result;
}
vector3 vector3::operator+(const vector3&rhs)
{
    vector3 result;
    result.p=(p+rhs.p);
    return result;
}
vector3& vector3::operator+=(const vector3&rhs)
{
    p=(p+rhs.p);
    return p;
}

那我应该把我的三维向量存储在vec4中吗? - Iter Ator
通常我会创建一个包装器,两个类,point3和vector3,它们内部都有vec4,然后重载运算符以使每个类正常工作。这并不需要太多的工作,因为基本上你已经通过glm完成了所有艰苦的工作。 - Asier Sánchez Rodríguez
作为一条小知识,第四维仅用于将所有变换连接成一个单独的矩阵。这样,平移矩阵只会影响到w坐标值为1的4D向量。 - Asier Sánchez Rodríguez
此帖子可能会帮助您理解为什么区分向量中的w维度很重要。链接 - Asier Sánchez Rodríguez
通常我会创建一个包装器。这怎么可能呢?你能给我一些关键词吗,用这些关键词我可以找到一些关于它的示例代码或教程吗? - Iter Ator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接