2012-12-15 3 views
2

높이 맵 데이터의 법선을 찾고 싶습니다. gl_triangles 내 코드에서 인덱스를 사용하고 있습니다. 이것에 대한 법선을 어떻게 찾을 수 있습니까?높이 맵 데이터의 법선

답변

2

주어진 삼각형 (vert1, vert2, vert3)은 정상인 ((vert2 - vert1).cross(vert3 - vert1)).normalize()입니다.

부드럽고 버텍스가 많은 법선의 경우 : Foreach 버텍스, 버텍스가 포함 된 각 삼각형의면 노멀을 합친 다음 합계를 정규화합니다.

편집 : 예 :

#include <GL/glut.h> 
#include <vector> 
#include <cmath> 
#include <Eigen/Core> 
#include <Eigen/Geometry> 

using namespace std; 
using namespace Eigen; 

typedef Matrix< Vector3f, Dynamic, Dynamic > VecMat; 

// given a matrix of heights returns a matrix of vertices 
VecMat GetVerts(const MatrixXf& hm) 
{ 
    VecMat verts(hm.rows(), hm.cols()); 
    for(int col = 0; col < hm.cols(); ++col) 
     for(int row = 0; row < hm.rows(); ++row) 
      verts(row, col) = Vector3f(col, row, hm(row, col)); 
    return verts; 
} 

VecMat GetNormals(const VecMat& hm) 
{ 
    VecMat normals(hm); 
    for(int col = 0; col < hm.cols(); ++col) 
     for(int row = 0; row < hm.rows(); ++row) 
     { 
      Vector3f sum(Vector3f::Zero()); 
      const Vector3f& cur = hm(row, col); 
      if(row+1 < hm.rows() && col+1 < hm.cols()) 
       sum += (hm(row+0, col+1) - cur).cross(hm(row+1, col+0) - cur).normalized(); 
      if(row+1 < hm.rows() && col > 0) 
       sum += (hm(row+1, col+0) - cur).cross(hm(row+0, col-1) - cur).normalized(); 
      if(row > 0 && col > 0) 
       sum += (hm(row+0, col-1) - cur).cross(hm(row-1, col+0) - cur).normalized(); 
      if(row > 0 && col+1 < hm.cols()) 
       sum += (hm(row-1, col+0) - cur).cross(hm(row+0, col+1) - cur).normalized(); 
      normals(row, col) = sum.normalized(); 
     } 
    return normals; 
} 

// returns an index array for a GL_TRIANGLES heightmap 
vector< unsigned int > GetIndices(int rows, int cols) 
{ 
    vector< unsigned int > indices; 
    for(int col = 1; col < cols; ++col) 
     for(int row = 1; row < rows; ++row) 
     { 
      // Eigen default storage order is column-major 
      // lower triangle 
      indices.push_back((col-1) * rows + (row-1)); 
      indices.push_back((col-0) * rows + (row-1)); 
      indices.push_back((col-1) * rows + (row-0)); 
      // upper triangle 
      indices.push_back((col-1) * rows + (row-0)); 
      indices.push_back((col-0) * rows + (row-1)); 
      indices.push_back((col-0) * rows + (row-0)); 
     } 
    return indices; 
} 

VecMat heightmap; 
VecMat normals; 
vector< unsigned int > indices; 
void init() 
{ 
    // wavy heightmap 
    MatrixXf hm(64, 64); 
    for(int col = 1; col < hm.cols(); ++col) 
     for(int row = 1; row < hm.rows(); ++row) 
     { 
      float x = (col - (hm.cols()/2.0f))/2.0f; 
      float y = (row - (hm.rows()/2.0f))/2.0f; 
      hm(row, col) = cos(sqrt(x * x + y * y)); 
     } 

    heightmap = GetVerts(hm); 
    heightmap.array() -= Vector3f(hm.cols()/2.0f, hm.rows()/2.0f, 0); 
    for(int col = 0; col < hm.cols(); ++col) 
     for(int row = 0; row < hm.rows(); ++row) 
      heightmap(row, col).array() *= Vector3f(1/4.0f, 1/4.0f, 1.0f).array(); 

    normals = GetNormals(heightmap); 
    indices = GetIndices(heightmap.rows(), heightmap.cols()); 
} 

void display() 
{ 
    glEnable(GL_DEPTH_TEST); 
    glEnable(GL_CULL_FACE); 
    glShadeModel(GL_SMOOTH); 

    glEnable(GL_LIGHTING); 
    GLfloat global_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; 
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient); 
    glEnable(GL_COLOR_MATERIAL); 
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); 

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    double w = glutGet(GLUT_WINDOW_WIDTH); 
    double h = glutGet(GLUT_WINDOW_HEIGHT); 
    gluPerspective(60, w/h, 1, 100); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    gluLookAt(8, 8, 8, 0, 0, 0, 0, 0, 1); 

    // spinning light 
    glEnable(GL_LIGHT0); 
    float angle = 20 * (glutGet(GLUT_ELAPSED_TIME)/1000.0f) * (3.14159f/180.0f); 
    float x = cos(-angle) * 6; 
    float y = sin(-angle) * 6; 
    GLfloat light_position[] = { x, y, 2, 1.0 }; 
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);  
    glDisable(GL_LIGHTING); 
    glPointSize(5); 
    glBegin(GL_POINTS); 
    glColor3ub(255, 255, 255); 
    glVertex3fv(light_position); 
    glEnd(); 
    glEnable(GL_LIGHTING); 

    glColor3ub(255,0,0); 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_NORMAL_ARRAY); 
    glVertexPointer(3, GL_FLOAT, sizeof(Vector3f), heightmap(0,0).data()); 
    glNormalPointer(GL_FLOAT, sizeof(Vector3f), normals(0,0).data()); 
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, &indices[0]); 
    glDisableClientState(GL_VERTEX_ARRAY); 
    glDisableClientState(GL_NORMAL_ARRAY); 

    glutSwapBuffers(); 
} 

void timer(int extra) 
{ 
    glutPostRedisplay(); 
    glutTimerFunc(16, timer, 0); 
} 

int main(int argc, char **argv) 
{ 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); 
    glutInitWindowSize(640, 480); 
    glutCreateWindow("Heightmap"); 
    init(); 
    glutDisplayFunc(display); 
    glutTimerFunc(0, timer, 0); 
    glutMainLoop(); 
    return 0; 
} 
관련 문제