具有平均法线的高度场

Posted

技术标签:

【中文标题】具有平均法线的高度场【英文标题】:Height Field with average normals 【发布时间】:2020-10-22 13:35:13 【问题描述】:

我正在创建高度场并且我想创建它的法线(面/顶点),我正在使用三角形来创建网格。我已经计算了 GL 四边形法线,但在这里混淆了三角形而不是四边形。 我搜索了互联网,发现存在两种类型的法线,例如每个面和每个顶点,但没有找到任何与我的代码相关的帮助。 这是我现在正在做的创建高度场。

int average_normal()

 
glPushMatrix();


GLfloat xdelta=xsize/xsteps;
GLfloat zdelta=zsize/zsteps;
   
glNormal3f(0,1,0);

for (int x=0; x<xsteps-1; x++)
    for (int z=0; z<zsteps-1; z++)
    
    
    glBegin(GL_TRIANGLES);
    setMaterialHeight(map[x][z]);
    glNormal3f(0, 0, 1);
    glVertex3f(xdelta*x,map[x][z],zdelta*z);
    setMaterialHeight(map[x+1][z]);
    glNormal3f(0, 0, 1);
    glVertex3f(xdelta*x+xdelta,map[x+1][z],zdelta*z);
    setMaterialHeight(map[x][z+1]);
    glNormal3f(0, 0, 1);
    glVertex3f(xdelta*x,map[x][z+1],zdelta*z+zdelta);   
    glEnd();

    glBegin(GL_TRIANGLES);
    setMaterialHeight(map[x+1][z+1]);
    glNormal3f(0, 0, 1);
    glVertex3f(xdelta*x+xdelta,map[x+1][z+1],zdelta*z+zdelta);  
    setMaterialHeight(map[x][z+1]);
    glNormal3f(0, 0, 1);
    glVertex3f(xdelta*x,map[x][z+1],zdelta*z+zdelta);       
    setMaterialHeight(map[x+1][z]);
    glNormal3f(0, 0, 1);
    glVertex3f(xdelta*x+xdelta,map[x+1][z],zdelta*z);
    glEnd();
    
glPopMatrix();
return true;

如何计算它的法线?

【问题讨论】:

【参考方案1】:

法线向量可以通过2个向量的Cross product来计算。创建一个函数,计算叉积并设置法线向量属性:

void set_normal_from_cross_product(
    float x1, float y1, float z1, 
    float x2, float y2, float z2)

    float nx = y1*z2 - z1*y2;
    float ny = z1*x2 - x1*z2;
    float nz = x1*y2 - y1*x2;
    float len = sqrt(nx*nx + ny*ny + nz*nz);
    if (len != 0.0f)
        glNormal3f(nx/len, ny/len, nz/len);

在网格中,法线向量可以通过相邻顶点之间的向量来计算。编写函数计算相邻顶点之间的向量并调用set_normal_from_cross_product

void set_grid_normal(int x, int z)

    int prev_x = x > 0 ? x - 1 : x;
    int next_x = x < xsteps - 1 ? x + 1 : x;
    int prev_z = z > 0 ? z - 1 : z;
    int next_z = z < zsteps - 1 ? z + 1 : z;

    set_normal_from_cross_product(
        xdelta * 2, map[next_x][z]-map[prev_x][z], 0,
        0, map[x][next_z]-map[x][prev_z], zdelta * 2);

使用函数设置法向量:

void set_attributes(int x, int z)

    setMaterialHeight(map[x][z]);
    set_grid_normal(x, z);
    glVertex3f(xdelta*x,map[x][z],zdelta*z);

for (int x=0; x<xsteps-1; x++)

    for (int z=0; z<zsteps-1; z++)
    
        glBegin(GL_TRIANGLES);
        set_attributes(x, z);
        set_attributes(x+1, z);
        set_attributes(x, z+1);
        glEnd();

        glBegin(GL_TRIANGLES);
        set_attributes(x+1, z+1);
        set_attributes(x, z+1);
        set_attributes(x+1, z);
        glEnd();
    

【讨论】:

什么是 prev_x_z ?没有定义? 明白了!!!但是当我按下按键时什么都没有显示:( @Struggler 可能法线向量必须反转glNormal3f(-nx/len, -ny/len, -nz/len) 让我们continue this discussion in chat。 @Struggler 我的代码中的另一个错字:sqrt(nx*nx + ny*ny * nz*nz) -> sqrt(nx*nx + ny*ny + nz*nz)

以上是关于具有平均法线的高度场的主要内容,如果未能解决你的问题,请参考以下文章

FFT与游戏开发

如何根据平均海平面计算海拔高度

HDU 1326 Box of Bricks(水~平均高度求最少移动砖)

二叉搜索树的平均查找长度及时间复杂度

HDU 1326

Cesium-如何计算点击位置周围指定区域的最高点、最低点、平均高度?