PowerPoint 簡報

Download Report

Transcript PowerPoint 簡報

Modeling
靜宜大學資工系 蔡奇偉副教授
大綱






何謂多邊形?
多邊形的種類
多邊形的正面與反面
填滿多邊形
OpenGL 多邊形相關函式
範例
何謂多邊形?
n 邊的多邊形(polygon)是由 n 個共平面的端點 v1, v2, …, vn 和
n 條邊線 (v1, v2),(v2, v3), …, (vn-1, vn), (vn, v1) 所組成。
v1
v2
v3
v7
v1
v1
v4
v2
v3
v3
v5
v6
v2
v3
v1
v4
v4
v5
v2
多邊形的種類
簡單多邊形(simple polygon)
邊線都不相交而且沒有洞的多邊形。又可分成:
凸多邊形(convex polygon)
假定 a 和 b 是多邊形中任意的兩點。線段 ab 上所有
的點也都在多邊形中。
凹多邊形(concave polygon)
不是凸的簡單多邊形即為凹多邊形。
非簡單多邊形(non-simple polygon)
邊線相交或有洞的多邊形。
凸多邊形
凹多邊形
非簡單的多邊形
多邊形的正面與反面
在三度空間中,多邊形有正反兩面。通常我們把端點順序符合
逆時針方向的那一面稱為正面,另一面稱為反面。
v3
v2
反
面
正
面
v4
v1
OpenGL 多邊形相關函式




