[MFC :: OpenGL] Mesh :: Part 1 (옮김)

심플디 2014.04.25 12:59 조회 수 : 1584

clMesh_Tera_Info.cpp

clMesh_Tera_Info.h

clMesh_Tera_Setup.cpp

clMesh_Tera_Setup.h

clMesh2.cpp clMesh2.h

ProjectOpenGLDoc.cpp

ProjectOpenGLDoc.h

ProjectOpenGLView.cpp

ProjectOpenGLView.h


DXF 프로젝트는




'파일을 읽고 곧바로 Nurbs curve로 표현' 하는 기능에 초점이 맞추어져 있었다.




하지만 OpenGL에서 제공하는 함수가 Sample 용이였으며, 이에 따라 점을 면으로 연결하기 위한 알고리즘의 필요성이 부각되었다.




Mesh 프로젝트는 점을 면으로 표현하는 기본적인 방법을 소개할 것이다.




<Mesh의 정의와 클래스 구성도>



















Intro::솔직하게 말하면 기분이 정말 아삼삼하다. 손에 땀이 난다. 내가 2차원 mesh를 짜게 될 줄은 몰랐다...


필자는 현재 2주를 공부한 NurbsCurve 함수가 Sample용임을 알고 상당히 빡쳐있다. (내가 면 생성 함수를 직접 짜게 될 줄은 몰랐다.)


이것에 대해서는 아주 괜춘한 예제가 하나 있는데, http://code.google.com/p/myastro/ 사이트의 heightmap.v01.zip 과 v02를 참고해 주기 바란다.


이 사이트에서 소개하는 map은 수 많은 점들로 프로그래밍 되어 있으며, 이것들을 전부 삼각형으로 연결하여 '면'으로 표현하고 있다.


그런데 아쉽게도 초심자가 구조를 파악하는 것이 어렵고, 주석도 별로 없어서 필자 같은 떨이는 감히 따라할 엄두를 낼 수 없다. 


이것을 필자가 사용하게 될지, 혹은 무시하게 될 지는 모르겠지만 참고용으로는 꼭 필요한 코드이니 반드시 한번 참고하기를 바란다.


 


이렇게 된 이상 돼지저금통을 '면'으로 보이게 하는 방법을 2가지로 나눌 수 있는데,


점끼리 연결을 하여 Mesh를 생성 후 그것들 각각을 '면'들로 표현 하는 간단한(?) 방법과,


Nurbscurve를 단위로 나누어서 곡면을 생성하는 방법을 생각해 볼 수 있는데, 후자 역시 Mesh가 필요하다.


후자의 경우는 단지 Mesh의 범위가 커질 뿐이다.




즉, 아직 곡면을 포기한 것은 아니다.


 




 


 



<그림 1 :: Mesh의 정의>


 


<그림 1>은 mesh의 사전적인 정의를 보여주고 있다.


 


 



<그림 2 :: 다양한 Mesh가 적용된 사례(4면체 메쉬)>


 



<그림 3 :: Mesh가 수정된 사례 (6면체 메쉬)>





<그림 4 :: 균일한 Mesh로 수정되는 사례>


 


<그림 2, 3, 4>는 필자가 예전에 Ansys를 하면서 간단하게 만들어본 PPT 파일 내용인데... 사용하게 될 줄 몰랐다.


Ansys같은 FEM 프로그램을 다루는 사람들은 목적이 된 대상물을 일정 형상으로 잘게 나누는 행위를 메쉬(mesh)를 짠다고 한다.


즉, mesh는 일정 대상을 잘게 나눈 형상단위라고 할 수 있겠다. (FEM :  (Naver 사전치면 뭔지 나옴))


컴퓨터 공학도들에게 이런 예를 든다는 것은 조금 생소할 수 있겠다.


하지만 기계 공학도들에게 이 정도는 쉽게 볼 수 있는 개념이므로 꼭 한번 보여주고 싶었다.


 




 <그림 5 :: 웰컴투 메시 월드>





<그림 5>의 면의 기본 단위는 점 3개로 이루어진다.


점 4개로 이루어진 면은, 점 1개의 z값이 바뀌면 평면의 왜곡현상이 일어난다. ( 검증은 Auto CAD로 그려보시길... )


사실, 보기 좋은것은 4각형, 혹은 6면체 메쉬겠지만, 정밀한 표현을 하기 위해서는 3각형, 4면체 메쉬가 적합하다.







<그림 6 :: clFile 클래스 조작>




2011.11.12  :: 


<그림 6>은 그동안 오랫동안 필자를 괴롭혀온 오류를 잡기위한 clFile 클래스의 조작이다.


