OpenGL 사람 만들기 질문좀 드리겠습니다. (장문주의!)

조회수 1675회

이미지

이미지

안녕하십니까? OpenGL을 공부중인 학생입니다. 다름이 아니라 OpenGL을 이용해서 소스를 짜고 있는데 저의 미천한 실력으로는 도저히 아니되어서 결국 새벽시간에 질문글을 남깁니다.. 어떤 소스냐면 메모장이 하나 주어져있는데, 이 메모장에는 사람 모습에 대한 정점에 대한 정보와 면의 정보 저장되어있습니다.

위 사진중 첫번째 사진은 각 정점에 대한 정보입니다. 10113은 정점의 갯수입니다. 사람 모습의 소스는 10113개의 정점으로 이루어져 있다는 말입니다. 그 아래 소수들은 3개단위로 적혀져있는데 정점의 좌표입니다. 첫번째 정점의 좌표는 91.459999 -169.619995 -89.230003이 되겠군요. 이런식으로 10113개가 있습니다.이게 0번 정점이 되고 순서대로 저장됩니다.

두번째 사진의 20222는 면의 개수입니다. 이 사람의 모습은 20222개의 면으로 이루어져 있군요. 이후 3개단위로 끊어져 있는 숫자들은 정점의 번호입니다. 3개단위로 끊어져있으니 이 면들은 삼각형이겠습니다. 첫번째 면은 16번 20번 19번 정점으로 이루어져있습니다.이게 0번면이 될거고 순서대로 저장됩니다.

이제 이 메모장에 있는 정보를 파일 입출력 함수를 이용해서 받아온후 이 정점을 토대로 그리기만 하면됩니다.

struct FileVertex // 파일에서 읽어온 정점 정보
{
    float x;
    float y;
    float z;
    vector3d normal; // 해당 점에서의 법선벡터
};

struct FileFace // 파일에서 읽어온 면의 정보
{
    int fn1; // 면의 정점1
    int fn2; // 면의 정점2
    int fn3; // 면의 정점3
    vector3d normal; // 해당면에서의 법선벡터
};

이건 메모장에서 읽어온 정보를 저장하는 구조체입니다. 동적할당을 이용해서 저장했습니다.

정점과 면의 정보를 읽어오는 것은 확인을 했으니 따로 문제가 되지않는걸로 판단하고 읽어오는 따로 소스를 올리지는 않겠습니다. 하지만 이후에 그리는 것이 문제인데, 그리기에 앞서 이 정점들의 법선벡터를 구해야합니다.

이 정점들의 법선벡터를 구하기 위해서는 이 정점으로부터 인접해 있는, 즉 이 정점들이 포함되어있는 모든 면들의 법선벡터를 구한후 평균을 취하면 이 정점의 법선벡터가 된다고 합니다.

for (int i = 0; i < numOfFace; i++) // 각면의 법선벡터 미리 계산하기
    ff[i].normal = Face_Normal_Computing(ff[i]);

// 해당정점에서 인접한 면들의 법선벡터 평균구하기
for (int i = 0; i < numOfVertex; i++) // 정점 돌아다니는 루프
{
    int n_count = 0;
    for (int j = 0; j < numOfFace; j++) // 면 검사 루프
    {
        if (i == ff[j].fn1 | i == ff[j].fn2 | i == ff[j].fn3) //  i번째 정점이 j번째 면에 속한다면
        {
            fv[i].normal.x += ff[j].normal.x;
            fv[i].normal.y += ff[j].normal.y;
            fv[i].normal.z += ff[j].normal.z;
            n_count++; // 인접해있는 면의 갯수 카운트
        }
    }
    fv[i].normal.x /= n_count; // 법선벡터의 평균 구하기
    fv[i].normal.y /= n_count; // 법선벡터의 평균 구하기
    fv[i].normal.z /= n_count; // 법선벡터의 평균 구하기
}

첫번째 for문의 Face_Normal_Computing 함수는 법선벡터를 계산하는 함수입니다. 모든 면에 있는 정점에 대해 미리 법선벡터를 계산해놓고 이후에 해당 정점이 포함되어 있는 면들의 법선벡터만 바로 넣어줄수 있게 하기위해 미리 계산해놓았습니다.

