■ OpenGL: Normal Vector
1. 법선벡터
법선(法線, normal)벡터: 임의 두 점사이 직선에 90도 각도로 수직을 이루는 선을 법선이라고 함.
- 아나 한국말은 용어가 어렵다. 한문 하나하나 봐야 이해가 된다. 법은 法일반적인 법법이고 선은 줄선線인데 법에 다른 의미로 모형 도는 꼴 법이라고도 할 수 있고.... 모형의 선? 아놔.. 이렇게 만드니 이해하기 어렵다. 그냥 그림으로 보는게 좋다.
그림에 파란색 아이를 법선 벡터라고 하고 이 벡터는 각 꼭지점을 지나는 평면을 그리면 무수하게 많이 표현될 수 있다.
3D 개념에서 법선벡터를 이해하는게 중요하다고 한다.
왜 모든 꼭지점(Vertex)에 법선 벡터를 만들어야 하나?
- 모든 꼭지점에 법선 벡터를 사용함으로써 울퉁불퉁한 곡면을 부드럽게 표현, 완벽한 조명 적용 가능 하다고 함
http://opengl.czweb.org/ch09/275-279.html
위 그림에서 x, y 평면에 면이 하나 있고 점 (1,1,0)이 존재 한다. 이 점을 기준으로 수직으로 (1,10,0)을 그었을때 이 직선을 법선벡터(Normal Vector)이라고 함
법선벡터를 좀더 간단히 표현하기 위해 기존의 (1, 1, 0 ) - (1, 10 ,0)을 하면 그림에서 볼 수 있듯이 Translated Normal vector이 나오게 된다.
벡터란 방향을 알려주는 역할을 하며 여기서는 버텍스나 폴리곤이 어떤 방향으로 위치해 있는지 OpenGL에게 알려주게 됨
1 2 3 4 5 6 | glBegin(GL_TRIANGLES); glNormal3f(0.0f, -1.0f, 0.0f); glVertex3f(0.0f, 0.0f, 60.0f); glVertex3f(-15.0f, 0.0f, 30.0f); glVertex3f(15.0f,0.0f,30.0f); glEnd(); |
위 소스에 보면 삼각형을 만드는데 3개의 꼭지점이 있고 법선벡터가 y 축의 -1.0으로 설정된것을 확인할 수 있다. 법선벡터 설정은 glNormal3f 함수를 사용한다.
폴리곤 설정시 법선벡터는 폴리곤의 앞으로 나아감.
2. 단위 법선 벡터
법선벡터 -->정규화 --> 단위 벡터 --> OpenGL
단위가 1인 벡터를 단위벡터라고 함.
단위가 1인 법선벡터를 만들기 위해서 정규화(Normalization) 과정이 들어간다.
glEnable(GL_NORMALIZE); // 효율적이지 못하다.
glEnable(GL_RESCALE_NORMALS); // 단위 길이(1)이 아니지만 같은 비율을 통해 단위길이로 변환할 수 있음
때문에 직접 계산하는것이 프로세싱 속도를 높이는데 도움이 된다.
단위벡터 만들기: (x^2 + y^2 + z^2)^1/2 하면 됨
3. 법선 벡터 찾기
위 4점으로 만들어진 Polygon(면)에서 법선 벡터를 어떻게 구할까?
3점만 있으면 구하기 쉽다.
위 점들 중 3개점을 각각 P1, P2, P3라 지정하고 P1과 P2를 연결하는 V1 벡터, P1과 P3를 연결하는 V2벡터로 지정
수학: 두 벡터가 한점에서 만나면 평면을 만들 수 있고, 두 벡터 V1, V2 외적을 구하면 그 평면의 법선벡터를 구할 수 있다.
1. 3지점을 얻어 한점에서 만나는 두개의 벡터를 그림
2. 두 벡터의 외적을 구하여 법선벡터를 구함
http://opengl.czweb.org/ch09/279-282.html
법선벡터 구하는 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // Points p1, p2, & p3 specified in counterclockwise order void calcNormal(float v[3][3], float out[3]) { float v1[3],v2[3]; static const int x = 0; static const int y = 1; static const int z = 2; // Calculate two vectors from the three points v1[x] = v[0][x] - v[1][x]; v1[y] = v[0][y] - v[1][y]; v1[z] = v[0][z] - v[1][z]; v2[x] = v[1][x] - v[2][x]; v2[y] = v[1][y] - v[2][y]; v2[z] = v[1][z] - v[2][z]; // Take the cross product of the two vectors to get // the normal vector which will be stored in out[] out[x] = v1[y]*v2[z] - v1[z]*v2[y]; out[y] = v1[z]*v2[x] - v1[x]*v2[z]; out[z] = v1[x]*v2[y] - v1[y]*v2[x]; // Normalize the vector (shorten length to one) ReduceToUnit(out); } |
좀 더 공부해서 법선벡터를 많이 사용할때의 곡면 표현의 차이점을 봐야 겠다.
'OpenGL' 카테고리의 다른 글
OpenGL: Text in OpenGL (0) | 2014.05.15 |
---|---|
OpenGL: Selection and Picking (0) | 2014.05.05 |
OpenGL: Index of Vertex Array (0) | 2014.05.04 |
OpenGL: Geometric and Vertex (0) | 2014.05.04 |
OpenGL: gluPerspective, glFrustum (0) | 2014.04.20 |
■ OpenGL: Index of Vertex Array
요번에는 꼭지점배열과 인덱스의 관계를 알아 보려 한다.
꼭지점 인덱스 배열사용 이유
- 메모리 절약과 불필요한 변환을 줄이는 효과
꼭지점과 법선벡터를 배열 선언하여 사용할 경우
- 다시 계산하지 않고 재사용하게 되기 때문에 메모리 양을 줄일 수 있고, 버텍스에 대한 변환도 줄일 수 있다.(시간 절약).
- 다음의 사각형을 Vertex와 Index 배열을 사용해서 그려보장
http://www.anandtech.com/show/391/6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | GLfloat RectVertex[]={ -20.0f, 20.0f, 20.0f,//0 20.0f, 20.0f, 20.0f,//1 20.0f, -20.0f, 20.0f,//2 -20.0f, -20.0f, 20.0f,//3 -20.0f, 20.0f, -20.0f,//4 20.0f, 20.0f, -20.0f,//5 20.0f, -20.0f, -20.0f,//6 -20.0f, -20.0f, -20.0f //7 }; GLubyte RectIndexes[]={ 0,1,2,3,//Front 4,5,1,0,//Top 3,2,6,7,//Bottom 5,4,7,6,//Back 1,5,6,2,//Right 4,0,3,7 //Left }; |
우선 사각형의 vertex 배열을 만들고 나서 각 인덱스 배열을 선언
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | void C3DScatterPlot::RenderScene(void) { // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(0.0f, 0.0f, -350.0f); glRotatef(xRot, 1.0f, 0.0f, 0.0f); //x glRotatef(yRot, 0.0f, 1.0f, 0.0f); //y //배열의 사용 glEnableClientState(GL_VERTEX_ARRAY); glColor3f(0.0f, 1.0f, 0.0f); //색상 //데이터 위치 glVertexPointer(3, GL_FLOAT, 0, RectVertex); //드로잉 glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, RectIndexes); glPopMatrix(); } |
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);// 와이어 프레임으로 드로잉
인덱스 값은 바이트 포멧을 가진다.
glVertexPointer(3, GL_FLOAT, 0, RectVertex); //버텍스 배열에서 3개씩 묵음으로 위치를 가져온다.
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, RectIndexes);//
void glDrawElements(
GLenum mode, //Specifies what kind of primitives to render
GLsizei count, //Specifies the number of elements to be rendered.
GLenum type, //Specifies the type of the values in indices.
const GLvoid * indices // Specifies a pointer to the location where the indices are stored.
);
여기서 모드는 다음과 같은 심볼을 써야 함
GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN,
GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS, and GL_POLYGON
type값은 다음과 같은 심볼을 써야 함
GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.
http://www.opengl.org/sdk/docs/man2/xhtml/glDrawElements.xml
'OpenGL' 카테고리의 다른 글
OpenGL: Selection and Picking (0) | 2014.05.05 |
---|---|
OpenGL: Normal Vector (0) | 2014.05.04 |
OpenGL: Geometric and Vertex (0) | 2014.05.04 |
OpenGL: gluPerspective, glFrustum (0) | 2014.04.20 |
OpenGL: Setting Viewport (0) | 2014.04.19 |
■ OpenGL: Geometric and Vertex
지오메트릭은 머 도형이라고 이해하면 좋다. 그리고 버텍스는 꼭지점이다. 즉 꼭지점을 알고 있으면 선으로 연결하여 도형을 만들 수 있는 관계가 성립된다.
OpenGL에서 도형을 만들기 위한 방법으로
- 지원되는 함수 사용
- glBegin - glEnd를 통해 그리기
가 있는 것 같다. 하지만 이 함수보다 효율적으로 빠르게 도형을 만들기 위해서 버텍스 배열을 사용한다고 한다. 한번 알아 보자 어떻게 하는지
1. OpenGL에서 Vertex 사용 방법
step 1: 디스크 파일 또는 알고리즘을 통해 지오메트리 데이터를 읽어 배열에 저장
- 위치 또는 도형에 대한 vertex 정보를 담은 vertex 배열을 선언한다.
step 2: Vertex 배열 사용 설정
- OpenGL은 클라이언트(CPU)와 서버(그래픽 하드웨어)등 두가지 방법으로 동작함.
- 클라이언드 모드에서 Vertex 배열 사용 설정 함수
- glEnableClientState(GL_VERTEX_ARRAY) / glDisableClientState(GL_VERTEX_ARRAY) : 활성함수와 비활설 함수 짝을 이룬다.
void glEnableClientState(GLenum cap);
Specifies the capability to enable. Symbolic constants GL_COLOR_ARRAY, GL_EDGE_FLAG_ARRAY, GL_FOG_COORD_ARRAY, GL_INDEX_ARRAY, GL_NORMAL_ARRAY, GL_SECONDARY_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY, and GL_VERTEX_ARRAY are accepted.
http://www.opengl.org/sdk/docs/man2/xhtml/glEnableClientState.xml
step 3: 배열의 형태 지정(vertex, color, normal vector, etc.)
vertex 배열을 선언하고 사용하겠다라고 예기했으니 데이터를 얻을라면 어디 버텍스 정보를 가져다 써라라고 해줘야 함. 아래와 같은 여러 함수가 있는데 입맛에 따라서 골라서 써야 함. 복잡하지만 정리하면 다음과 같음
================================================================================================
- GLint size: 좌표 타입을 구성하는 요소(두개 -x,y 세개-x,y,z 내게-x,y,z,w)
- CLenum Type: 실수 인지 정수인지 데이터 포멧(GLfloat)
- GLsizei stride: stride is the byte offset between consecutive vertexes. If stride is 0, the vertices are understood to be tightly packed in the array.(배열에서 가져올때 간격을 말하는듯, 0이면 배열 0,1,2..,N 이렇게 순차적으로 가져오고 만약 1이면 0, 2, 4, ...,N 요렇게? 가져 올듯)
- GLvoid *pointer: 데이터를 가져올 Vertex 배열
================================================================================================
void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
void glIndexPointer(GLenum type, GLsizei stride, const GLvoid *pointer);
void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer);
void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
void glEdgeFlagPointer(GLsizei stride, const GLvoid *pointer);
void glVertexPointer(GLint size, GLenumtype, GLsizei stride, const GLvoid *pointer); //버텍스 위치 정보
Command | Sizes | Values for type Argument |
glVertexPointer | 2, 3, 4 | GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE |
glNormalPointer | 3 | GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE |
glColorPointer | 3, 4 | GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, GL_DOUBLE |
glIndexPointer | 1 | GL_UNSIGNED_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE |
glTexCoordPointer | 1, 2, 3, 4 | GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE |
glEdgeFlagPointer | 1 | no type argument (type of data must be GLboolean) |
http://www.felixgers.de/teaching/jogl/vertexArrayData.html
glVertexPointer(2, GL_FLOAT, 0, Vertex);//좌표 타입 x,y로 구성, 데이터 포멧은 GLfloat, 데이터 간격은 0으로 Vertex 배열에 위치 지정
step 4: 배열 정보 랜더링
이제 마지막으로 꼭지점들의 정보를 받았으니 이 정보들을 랜덩링해서 보여주면 된다.
glDrawArrays(GL_POINTS, 0, 10); // POINT 형식으로 처음 0 번째 부터 10개를 그려라
glDrawArrays(CLenum 모드, GLint 처음, GLint 개수);
GLenum 모드: OpenGL 의 Basic Model 중 하나가 되고
GLint 처음: 이전 지정한 vertex 배열에서 시작 주소
GLint 개수: 시작 지점으로 부터 읽을 vertex 의 개수가 됨
2. 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | void C3DScatterPlot::RenderScene(void) { // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glTranslatef(0.0f, 0.0f, -350.0f); //원근 투영을 사용하고 있으므로 z좌표를 뒤로 350 이동하여 보기 GLfloat Vertex[10][2]; //꼭지점 정보 저장을 위한 2차원 배열 설정 for(int i=0; i<10; i++){ //10개의 x, y 좌표를 랜덤하게 Vertex 배열에 저장 Vertex[i][0]=(GLfloat)(rand()%50); // y Vertex[i][1]=(GLfloat)(rand()%50); // x } //Vertex 배열 사용 활성화- 클라이언트 모드 glEnableClientState(GL_VERTEX_ARRAY); //포인트를 그릴때 크기 지정 glPointSize(10.0f); //색상 지정 glColor3f(0.0f, 1.0f, 0.0f); //Vertex 배열 위치 지정 glVertexPointer(2, GL_FLOAT, 0, Vertex); //드로잉 glDrawArrays(GL_POINTS, 0, 10); } |
void glDrawArrays(
GLenum mode,
GLint first,
GLsizei count
);
mode
Specifies what kind of primitives to render. Symbolic constants GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_TRIANGLE_STRIP_ADJACENCY and GL_TRIANGLES_ADJACENCY are accepted.
first
Specifies the starting index in the enabled arrays.
count
Specifies the number of indices to be rendered.
위에 보면 랜덤으로 x,y 를 저장하고 있는 꼭지점 배열의 정보를 가져와 10의 사이즈를 갖는 Point들이 드로잉 된것을 볼 수 있다.
http://www.felixgers.de/teaching/jogl/vertexArrayData.html
'OpenGL' 카테고리의 다른 글
OpenGL: Normal Vector (0) | 2014.05.04 |
---|---|
OpenGL: Index of Vertex Array (0) | 2014.05.04 |
OpenGL: gluPerspective, glFrustum (0) | 2014.04.20 |
OpenGL: Setting Viewport (0) | 2014.04.19 |
OpenGL: Setting Clipping region (0) | 2014.04.19 |