알 수 없는 오류가 계속 잡히지 않았는데, 파일의 경로, 이름, 확장자 저장하는 변수들이 크기가 적어서 메모리 침범이 일어난 것이였다.


2011.11.12 ::


실험실 분위기가 좋지 않다.


힘든 결정을 해야 하기 때문이다. 


때문에 오랫동안 이 프로젝트를 할 의지를 잃고 있었다.


지금도 사실 꾸역꾸역 하는 중...


2011.11.12 ::


예전에 공주대 신관캠 도서관 2층에서 이 프로젝트와 거의 흡사한 프로젝트로 컴공 대학원생이 쓴 논문을 본 적이 있다.


기계공학도로서, 이 프로젝트를 무사히 마칠 수 있을지 걱정이 앞섬과 동시에, 


근 2년 만에 컴퓨터 프로그래밍 실력이 이 정도로 향상되었음에 뿌듯하다.


2011.11.12 ::


너무 오랫만에 잡아서 그런가.


예전에 짜 두었던 메시 짜주는 코드의 procedure(절차)선언 방식을 모조리 까먹었다. =_=;;







 <그림 7 :: View 수정>


 



<그림 7>은 Doc 클래스에서 Nurbs에 관련된 변수들의 목적이, File의 정보를 긁어오는 목적으로 변질되었음을 보여주고 있다.


극단적으로 보면 Draw_Nurbs...로 시작하는 메서드들은 수정되었거나 삭제되어있다.


다 지우고 싶은데, 죄표를 긁어오는 메커니즘이 있기 때문에 '목적'만 변경한 것이다.






<그림 8 :: Doc에 선언된 전역 '함수'>




<그림 8>은 Doc 클래스 내부에서 선언된 '메서드'가 아닌, 그냥 전역 함수가 ~Doc.cpp 파일에 포함된 모습을 보여주고 있다.


이 전역함수는 Frame 변수를 할당받고 Frame 변수를 통해 View클래스의 포인터를 리턴한다.


이 전역함수의 사용은 <그림 9>에서 볼 수 있다.






<그림 9 :: Doc에서 View 클래스 변수를 초기화 하는 모습>




<그림 9>는 Doc 클래스에서 View 클래스 변수를 초기화 하는 모습을 보여주고 있다.


왜 이런 기능이 필요하냐면, 파일을 불러오고 읽어오는 타이밍을 View에서 맞춰주기 힘들기 때문이다.


물론 논리 변수를 사용하면, 단순한 개념으로 해결 될 수 있다.




그러나 필자는 논리 변수를 많이 사용함으로서, 가독성이 떨어지는 경우를 겪어 보았고,


논리 변수를 많이 사용함으로서, 대괄호가 많아짐에 따라 글씨들이 좌우로 들쑥 날쑥 거리는것을 끔찍하게 싫어한다. (수정 할 때 빡친다.)


그래서 이런 방법을 썼다.




 


<그림 10 :: Serialize 메서드 단순화>


 


<그림 10>으로 한번 한숨을 쉬어 본다. (제대로 실행 됨을 확인 하였다.)


대략 클래스의 간소화를 도모했으므로 이제 본격적으로 메시에 대한 설명을 하려 한다.






<그림 11 :: 배열(점)의 배치>




<그림 11>을 통해 우리는 우리가 어떤 방식으로 '배열'을 선언했고, 어떤 방식으로 '점'을 배열에 초기화 시켰는지 알 수 있다.


우리는 점들의 좌표만 갖는 x, y, z 좌표를 배열로 할당 한 것이 아니다.


즉, vlPoint 를 사용하는것이 아니라, U, V좌표를 사용하는 vlPoint2를 사용하고 있다.


(이게 이해가 안가면 DXF 클래스 게시물을 보시고 오세요^^... 개소리가 많아서 스크롤이 길지, 실 내용은 별거 없어요)




그리고 vlPoint2로 좌표를 긁어오는 마지막 단계에서는 '빈 배열'에 '비어있지 않은 u 배열의 값'을 초기화 하는 소팅 작업도 한 적 있었다.


즉, 어떤 형식이든 <그림 11>처럼 질서 정연한 상태란 의미다.






<그림 12 :: 메시 짜기 첫 발자욱>




<그림 12>는 U,V 좌표의 (0, 0) (0, 1) (1, 1)좌표를 갖는 1개의 메시를 보여준다.








<그림 13 :: 메시짜기 두번째 발자욱>




<그림 13>은 U, V 좌표의 (0, 0) (1, 1) (1, 0) 좌표를 갖는 1개의 메시를 보여준다.


즉, (0, 0)과 (1, 1)로 이루어진 사각형 메시 안에는 (0, 0), (0, 1) (1, 1)와 (0, 0)(1, 1)(1, 0)의 삼각형 메시가 2개나 들어음을 의미한다.