그 다음 이중 for문을 보시겠습니다. i는 정점에대한 for문이고 j는 면에대한 정보입니다. 그러니까 i=0부터 즉 0번 정점부터 시작합니다.

0번 정점부터시작해서 0번 면부터 이 정점이 포함되어있는지를 확인합니다.                                       0번 면은 16번 20번 19번 정점으로 이루어져있으니 0번 정점이 없습니다.                                     1번 면은 16번 15번 0번 정점으로 이루어져있으니 0번 정점이 있습니다.

따라서 이제 if문을 실행하게되는데 아까 계산해 놓은 법선벡터를 해당 정점에 더 합니다. 포함되는 면이 있을 때마다 더해줍니다. 내부 for문을 빠져나가면 해당정점이 포함하는 면이 없다는 뜻이므로 이제 n_count를 나눠 주면 해당정점에서의 진짜 법선벡터가 되는 것 입니다.

void Draw_Sphere(void) // Vertex_Generation에서 만들어진 정점으로 면을 만들고, 구를 그리기
{
    for (int i = 0; i < numOfVertex; i+=3)
    {
        glBegin(GL_POLYGON);
            glNormal3f(fv[i].x, fv[i].y, fv[i].z);
            glVertex3f(fv[i].x, fv[i].y, fv[i].z);
            glNormal3f(fv[i + 1].x, fv[i + 1].y, fv[i + 1].z);
            glVertex3f(fv[i + 1].x, fv[i + 1].y, fv[i + 1].z);
            glNormal3f(fv[i + 2].x, fv[i + 2].y, fv[i + 2].z);
            glVertex3f(fv[i + 2].x, fv[i + 2].y, fv[i + 2].z);
        glEnd();
    }
}

이렇게 계산한 정점들을 위 함수를 통해서 그려주면 저는 나올 것이라고 기대했는데 전혀 나오질 않습니다..어디가 잘못된지 어디가 논리적으로 잘못되었는지 잘 모르겠습니다... 도움좀 주시면 감사하겠습니다. 혹 전체 소스가 필요하시면 글을 수정해서 다시 올려드리겠습니다.. 글이 길지만 꼭좀 도와주시면 감사하겠습니다

1 답변

  • 좋아요

    0

    싫어요
    채택 취소하기
    • 초기 fv.normal이 (0, 0, 0)으로 잘 초기화 되어 있는지.
    • if 문 내부에 bitwise OR를 => logical OR로 변환. (혹시 모름)
    • glNormal3f(); 에 정점이 아닌 정점에 대한 노말값을 넘겨야 함.
    glBegin(GL_TRIANGLES);
      glNormal3f(n1x, n1y, n1z);
      glVertex3f(v1x, v1y, v1z);
      glNormal3f(n2x, n2y, n2z);
      glVertex3f(v2x, v2y, v2z);
      glNormal3f(n3x, n3y, n3z);
      glVertex3f(v3x, v3y, v3z);
    glEnd();
    

    코드로 유추할만한건 이정도임돠

    • 답변주셔서 감사합니다. 답변주신 세가지 문장중 마지막 부분이 이해가 잘안가는데 정점이 아닌 정점에 대한 노말값은 무슨 말씀인지 잘 이해가 안가네요.. codeslave 2018.11.5 23:44
    • 정점에 대한 노말값은...구하신 FileVertex.normal 입니다. 이걸 Face Normal의 평균으로 구하신 코드니까 구한 걸 써야죠. ㅎ doodoji 2018.11.6 00:17
    • 의도에 따라 Face Normal을 쓰기도 하고 Vertex Normal을 쓰기도 합니다. 하지만 정작 노말값이 문제가 되어 보이는 것은 조명이 있을 경우고 일단 정점이 잘 찍혔다면 해당 위치에 그 모양이라도 보여야 정상입니다. 보이지 않는 이유는 데이터가 잘못되었거나 해당 정점들이 view frustum안에 있지 않을 경우, 즉 카메라의 위치와 방향이 잘못되어 있을 가능성도 봐야 할거구요. doodoji 2018.11.6 00:21
    • 노말은 일단 빼더라도 각 정점에 대한 컬러를 넣어서 확인해 보심이 좋을 듯 합니다. doodoji 2018.11.6 00:21
    • 죄송합니다 저는 글렀네요 ㅠㅠ... codeslave 2018.11.8 13:02

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)