- 理论基础
1,锯齿:在图元边缘处我们能相当清楚地看到两种颜色的分界,我们把这种称之为锯齿。为什么会产生?这是因为我们的图像是由一个个像素组成的,而每个像素近似一个很小的正方形,这样由正方形组成的图像边缘肯定会产生锯齿。示意图如下:
2,抗锯齿:常见的抗锯齿方法有两种:混合和多重采样。使用混合消除锯齿的原理是,在边缘处降低alpha值再做混合操作从而达到欺骗眼睛的目的。然而混合操作受绘制顺序的影响,对于整个场景的抗锯齿操作是很麻烦的(排序)。这时可以使用另一种抗锯齿方式,多重采样:它在边缘的像素颜色是采集了多种颜色信息最终计算得出个平滑的颜色。其实这种模式它是单独又开辟了一个缓冲区来保存这些信息,这些处理都是要额外带来开销的,有可能对性能造成影响。因此有些opengl实现可能并不支持多重采样。
注释:现在手机上貌似都不需要考虑锯齿问题了,因为分辨率普遍都很高了。
- 实例代码
1,使用混合形式的抗锯齿
#include "GLTools.h"
#include "GLShaderManager.h"
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
static float rotAngle = 0.;
void init(void)
{
GLfloat values[2];
/*获取opengl支持信息*/
glGetFloatv (GL_LINE_WIDTH_GRANULARITY, values);//线宽变化量(梯度)
printf ("GL_LINE_WIDTH_GRANULARITY value is %3.1f\n", values[0]);
glGetFloatv (GL_LINE_WIDTH_RANGE, values);//支持的线宽范围
printf ("GL_LINE_WIDTH_RANGE values are %3.1f %3.1f\n", values[0], values[1]);
glEnable (GL_LINE_SMOOTH);//启用线抗锯齿,边缘会降低其alpha值
glEnable (GL_BLEND);//启用混合
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/*对图像质量和渲染速度之间控制权衡关系*/
glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);//没有偏向
glLineWidth (1.5);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
//绘制绿线(默认alpha=1)
glColor3f (0.0, 1.0, 0.0);
glPushMatrix();
glRotatef(-rotAngle, 0.0, 0.0, 0.1);
glBegin (GL_LINES);
glVertex2f (-0.5, 0.5);
glVertex2f (0.5, -0.5);
glEnd ();
glPopMatrix();
//绘制蓝线
glColor3f (0.0, 0.0, 1.0);
glPushMatrix();
glRotatef(rotAngle, 0.0, 0.0, 0.1);
glBegin (GL_LINES);
glVertex2f (0.5, 0.5);
glVertex2f (-0.5, -0.5);
glEnd ();
glPopMatrix();
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D (-1.0, 1.0,
-1.0*(GLfloat)h/(GLfloat)w, 1.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D (-1.0*(GLfloat)w/(GLfloat)h,
1.0*(GLfloat)w/(GLfloat)h, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'r':
case 'R':
rotAngle += 20.;
if (rotAngle >= 360.) rotAngle = 0.;
glutPostRedisplay();
break;
case 27: /* Escape Key */
exit(0);
break;
default:
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (200, 200);
glutCreateWindow (argv[0]);
init();
glutReshapeFunc (reshape);
glutKeyboardFunc (keyboard);
glutDisplayFunc (display);
glutMainLoop();
return 0;
}
2,使用多重采样的抗锯齿
#include "GLTools.h"
#include "GLShaderManager.h"
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
/*多重采样步骤:
1,获得一个支持多重采样的窗口
2,查看系统是否支持
3,激活多重采样
*/
static int bgtoggle = 1;
void init(void)
{
static GLint buf[1], sbuf[1];
int i, j;
glClearColor(0.0, 0.0, 0.0, 0.0);
/*查看系统是否支持多重采样*/
glGetIntegerv (GL_SAMPLE_BUFFERS_ARB, buf);
printf ("number of sample buffers is %d\n", buf[0]);
glGetIntegerv (GL_SAMPLES_ARB, sbuf);
printf ("number of samples is %d\n", sbuf[0]);
/*显示列表形式*/
//线段与三角形交替环绕
glNewList (1, GL_COMPILE);
for (i = 0; i < 19; i++) {
glPushMatrix();
glRotatef(360.0*(float)i/19.0, 0.0, 0.0, 1.0);
glColor3f (1.0, 1.0, 1.0);
glLineWidth((i%3)+1.0);
glBegin (GL_LINES);//线段
glVertex2f (0.25, 0.05);
glVertex2f (0.9, 0.2);
glEnd ();
glColor3f (0.0, 1.0, 1.0);
glBegin (GL_TRIANGLES);//三角形
glVertex2f (0.25, 0.0);
glVertex2f (0.9, 0.0);
glVertex2f (0.875, 0.10);
glEnd ();
glPopMatrix();
}
glEndList ();
//二维正方形背景
glNewList (2, GL_COMPILE);
glColor3f (1.0, 0.5, 0.0);
glBegin (GL_QUADS);//正方形
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
if (((i + j) % 2) == 0) {
glVertex2f (-2.0 + (i * 0.25), -2.0 + (j * 0.25));
glVertex2f (-2.0 + (i * 0.25), -1.75 + (j * 0.25));
glVertex2f (-1.75 + (i * 0.25), -1.75 + (j * 0.25));
glVertex2f (-1.75 + (i * 0.25), -2.0 + (j * 0.25));
}
}
}
glEnd ();
glEndList ();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
if (bgtoggle)
glCallList (2);//二维正方形背景绘制
//左边
glEnable (GL_MULTISAMPLE_ARB);//激活多重采样
glPushMatrix();
glTranslatef (-1.0, 0.0, 0.0);
glCallList (1);//线段和三角形环绕绘制
glPopMatrix();
//右边
glDisable (GL_MULTISAMPLE_ARB);//关闭多重采样
glPushMatrix();
glTranslatef (1.0, 0.0, 0.0);
glCallList (1);
glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= (2 * h))
gluOrtho2D (-2.0, 2.0,
-2.0*(GLfloat)h/(GLfloat)w, 2.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D (-2.0*(GLfloat)w/(GLfloat)h,
2.0*(GLfloat)w/(GLfloat)h, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'b':
case 'B':
bgtoggle = !bgtoggle;
glutPostRedisplay();
break;
case 27: /* Escape Key */
exit(0);
default:
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
//创建一个支持多重采样,双缓冲,RGB颜色模式的窗口
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);
glutInitWindowSize (600, 300);
glutCreateWindow (argv[0]);
init();
glutReshapeFunc (reshape);
glutKeyboardFunc (keyboard);
glutDisplayFunc (display);
glutMainLoop();
return 0;
}