그리고 점들을 메시에 저장하는 순서도 굉장히 중요하다.


메시에서 초기화된 점들의 순서는, OpenGL 화면에서 그려지는 점의 순서이기도 하다.


현재 필자가 사용하는 OpenGL 출력은 '앞' 과 '뒤'면을 CW 및 CCW 방식으로 구분짓고 있다.


그리고 OpenGL에서는 면이 그려지는 점의 방향성이 시계방향(CW)이냐 시계반대방향(CCW)이냐에 따라서 '앞' '뒤' 면들 필터링하고, 


'앞' 면인 경우만 화면에 출력한다.






<그림 14 :: cw 초기화 방식>




<그림 14>는 cw 방식의 초기화를 보여주고 있다.


이 방식과는 별개로 ccw 방식은 cw의 반대방향으로 초기화 된다.






 


<그림 15>




이제 <그림 15>의 좌, 우측 메시 초기화 방식을 전체에도 적용해야 한다.


일반적으로 한 사각형 범위의 2개 메시는 기준점을 기준으로 초기화 될 수 있다.


총 메시의 개수(E)는




E(ea) = {u배열의 개수(u) - 1} * {v배열의 개수(v) - 1} * 2 


ex ) [6][4]의 U, V 배열의 메시 개수      =      {6-1}*{4-1}*2      =      5*3*2      =      30 개      =      30 ea




다. (알고리즘 필기했던 A4용지가 어디론가 증발해서 생각나는 대로 써본다...)


그리고 CW를 준수하는 기준점에 따라 첫번째 메시의 초기화 값은 E1.Point1(u, v) E1.Point2(u, v+1) E1.Point3(u+1, v+1)이 될 것이다.


E2도 역시 처음 값은 (u, v)가 된다.




for문을 돌며 u는 개수의 1가감 값이 되고, v역시 1가감 값이 된다.


예를 들면 




for(int i=0; i<u-1; i++)


for(int j=0; j<v-1; j++) 



->방향성에 맞게 메시 2개의 값을 초기화




가 되겠다.




만약 여기까지 된다면 독자도 어느정도 눈치를 챘을 것이다.


면을 그리는 것은, 


mesh클래스를 순차적으로 선언하고, 


각각의 mesh에 대한 point를 순차적으로 선언하기만 하면 간단히 해결 할 수 있음을.










<그림 16 :: clInputManager 클래스의 수정>




<그림 11>은 clInputManager 클래스의 수정 사항을 보여주고 있다.


그런데 <그림 11>은 한가지 문제점을 안고 있다.


Seriailize 메서드 안에서 선언되고 바로 해제되기 때문에 'mesh의 저장'이 용이하지 않다는 것이다.






 <그림 17 :: 클래스 수정>




<그림 17>은 <그림 16>의 클래스 계열도를 전체적으로 수정한 모습을 보여주고 있다.






 <그림 18 :: 클래스 수정>




<그림 18>은 mesh에 관련된 클래스의 manager(메니저)클래스의 이름을 clMesh2로 바꾼 모습을 보여주고 있다.


관리하기 편리하기도 하고, 가독성 측면에서도 좋을 것 같아서 이름 수정을 감행했다.


마음 같아서는 clPoint2 클래스를 clMesh2클래스에 상속시키고 싶은데, 나중에 수정하기 힘들 것 같아서 시도하지 않았다. (별로 내키지도 않고...)


그리고 사실 vlPoint2도 vlMesh2와 같이 몇개의 클래스가 상속된 형태를 띄고 있다.







 <그림 19 :: Test_Vertex>





<그림 19>는 mesh의 일단면을 보여주고 있다.




프로그래밍 상에서는 선 하나만 긋게 했는데, 0번째 메시의 0번 포인트와 1번 포인트를 이은 것이다.


데이터가 순조롭게 초기화 되었음을 알 수 있다.







 <그림 20 :: Test_Vertex>






프로그래밍 상에서는 선 하나만 긋게 했는데, 1번째 메시의 0번 포인트와 1번 포인트를 이은 것이다.


데이터가 순조롭게 초기화 되었음을 알 수 있다.




<그림 20>이 나오기까지의 코드는 아래와 같다.








<그림 21>


 





<그림 22>


 





<그림 23>






 


<그림 24>






 


<그림 25>




<그림 21>~<그림 25>는 <그림 20>을 위한 코드 선언을 보여주고 있다.


필자도 요즘 코드 하나하나에 대한 설명이 허접하다는 것을 안다.


하지만 이 정도는 방법만 알면 그리 어려운 일이 아니라고 생각한다.






<그림 26 :: Test_Vertex (CCW)>





 


