文章目录
- 一、说明
- 二、下列程序使用库
- 三、OpenGL图元盘点
- 四、图元解析
- 4.1 线段
- 4.2 表面surface
- 4.3 三角形表面surface
- 五、图元作图示例
- 5.1 三角链和圆环GL_TRIANGLE_STRIP
- 5.2 三角链和圆环
- 六、三维物体渲染
- 6.1 直纹面
- 6.2 旋转面
- 七、GLSL程序优化代码
- 7.1 顶点着色器
- 7.2 几何着色器
- 7.2 片段着色器
一、说明
在OPenGL的图元设计中,已经包含一定的算法,仔细研究,我们就会发现,一些对象的生成方式,就是通过灵活运用图元完成的。本文将按照图元的给定方法,渲染出若干物体对象。
二、下列程序使用库
在我们的 OpenGL 程序中使用了以下三组软件库:
- OpenGL 核心库(GL):包含数以百计的函数,以 “gl”开头(例如:glColor,glVertex, glTranslate,glRotate)。OpenGL 核心库通过一组几何图元(例如点,线,多边形)来进行建模。
- OpenGL 实用程序库(GLU):基于 OpenGL 核心构建,提供一些重要的实用程序(例如:设置摄像机以及投影),以 “glu”开头(例如:gluLookAt,gluPerspective)。
- OpenGL 实用工具包(GLUT):OpenGL 被设计为独立于操作系统。因此我们需要 GLUT 来与操作系统进行交互(例如:创建窗口,处理键盘和鼠标输入),其提供的函数以 “glut” 开头(例如:glutCreatewindow,glutMouseFunc)。GLUT 是平台无关的,其基于平台相关的 OpenGL 扩展构建,例如对于 X Window 是 GLX,对于 Windows 系统是 WGL,对于 Mac OS 则是 AGL,CGL 或者 Cocoa。
三、OpenGL图元盘点
共有10种图元,这10个基本图元能较为方便地生成各自的曲线和曲面模型,如下图标所示。
四、图元解析
4.1 线段
- GL_LINES:这是纯线段图像的图元,比如网格。或Frame这正是恰挡应用。也可以是机械制图作品描述。
- GL_LINE_STRIP:这是外观复杂,但基本可以直线段描述的区域表述。
- GL_LINE_LOOP:适应于以角度为参数的图形。圆周、椭圆,双曲线等。
4.2 表面surface
- GL_POLYGON:多边形面,适应于大面积的面描述。
- GL_QUARDS:适应于小面的拼接表述,如球面中经纬度相交后区域。
- GL_QUARD_STRIP:条形或带形物体描述,球面也可。
4.3 三角形表面surface
- GL_TRIGANLE:此适应任何复杂表面拼接。
- GL_TRIANGLE_STRIP:绘制环面区域,条带等。
- GL_TRIANGLE_FAN:对于锥体,直平面一类的有效。
复杂图像只能是线段渲染,如图:
五、图元作图示例
5.1 三角链和圆环GL_TRIANGLE_STRIP
GL_TRIANGLE_STRIP则稍微有点复杂。如:顶点序列是【1,2,3,4,5,6,7,8】那么,三角形链的三角形分别是:
Δ1,2,3
Δ2,3,4
Δ 3,4,5
Δ4,5,6
Δ5,6,7
Δ6,7,8
其规律是:
5.2 三角链和圆环
数据结构,有两个数列:inroop=【0,1,2,,,,11】;outroop=【0,1,2,,,,11】
将两个序列进行合并:
outroop【0】=1;inroop【0】=2;outroop【1】=3;inroop【1】=4;
outroop【2】=5;inroop【2】=6;outroop【3】=7;inroop【3】=8;
…
这样组成的三角形,将构成圆环。如图:
我们按照上面算法,其渲染效果如下:
当我们把内圆的直径收缩到接近0后,渲染出一个红太阳。
六、三维物体渲染
6.1 直纹面
指纹面相对来说是较容易实现的曲面渲染。直纹面的实现方法也是多样的,用GL_TRIGANLE就可以实现。
6.2 旋转面
旋转面相对较难完成。它的实现方法需要在三维立体上建立面模型。
这个漂亮的救生圈,是我们应用微分几何的《曲面论》结合OpenGL的着色器完成,具体代码见XXX地址。
七、GLSL程序优化代码
这是一个灵活使用着色器的代码,可以优化上述程序,具有很大参考意义。
7.1 顶点着色器
坐标之转换:
1)模型坐标转世界坐标
2)世界坐标转视觉坐标
3) 视觉坐标转屏幕坐标。
Vertex Shader
#version 150
in vec4 gxl3d_Position;
void main()
{
gl_Position = gxl3d_Position;
}
7.2 几何着色器
几何着色器可以优化,剔除顶点。
Geometry Shader
#version 150
layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;
uniform mat4 gxl3d_ModelViewProjectionMatrix; // GeeXLab auto uniform
uniform vec2 WIN_SCALE;
out vec3 dist;
void main()
{
vec4 p0_3d = gl_in[0].gl_Position;
vec4 p1_3d = gl_in[1].gl_Position;
vec4 p2_3d = gl_in[2].gl_Position;
// Compute the vertex position in the usual fashion.
p0_3d = gxl3d_ModelViewProjectionMatrix * p0_3d;
// 2D position
vec2 p0 = p0_3d.xy / p0_3d.w;
// Compute the vertex position in the usual fashion.
p1_3d = gxl3d_ModelViewProjectionMatrix * p1_3d;
// 2D position
vec2 p1 = p1_3d.xy / p1_3d.w;
// Compute the vertex position in the usual fashion.
p2_3d = gxl3d_ModelViewProjectionMatrix * p2_3d;
// 2D position
vec2 p2 = p2_3d.xy / p2_3d.w;
//--------------------------------
// Project p1 and p2 and compute the vectors v1 = p1-p0
// and v2 = p2-p0
vec2 v10 = WIN_SCALE*(p1 - p0);
vec2 v20 = WIN_SCALE*(p2 - p0);
// Compute 2D area of triangle.
float area0 = abs(v10.x*v20.y - v10.y*v20.x);
// Compute distance from vertex to line in 2D coords
float h0 = area0/length(v10-v20);
dist = vec3(h0, 0.0, 0.0);
// Quick fix to defy perspective correction
dist *= p0_3d.w;
gl_Position = p0_3d;
EmitVertex();
//--------------------------------
// Project p0 and p2 and compute the vectors v01 = p0-p1
// and v21 = p2-p1
vec2 v01 = WIN_SCALE*(p0 - p1);
vec2 v21 = WIN_SCALE*(p2 - p1);
// Compute 2D area of triangle.
float area1 = abs(v01.x*v21.y - v01.y*v21.x);
// Compute distance from vertex to line in 2D coords
float h1 = area1/length(v01-v21);
dist = vec3(0.0, h1, 0.0);
// Quick fix to defy perspective correction
dist *= p1_3d.w;
gl_Position = p1_3d;
EmitVertex();
//--------------------------------
// Project p0 and p1 and compute the vectors v02 = p0-p2
// and v12 = p1-p2
vec2 v02 = WIN_SCALE*(p0 - p2);
vec2 v12 = WIN_SCALE*(p1 - p2);
// Compute 2D area of triangle.
float area2 = abs(v02.x*v12.y - v02.y*v12.x);
// Compute distance from vertex to line in 2D coords
float h2 = area2/length(v02-v12);
dist = vec3(0.0, 0.0, h2);
// Quick fix to defy perspective correction
dist *= p2_3d.w;
gl_Position = p2_3d;
EmitVertex();
//--------------------------------
EndPrimitive();
}
7.2 片段着色器
可以实现颜色blend等具体功能。
Pixel Shader
#version 150
uniform vec3 WIRE_COL;
uniform vec3 FILL_COL;
in vec3 dist;
out vec4 FragColor;
void main()
{
// Undo perspective correction.
//vec3 dist_vec = dist * gl_FragCoord.w;
// Wireframe rendering is better like this:
vec3 dist_vec = dist;
// Compute the shortest distance to the edge
float d = min(dist_vec[0], min(dist_vec[1], dist_vec[2]));
// Compute line intensity and then fragment color
float I = exp2(-2.0*d*d);
FragColor.rgb = I*WIRE_COL + (1.0 - I)*FILL_COL;
FragColor.a = 1.0;
}