【问题标题】:Vertex normals not being calculated correctly未正确计算顶点法线
【发布时间】:2021-12-05 02:04:45
【问题描述】:

我正在尝试通过将 3 个向量相乘以沿这些法线挤出顶点来计算法线,它仅适用于对象的一半,请参阅this 图像作为参考(粉红色线代表挤出的顶点)

以下是计算法线的方法:

    for (Vertex& v : vertices)
    {

        glm::vec3 normal = { 0,0,0 };

        for (int i = 0; i < vertices.size(); i++)
        {
            const glm::vec3& a = vertices[i].position;
            const glm::vec3& b = vertices[i + 1].position;
            const glm::vec3& c = vertices[i + 2].position;

            glm::vec3 n = (b - a) * (c - a);
            
            normal += glm::normalize(n);
        }

        v.normal = glm::normalize(normal);
    }

编辑1: 我尝试使用 glm::cross(b-a, c-a),但输出始终为零,对象现在看起来像 this

这是代码:

    for (Vertex& v : vertices)
    {

        glm::vec3 normal = { 0,0,0 };

        for (int i = 0; i < vertices.size(); i++)
        {

            const glm::vec3& a = vertices[i].position;
            const glm::vec3& b = vertices[i + 1].position;
            const glm::vec3& c = vertices[i + 2].position;

            glm::vec3 n = glm::cross( (b - a), (c - a) );
             
            normal += glm::normalize(n);
        }

        v.normal = glm::normalize(normal);
    }

另外,每个向量中的 Y 分量总是等于 0

编辑 2: 基本形状是二维的,它只使用 x,z 分量,然后沿 y 轴拉伸,this 是顶点处理的工作原理

-- 更新--

我设法通过首先计算顶点切线然后使用该切线计算法线来解决问题,但这会导致一个小问题,当我更改对象的位置时,切线/法线计算会使对象变形并且我想这是与规范化有关的问题,我可能会为此创建一个单独的帖子,我会在创建它时包含指向该帖子的链接。

glm::vec3 GetUnitNormal(const glm::vec2& p1, const glm::vec2& p2, const float s)
    {
        const glm::vec2 p3 = p1 + ( (p2 - p1) * s );
        const float m = (p3.y - p1.y) / (p3.x - p1.x);
        const float c = p1.y - m * p1.x;
        const float y = (m * p1.x) + c;

        const glm::vec2 tangent = glm::normalize(glm::vec2(p1.x, y));
        glm::vec3 normal = glm::vec3(-tangent.y, 0, tangent.x);

        return glm::normalize(normal);
    }

编辑 4: here is帖子链接

【问题讨论】:

  • 你的形状是二维的吗?
  • @n.1.8e9-where's-my-sharem。基础顶点是 2d 的,它们只使用 x、z 分量,在挤压之后,新对象会沿 y 轴挤压
  • 我不明白你在做什么。法线是否应该沿 y 轴延伸?那么无论顶点如何,它总是(0,1,0)。
  • @n.1.8e9-where's-my-sharem。抱歉混淆,我正在尝试计算每个顶点的法线,以便我可以沿着它们的法线挤出这些顶点,这将使形状具有厚度,在第三张图像中,这表示为第二步,我已经知道如何挤出它们沿 y 轴,这是第三张图像的最后一步(位于第二个编辑处)
  • 您正在计算一个法线向量。法线向量在表面上的某个点垂直于某个表面。它是什么表面?

标签: c++ opengl glm-math normals


【解决方案1】:

确保您使用的是叉积和 * 运算符。这被定义为

template<typename T, qualifier Q>
    GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)
    {
        return vec<3, T, Q>(
            v1.x * v2.x,
            v1.y * v2.y,
            v1.z * v2.z);
    }

应该是:

glm::vec3 n = cross((b - a), (c - a));

【讨论】:

  • 使用 glm::cross( b-a, c-a ) 我总是得到 0 作为输出,我编辑了原始帖子
  • @UserNotFound 那么abc 是什么?如果向量之一为 (0, 0, 0) 或向量在同一方向上,则叉积为 (0, 0, 0)。
  • @Rabbid76 我可以确认没有一个向量是 0/指向同一个方向,我猜问题的根源是形状本身,因为它的向量被视为 2d 向量( Y 分量始终为 0)
  • @UserNotFound 如果您的顶点只有一个 x 和 y 分量,则叉积的结果只有一个 z 分量(0、0、+/-z)。这是正常向量的本质。
  • @UserNotFound 你提到它只适用于一半的形状,我知道你还需要指向屏幕的另一个方向的法线(就像这张图片一样)ibb.co/r5hrXxQ。如果这是正确的,您需要做的就是切换叉积的参数以获得另一个向量。因为 a x b != b x a
猜你喜欢
  • 2013-02-15
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-25
  • 2010-11-12
  • 2021-12-19
  • 2012-04-06
相关资源
最近更新 更多