为了账号安全,请及时绑定邮箱和手机立即绑定

计算三角形网格中的法线

计算三角形网格中的法线

C++
温温酱 2019-11-25 15:34:07
我绘制了一个具有10000个顶点(100x100)的三角形网格,它将成为草地。我使用了gldrawelements()。我整天看了看,仍然不明白该如何计算法线。每个顶点都有自己的法线还是每个三角形都有自己的法线?有人可以为我指出如何编辑代码以合并法线的正确方向吗?struct vertices {    GLfloat x;    GLfloat y;    GLfloat z;}vertices[10000];GLuint indices[60000];/*99..999998..9998........01..990100..9900*/void CreateEnvironment() {    int count=0;    for (float x=0;x<10.0;x+=.1) {        for (float z=0;z<10.0;z+=.1) {            vertices[count].x=x;            vertices[count].y=0;            vertices[count].z=z;            count++;        }    }    count=0;    for (GLuint a=0;a<99;a++){        for (GLuint b=0;b<99;b++){            GLuint v1=(a*100)+b;indices[count]=v1;count++;            GLuint v2=(a*100)+b+1;indices[count]=v2;count++;            GLuint v3=(a*100)+b+100;indices[count]=v3;count++;        }    }    count=30000;    for (GLuint a=0;a<99;a++){        for (GLuint b=0;b<99;b++){            indices[count]=(a*100)+b+100;count++;//9998            indices[count]=(a*100)+b+1;count++;//9899            indices[count]=(a*100)+b+101;count++;//9999        }    }}void ShowEnvironment(){    //ground    glPushMatrix();    GLfloat GroundAmbient[]={0.0,0.5,0.0,1.0};    glMaterialfv(GL_FRONT,GL_AMBIENT,GroundAmbient);    glEnableClientState(GL_VERTEX_ARRAY);    glIndexPointer( GL_UNSIGNED_BYTE, 0, indices );    glVertexPointer(3,GL_FLOAT,0,vertices);    glDrawElements(GL_TRIANGLES,60000,GL_UNSIGNED_INT,indices);    glDisableClientState(GL_VERTEX_ARRAY);    glPopMatrix();}
查看完整描述

3 回答

?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

竖起大拇指给datenwolf!我完全同意他的方法。要为每个顶点添加相邻三角形的法线向量,然后进行归一化。我只想稍微介绍一下答案,并仔细研究具有x / y步长不变的矩形,平滑网格的特殊但很常见的情况。换句话说,每个点的高度都可变的矩形x / y网格。


这种网格是通过在x和y上循环并为z设置一个值来创建的,并且可以表示类似山丘的表面。因此,网格的每个点都由一个向量表示


P = (x, y, f(x,y)) 

其中f(x,y)是给出网格上每个点的z的函数。


通常要绘制这样的网格,我们使用TriangleStrip或TriangleFan,但是任何技术都应为生成的三角形提供相似的形貌。


     |/   |/   |/   |/

...--+----U----UR---+--...

    /|   /| 2 /|   /|           Y

   / |  / |  / |  / |           ^

     | /  | /  | /  | /         |

     |/ 1 |/ 3 |/   |/          |

...--L----P----R----+--...      +-----> X

    /| 6 /| 4 /|   /|          

   / |  / |  / |  / |         

     | /5 | /  | /  | /      

     |/   |/   |/   |/

...--DL---D----+----+--...

    /|   /|   /|   /|

对于atriangleStrip,每个顶点P =(x0,y0,z0)具有6个相邻顶点,表示为


up       = (x0     , y0 + ay, Zup)

upright  = (x0 + ax, y0 + ay, Zupright) 

right    = (x0 + ax, y0     , Zright) 

down     = (x0     , y0 - ay, Zdown)

downleft = (x0 - ax, y0 - ay, Zdownleft) 

left     = (x0 - ax, y0     , Zleft)

其中ax / ay分别是x / y轴上的恒定网格步长。在正方形网格上,ax = ay。


ax = width / (nColumns - 1)

ay = height / (nRows - 1)

因此,每个顶点都有6个相邻的三角形,每个三角形都有自己的法向矢量(表示为N1至N6)。可以使用定义三角形边的两个向量的叉积来计算这些值,并小心执行叉积的顺序。如果法向矢量指向您的Z方向:


N1 = up x left =

   = (Yup*Zleft - Yleft*Zup, Xleft*Zup - Xup*ZLeft, Xleft*Yup - Yleft*Xup) 


   =( (y0 + ay)*Zleft - y0*Zup, 

      (x0 - ax)*Zup   - x0*Zleft, 

      x0*y0 - (y0 + ay)*(x0 - ax) ) 


N2 = upright  x up

N3 = right    x upright

N4 = down     x right

N5 = downleft x down

N6 = left     x downleft

每个点P的最终法向矢量为N1至N6之和。我们求和后归一化。创建循环,计算每个法线向量的值,将它们相加然后进行归一化非常容易。但是,正如Shickadance先生所指出的那样,这可能会花费相当长的时间,尤其是对于大型网格物体和/或在嵌入式设备上。


如果我们仔细观察并手动执行计算,我们将发现大多数项相互抵消,从而为我们得出的向量N提供了非常优雅且易于计算的最终解决方案。避免计算N1到N6的坐标,从而对每个点进行6个叉积和6个加法运算,从而加快了计算速度。代数帮助我们直接跳到解决方案,使用更少的内存和更少的CPU时间。


我将不显示计算的详细信息,因为它很长但是很简单,并且会跳到网格上任何点的法线向量的最终表达式。为了清楚起见,仅分解了N1,其他向量看起来相似。求和后,我们得到尚未归一化的N:


N = N1 + N2 + ... + N6


  = .... (long but easy algebra) ...


  = ( (2*(Zleft - Zright) - Zupright + Zdownleft + Zup - Zdown) / ax,

      (2*(Zdown - Zup)    + Zupright + Zdownleft - Zup - Zleft) / ay,

       6 )

你去!只要标准化此向量,就可以知道网格上任何点的法线向量,只要您知道其周围点的Z值以及网格的水平/垂直步长即可。


请注意,这是周围三角形法线向量的加权平均值。权重是三角形的面积,并且已经包含在叉积中。


您甚至可以只考虑四个周围点(上,下,左和右)的Z值来进一步简化它。在这种情况下,您会得到:


                                             |   \|/   |

N = N1 + N2 + N3 + N4                    ..--+----U----+--..

  = ( (Zleft - Zright) / ax,                 |   /|\   |

      (Zdown -  Zup  ) / ay,                 |  / | \  |

       2 )                                 \ | / 1|2 \ | /

                                            \|/   |   \|/

                                         ..--L----P----R--...

                                            /|\   |   /|\

                                           / | \ 4|3 / | \

                                             |  \ | /  |

                                             |   \|/   |

                                         ..--+----D----+--..

                                             |   /|\   |

这更加优雅,计算速度更快。


希望这可以使一些网格更快。干杯


查看完整回答
反对 回复 2019-11-25
  • 3 回答
  • 0 关注
  • 1127 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信