<그림 27 :: Test_Vertex (CCW)>








 <그림 28 :: 면으로 보이게 하긔★>



 



<그림 26>과 <그림 27>은 TestVertex의 메시 모습을 보여주고 있다.


예전에 우리가 6면체 돌렸던 코드를 기억 하는가? 




메시에 대한 각각의 점에 대한 정보는 싱크로 할 수 있으므로, 면을 그리는 것은 메시를 선으로 보이게 하는 것 보다 쉬울 것이다.


각각의 면에 대해 법선 벡터를 설정해 주면 <그림 28>과 같이 보이게 할 수 있다.






<그림 29 :: 돼지 저금통 (GL_LINES) (CCW)>






<그림 30 :: 돼지 저금통 (GL_POLYGON) (CCW)>


 



<그림 29> 와 <그림 30>은 돼지저금통을 선 및 면으로 보여주는 코드다.


<그림 29>를 보면 쌩뚱맞게 튀어나온 선이 보이고, <그림 30>을 보면 쌩뚱맞게 튀어나온 면들이 보인다.


이것은 코드상의 문제가 아니라, 점 데이터들의 z(높이)값이 불규칙해서 그렇다.




코드상에 문제가 없음은 이미 Test_Vertex 파일을 읽으면서 확인했다.




그리고 <그림 30>을 보면, 튀는 부분은 u, v의 개념을 상실한 채 엄청난 범위를 침식하고 있음을 볼 수 있다. (핑크색 빗금 쳤음)


이건 sorting의 문제가 아닌듯 싶다.




필터링이 필요한데... 아... 아... 


프로그램을 대체 언제까지 수정해!!!






 <그림 31 :: 돼지 저금통을 면으로 표현함>




<그림 31>을 보면 돼지저금통을 면으로 표현한 결과를 볼 수 있다.


면 중간중간 촘촘하게 선이 그어져 있는데, 


그것은 굴곡으로 표현되지 않은 점간의 z(높이)값 격차가 일정하게 나서 생긴 줄이다.


즉, 너무 디테일한 표현을 해서 보이는 효과이고, 조명 효과를 제거하면 볼 수 없다.




앞면은 깨끗하게 면처리가 된 반면, 뒷면의 면 처리는 영 불만스럽다.


이것...도 해결 해야 하나?




아무튼 이쯤에서 마무리를 해야겠다.


관련 파일을 첨부해 놓을테니 참고해주기를 바란다.

번호 제목 글쓴이 날짜 조회 수
공지 본 게시글의 첨부파일 권한 심플디 2014.08.22 2376
47 [MFC :: OpenGL] 컴공 수업 발표 자료 (옮김) [2] 심플디 2014.04.25 2878
46 [MFC :: OpenGL] Project 시즌 2 후기 (옮김) 심플디 2014.04.25 1568
45 [MFC :: OpenGL] File output (옮김) 심플디 2014.04.25 1500
44 [MFC :: OpenGL] Tool bar(툴바) 편집방법 (옮김) 심플디 2014.04.25 1821
43 [MFC :: OpenGL] IntroPage (옮김) file 심플디 2014.04.25 1500
42 [MFC :: OpenGL] IPC 적용 (옮김) file 심플디 2014.04.25 1560
41 MFC :: OpenGL] ProjectMFCReport 와꾸짜기 (옮김) 심플디 2014.04.25 1681
40 [MFC :: OpenGL] Data Dialog 와꾸짜기 (옮김) 심플디 2014.04.25 1710
39 [MFC :: OpenGL] 시즌 2 개요 (옮김) file 심플디 2014.04.25 1499
38 [MFC :: OpenGL] Project 시즌 2 시작 (옮김) [1] 심플디 2014.04.25 1504
37 [MFC :: OpenGL] Project 시즌 1 후기 (옮김) file 심플디 2014.04.25 1566
36 [MFC :: OpenGL] Mesh :: Part 2 (옮김) [1] file 심플디 2014.04.25 1533
» [MFC :: OpenGL] Mesh :: Part 1 (옮김) file 심플디 2014.04.25 1584
34 [MFC :: OpenGL] DXF :: Part 5 (옮김) file 심플디 2014.04.25 1574
33 [MFC :: OpenGL] DXF :: Part 4 (옮김) file 심플디 2014.04.25 1469
32 [MFC :: OpenGL] DXF :: Part 3 (옮김) file 심플디 2014.04.25 1453
31 [MFC :: OpenGL] DXF :: Part 2 (옮김) file 심플디 2014.04.25 1503
30 [MFC :: OpenGL] DXF :: Part 1 (옮김) file 심플디 2014.04.25 1545
29 [MFC :: OpenGL] Proposal 및 앞으로의 계획 (옮김) 심플디 2014.04.25 1539