【问题标题】:Normal averaging of heightmap高度图的正常平均
【发布时间】:2013-11-11 11:50:33
【问题描述】:

我有以下代码用于计算高度图法线

void CalcMapNormals(HeightMap * map, Vec3f normals[])
{
int     dst, i, j, right, bottom;
Vec3f   p0, p1, p2;
Vec3f   n0;

/* Avoid writing map->rows|cols - 1 all the time */
right = map->cols - 1;
bottom = map->rows - 1;

dst = 0;
for (i = 0; i < map->rows; i++) {
    for (j = 0; j < map->cols; j++) {
        Vec3Set(normals[dst], 0, 0, 0);
        /* Vertex can have 2, 3, or 4 neighbours horizontally and vertically */
        if (i < bottom && j < right) {
            /* Right and below */
            GetHeightPoint(map, i, j, p0);
            GetHeightPoint(map, i + 1, j, p1);
            GetHeightPoint(map, i + 1, j + 1, p2);
            CalcTriNormal(n0, p0, p1, p2);
            VecAdd(normals[dst], normals[dst], n0);
        }
        /*  TODO: the other three possibilities */
        VecNormalize(normals[dst]);
        dst += 1;
    }
}
/* Sanity check */
if (dst != map->rows * map->cols)
    Fail("Internal error in CalcMapNormals: normals count mismatch");
}

我知道代码获取三角形的三个顶点,计算其法线,然后将它们相加并将它们归一化以获得平均法线。但我不知道您如何获得其他三种可能性,我一直在做以下事情:

void CalcMapNormals(HeightMap * map, Vec3f normals[])
{
int     dst, i, j, right, bottom;
Vec3f   p0, p1, p2;
Vec3f   n0;
Vec3f   p3, p4, p5;
Vec3f   n1;
Vec3f   p6, p7, p8;
Vec3f   n2;
Vec3f   p9, p10, p11;
Vec3f   n3;
/* Avoid writing map->rows|cols - 1 all the time */
right = map->cols - 1;
bottom = map->rows - 1;

dst = 0;
for (i = 0; i < map->rows; i++) {
    for (j = 0; j < map->cols; j++) {
        Vec3Set(normals[dst], 0, 0, 0);
        /* Vertex can have 2, 3, or 4 neighbours horizontally and vertically */
        if (i < bottom && j < right) {
            /* Right and below */
            GetHeightPoint(map, i, j, p0);
            GetHeightPoint(map, i + 1, j, p1);
            GetHeightPoint(map, i + 1, j + 1, p2);
            CalcTriNormal(n0, p0, p1, p2);
            VecAdd(normals[dst], normals[dst], n0);
        }
        if ( i > bottom && j > 0)
        {
            GetHeightPoint(map, i, j, p3);
            GetHeightPoint(map, i + 1, j, p4);
            GetHeightPoint(map, i, j -1, p5);
            CalcTriNormal(n1, p3, p4, p5);
            VecAdd(normals[dst], normals[dst], n1);
        }
        if ( i > 0 && j > 0)
        {
            GetHeightPoint(map, i, j, p6);
            GetHeightPoint(map, i, j - 1, p7);
            GetHeightPoint(map, i - 1, j, p8);
            CalcTriNormal(n2, p6, p7, p8);
            VecAdd(normals[dst], normals[dst], n2);

        }
        if ( i > bottom && j < right)
        {

            GetHeightPoint(map, i, j, p9);
            GetHeightPoint(map, i-1, j, p10);
            GetHeightPoint(map, i, j+1, p11);
            CalcTriNormal(n3, p9, p10, p11);
            VecAdd(normals[dst], normals[dst], n3);
        }
        /*  TODO: the other three possibilities */
        VecNormalize(normals[dst]);
        dst += 1;
    }
}
/* Sanity check */
if (dst != map->rows * map->cols)
    Fail("Internal error in CalcMapNormals: normals count mismatch");
}

但我不认为它给了我想要的结果,我得到了正常平均的概念,但无法弄清楚代码。

【问题讨论】:

  • 那么您是在寻找每个顶点的法线还是每个三角形面的法线?只是为了澄清我的意思,所以我可以简洁地回答:) 我问的原因是因为听起来你正在尝试获取三角形所有 3 个顶点的法线,然后对它们进行平均,这与 a 的法线相同三角脸。
  • @GMasucci 谢谢,我试图获得每个顶点的平均法线,基本上我试图让所有相邻的三角形共享一个顶点(最多 6 个三角形可以共享一个顶点,我使用 4 ) 并获得平均正常值,如果我没有清楚地解释这一点,请见谅。

标签: c++ opengl normals heightmap


【解决方案1】:

嗨,Yzwboy,这是我尝试制作“平滑”法线的一种方法(基于相邻三角形的平均值):

为了计算“平滑”的法线,您需要为每个顶点分配一个法线,该法线是在与该顶点相邻的三角形的法线上平均的。

我会根据与相关顶点相邻的两条边之间的角度计算加权平均值(叉积很容易计算):

伪代码:

Vec3F faceNormal(int face_id, int vertex_id) // assumes C-->B-->A is clockwise
{
    Vec3f A = triangleMesh.face[face_id].vertex[vertex_id];       // A
    Vec3f B = triangleMesh.face[face_id].vertex[(vertex_id+1)%3]; // B
    Vec3f C = triangleMesh.face[face_id].vertex[(vertex_id+2)%3]; // C
    Vec3f BA = B-A;
    Vec3f CA = C-A;
    Vec3f Normal = BA.cross(CA);

    float sin_alpha = length(Normal) / (BA.len() * CA.len() );  // depending on your implementation of Vec3f it could be .magnitude() or .length() instead of .len()
    return (Normal.normalize() * asin(sin_alpha);)
}

然后通过顶点改变法线:

void computeNormals() {
    for (vertex v in triangleMesh)
    {
        Vec3f Normal (0,0,0);
        for (int i = 0;i < TriangleCount;i++)
            if (triangleMesh.face[i].contains(v) )
            {
                int vertID = vertexPositionInTriangle(i,v); //Can be 0,1 or 2.  Use an enum to make A = 0, B=1, C=2 if that is easier to read:)
                Normal = Normal + faceNormal(i,vertID);
            }
        addNormalToVertexV(Normal.normalize(),v); // this is a function to set the normal for a vertex, the vertex class must have a member for normal though and the arguments for the function are Vec3f, Vec3f
    }
}

您还可以计算每个三角形的面积以用作权重,但我发现大多数情况下使用角度最适合外观。

我尝试使用符合 Vec3f 规范的名称以及内置函数来节省工作,但您需要进行一些编码才能使伪代码正常工作(我无法访问此处的 GL 测试环境)。

希望这会有所帮助:)

【讨论】:

  • 如果您再次遇到困难,请告诉我,我会尽力提供帮助:)
  • 谢谢,我现在明白了,如果还有问题我再问:)
猜你喜欢
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多