高度图的正常平均值 [英] Normal averaging of heightmap

查看:99
本文介绍了高度图的正常平均值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下计算Heightmap法线的代码

i have the following code for calculating Heightmap normals

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");
}



我理解代码得到三角形的三个顶点,然后添加它们并将它们归一化以获得平均正常。但我不知道如何获得其他三种可能性,我已经做了像下面的事情:

I understand that the code get the three vertexes of the triangle, calculate its normal and then add them and normalize them to get averaged normal. But i don't know how you can get the other three possibilities, ive been doing something like the following:

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");
}

但我不认为它给了我想要的结果,正常平均的概念,但不能找出代码。

But i don't think its giving me the result i wanted, i get the concept of normal averaging, but can't figure out the code.

推荐答案

Hi Yzwboy这里是一种方法,我会尝试平滑的法线(根据相邻的三角形进行平均):

Hi Yzwboy here is one way I would try to make "smoothed" normals (averaged based on adjacent triangles):

为了计算平滑的法线,你需要为每个顶点分配一个法线,

In order to compute "smoothed" normals you will need to assign to each vertex a normal which is averaged across the normals of the triangles adjacent to the vertex.

我将基于与所讨论的顶点相邻的两个边之间的角度来计算加权平均值(交叉积一个简单的计算):

I would calculate a weighted average based on the angle between the two edges adjacent to the vertex in question (cross product which is an easy calculation):

伪代码

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);)
}

然后通过顶点改变法线:

And then to vary the normal by vertex:

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
    }
}

你也可以计算每个三角形的面积作为权重,虽然我发现使用角度最适合看次。

You could also compute the area of a each triangle to use as the weighting, though I find using the angles works best for looks most times.

我试图使用匹配Vec3f规范的名称,以及内置函数来保存工作,但是你需要做一些编码来获得伪代码工作(我不能在这里访问GL测试环境)。

I have tried to use names which match the Vec3f spec, as well as inbuilt functions to save work, but you will need to do some coding to get the pseudocode working (I dont have access to a GL Test environment here).

希望这有助于:)

这篇关于高度图的正常平均值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