glRect*()
glPolygonMode()
glFrontFace()
glCullFace()
glRect{sifd} (TYPE x1, TYPE y1, TYPE x2, TYPE y2)
在 z = 0 的平面上,畫一個以 (x1, y1) 和 (x2, y2) 為對角端
點的矩形。
(x2, y2)
(x1, y1)
glRect{sifd}v (TYPE *v1, TYPE *v2)
v1: 用來存第一個端點的陣列
v2: 用來存第二個端點的陣列
(x1, y1)
(x2, y2)
glBegin(type)
/* 一連串的 glVertex*() 呼叫 */
glEnd()
參數 type 可以是下面的常數值:
GL_TRIANGLES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
GL_QUADS
GL_QUAD_STRIP
GL_POLYGON
glPolygonMode (GLenum face, GLenum mode)
控制多邊形的繪製的方式。
參數 face 設定繪製多邊形的正面或反面,其值為:
GL_FRONT_AND_BACK
正反面都畫
參數 mode 設定繪製的模式,其值可為:
GL_FILL
填滿多邊形內部(此為預設的模式)
GL_LINE
只畫多邊形的框線
GL_POINT
只畫多邊形的端點
glFrontFace (GLenum mode)
設定多邊形正面的決定方式。
參數 mode 設定正面的方向,其值可為:
GL_CCW
逆時針方向為正面(此為預設值)
GL_CW
順時針方向為正面
v3
v3
v2
GL_CCW
v2
GL_CW
正
面
v4
v1
v4
v1
正
面
glCullFace (GLenum mode)
設定多邊形那一個面被剔除(cull)。
參數 mode 選擇那一面被剔除,其值可為:
GL_FRONT
正面
GL_BACK
反面
GL_FRONT_AND_BACK
正面和反面
呼叫此函式之前,你必須已經呼叫
glEnable(GL_CULL_FACE)
來啟動此 OpenGL 的剔除功能。
若要關閉此功能,則可呼叫:
glDisable(GL_CULL_FACE)
範例:cube 繪製方法(使用 triangles)
y
2
vertex list
3
back
6
7
x
1
1
2
3
4
5
6
7
5
front
z
0
0
4
void make_cube_vertices ( GLfloat size )
{
GLfloat half_size = size / 2.0f;
vertexList[0]
vertexList[1]
vertexList[2]
vertexList[3]
vertexList[4]
vertexList[5]
vertexList[6]
vertexList[7]
}
=
=
=
=
=
=
=
=
vec3(-half_size,
vec3(-half_size,
vec3(-half_size,
vec3(-half_size,
vec3( half_size,
vec3( half_size,
vec3( half_size,
vec3( half_size,
-half_size,
-half_size,
half_size,
half_size,
-half_size,
-half_size,
half_size,
half_size,
half_size);
-half_size);
-half_size);
half_size);
half_size);
-half_size);
-half_size);
half_size);
2
3
back
6
7
1
5
front
0
4
void draw_cube01 (void)
{
vec3 tv[36]; // vertices of triangles
tv[0] =
tv[3] =
vertexList[2]; tv[1]
vertexList[7]; tv[4]
= vertexList[3]; tv[2]
= vertexList[6]; tv[5]
= vertexList[7];
= vertexList[2];
......
tv[30] = vertexList[4]; tv[31] = vertexList[0]; tv[32] = vertexList[5];
tv[33] = vertexList[0]; tv[34] = vertexList[1]; tv[35] = vertexList[5];
glBufferData( GL_ARRAY_BUFFER, 36*sizeof(vec3), tv, GL_STATIC_DRAW );
glVertexAttribPointer( loc, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
glDrawArrays( GL_TRIANGLES, 0, 36 );
}
Triangle Strips with Winding Order
Triangle strips do face culling differently. For every second triangle, the
one who's winding order is opposite from the first triangle's order, the
winding order is considered backwards for culling purposes.
So if you have set the front face to be clockwise, and have face culling cull
back-facing triangles, everything will work exactly as you expect so long
as the order of the first triangle is correct. Every even numbered triangle
will be culled if it has a clockwise winding, and every odd numbered
triangle will be culled if it has a counter-clockwise winding.
範例:cube 繪製方法(使用 triangle strips)
void draw_cube02 (void)
{
vec3 tv[18]; // vertices of triangles
tv[0]
tv[3]
tv[6]
tv[9]
=
=
=
=
vertexList[3]; tv[1]
vertexList[4]; tv[4]
vertexList[2]; tv[7]
vertexList[0];
= vertexList[0]; tv[2]
= vertexList[6]; tv[5]
= vertexList[1]; tv[8]
= vertexList[7];
= vertexList[5];
= vertexList[3];
2
tv[10] = vertexList[2]; tv[11] = vertexList[3];
tv[12] = vertexList[6]; tv[13] = vertexList[7];
3
6
7
1
tv[14] = vertexList[0]; tv[15] = vertexList[1];
tv[16] = vertexList[4]; tv[17] = vertexList[5];
0
5
4
glBufferData( GL_ARRAY_BUFFER, 18*sizeof(vec3), tv, GL_STATIC_DRAW );
glVertexAttribPointer( loc, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
glDrawArrays( GL_TRIANGLE_STRIP, 0, 10 );
glDrawArrays( GL_TRIANGLE_STRIP, 10, 4 );
glDrawArrays( GL_TRIANGLE_STRIP, 14, 4 );
}
Draw Elements



glDrawElements()
glMultiDrawElements()
glDrawRangeElements()
vertex arrays
index array
範例:cube 繪製方法(使用 elements)
建立 Buffer Objects
GLuint buffer[2];
// Buffer object ID’s
enum {VERTEX_ARRAY, ELEMENT_ARRAY};
glGenBuffers( 2, buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer[VERTEX_ARRAY] );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffer[ELEMENT_ARRAY] );
2
void draw_cube (void)
{
GLushort idx[18] = {
3, 0, 7, 4, 6, 5, 2, 1, 3, 0,
2, 3, 6, 7,
0, 1, 4, 5
};
3
6
7
1
0
5
4
glBufferData( GL_ARRAY_BUFFER, 8*sizeof(vec3), vertexList,
GL_STATIC_DRAW );
glVertexAttribPointer( loc, 3, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0) );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, 18*sizeof(GLushort), idx,
GL_STATIC_DRAW );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_SHORT,
BUFFER_OFFSET(0));
glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT,
BUFFER_OFFSET(10*sizeof(GLushort)));
glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT,
BUFFER_OFFSET(14*sizeof(GLushort)));
}
範例:Sphere 繪製方法
void make_sphere_vertices ( GLdouble radius, GLint slices, GLint stacks)
{
nVertices = slices * (stacks - 1) + 2; // two poles
vertexList = new vec3[nVertices];
vertexList[0] = vec3(0.0f, radius, 0.0f);
GLdouble ds = 2 * radius / stacks;
GLdouble yval = radius, dtheta = 2.0 * M_PI / slices;
int k = 1;
for (int i = 1; i < stacks; i++)
{
yval -= ds;
GLdouble r = std::sqrt(radius*radius - yval*yval);
GLdouble ang = 0.0;
for (int j = 0; j < slices; j++)
{
vertexList[k] = vec3(r*std::cos(ang), yval, r*std::sin(ang));
k++;
ang += dtheta;
}
}
vertexList[k] = vec3(0.0f, -radius, 0.0f);
}
glBufferData( GL_ARRAY_BUFFER, nVertices*sizeof(vec3),
vertexList, GL_STATIC_DRAW );
glVertexAttribPointer( loc, 3, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0) );
// North pole
nv = nSlices+2; // number of vertices
idx[0] = 0;
for (i = 1; i <= nSlices; i++)
idx[i] =
i;
idx[i] = 1;
glBufferData( GL_ELEMENT_ARRAY_BUFFER, nv*sizeof(GLushort),
idx, GL_STATIC_DRAW );
glDrawElements( GL_TRIANGLE_FAN, nv, GL_UNSIGNED_SHORT,
BUFFER_OFFSET(0));
// inside stacks
nv = 2*nSlices+2; // number of vertices
for (int k = 1; k < nStacks - 1; k++) {
int k1 = nSlices * (k -1) + 1;
int k2 = nSlices * k + 1;
for (int j = 0; j < 2*nSlices; j+=2) {
idx[j] = k1++;
idx[j+1] = k2++;
}
idx[nv-2] = idx[0];
idx[nv-1] = idx[1];
glBufferData( GL_ELEMENT_ARRAY_BUFFER, nv*sizeof(GLushort), idx,
GL_STATIC_DRAW );
glDrawElements( GL_TRIANGLE_STRIP, nv, GL_UNSIGNED_SHORT,
BUFFER_OFFSET(0));
}
// South pole
nv = nSlices+2; // number of vertices
idx[0] = nVertices - 1;
for (i = 1; i <= nSlices; i++)
idx[i] = nVertices - nSlices - 2 + i;
idx[i] = nVertices - nSlices - 1;
glBufferData( GL_ELEMENT_ARRAY_BUFFER, nv*sizeof(GLushort), idx,
GL_STATIC_DRAW );
glDrawElements( GL_TRIANGLE_FAN, nv, GL_UNSIGNED_SHORT,
BUFFER_OFFSET(0));
vertex list
nVertices – 1 – nSlices
nVertices – 1
Hidden-Line Removal with Polygon Offset
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
set_color(foreground);
draw_object_with_filled_polygons();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
set_color(background);
draw_object_with_filled_polygons();
glDisable(GL_POLYGON_OFFSET_FILL);
範例: Icosahedron 繪製方法
#define X .525731112119133606
#define Z .850650808352039932
void make_icosahedron_vertices ( GLdouble radius)
{
vdata[0] = radius * vec3(-X, 0.0, Z);
vdata[1] = radius * vec3(X, 0.0, Z);
vdata[2] = radius * vec3(-X, 0.0, -Z);
vdata[3] = radius * vec3(X, 0.0, -Z);
vdata[4] = radius * vec3(0.0, Z, X);
vdata[5] = radius * vec3(0.0, Z, -X);
vdata[6] = radius * vec3(0.0, -Z, X);
vdata[7] = radius * vec3(0.0, -Z, -X);
vdata[8] = radius * vec3(Z, X, 0.0);
vdata[9] = radius * vec3(-Z, X, 0.0);
vdata[10] = radius * vec3(Z, -X, 0.0);
vdata[11] = radius * vec3(-Z, -X, 0.0);
}
GLushort tindices[20][3] = {
{1,4,0}, {4,9,0}, {4,5,9}, {8,5,4}, {1,8,4}, {1,10,8}, {10,3,8},
{8,3,5}, {3,2,5}, {3,7,2}, {3,10,7}, {10,6,7}, {6,11,7}, {6,0,11},
{6,1,0}, {10,1,6}, {11,0,9}, {2,11,9}, {5,2,9}, {11,2,7}
};
範例:Sphere 繪製方法(subdivision)
Icosahedron
void subdivide(vec3 v1, vec3 v2, vec3 v3)
{
vec3 v12, v23, v31;
GLint i;
v12 = (v1+v2)/2.0;
v23 = (v2+v3)/2.0;
v31 = (v3+v1)/2.0;
// 映射至球面上
v12 = radius * normalize(v12);
v23 = radius * normalize(v23);
v31 = radius * normalize(v31);
v2
drawtriangle(v1, v12, v31);
drawtriangle(v2, v23, v12);
drawtriangle(v3, v31, v23);
drawtriangle(v12, v23, v31);
}
v23
v12
v1
v3
v31
Recursive Subdivision
void subdivide(vec3 v1, vec3 v2, vec3 v3, int depth)
{
GLfloat v12, v23, v31;
GLint i;
if (depth == 0) {
drawtriangle(v1, v2, v3);
return;
}
v12 = (v1+v2)/2.0;
v23 = (v2+v3)/2.0;
v31 = (v3+v1)/2.0;
// 映射至球面上
v12 = radius * normalize(v12);
v23 = radius * normalize(v23);
v31 = radius * normalize(v31);
subdivide(v1, v12, v31, depth-1);
subdivide(v2, v23, v12, depth-1); v1
subdivide(v3, v31, v23, depth-1);
subdivide(v12, v23, v31, depth-1);
}
v2
v23
v12
v3
v31
參考資料
1.
2.
OpenGL Programming Guide, 7E Version 3.0 and 3.1 (2010)
OpenGL Shading Language 3rd Edition (2010)