OpenGL蓝宝书源码学习(六)第三章——Smoother.cpp

混合功能--抗锯齿源码示例(二维图形)

// Smoother.cpp
// OpenGL SuperBible
// Demonstrates point and line antialiasing
// Program by Richard S. Wright Jr.
#include 
   
   
    
    	// OpenGL toolkit
#include 
    
    
     
     

#ifdef __APPLE__
#include 
     
     
      
      
#else
#define FREEGLUT_STATIC
#include 
      
      
       
       
#endif

GLShaderManager shaderManager;
GLFrustum viewFrustum;
GLBatch smallStarBatch;
GLBatch mediumStarBatch;
GLBatch largeStarBatch;
GLBatch mountainRangeBatch;
GLBatch moonBatch;

// Array of small stars
#define SMALL_STARS     100
#define MEDIUM_STARS     40
#define LARGE_STARS      15

#define SCREEN_X        800
#define SCREEN_Y        600

///
// Reset flags as appropriate in response to menu selections
void ProcessMenu(int value)
    {
    switch(value)
        {
        case 1:
            // Turn on antialiasing, and give hint to do the best
            // job possible.
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            glEnable(GL_POINT_SMOOTH);
            glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
            glEnable(GL_LINE_SMOOTH);
            glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
            glEnable(GL_POLYGON_SMOOTH);
            glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
            break;

        case 2:
            // Turn off blending and all smoothing
            glDisable(GL_BLEND);
            glDisable(GL_LINE_SMOOTH);
            glDisable(GL_POINT_SMOOTH);
            break;

        default:
            break;
        }
        
    // Trigger a redraw
    glutPostRedisplay();
    }


///
// Called to draw scene
void RenderScene(void)
    {		        
    // Clear the window
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         
    // Everything is white
    GLfloat vWhite [] = { 1.0f, 1.0f, 1.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_FLAT, viewFrustum.GetProjectionMatrix(), vWhite);
    
    // Draw small stars
    glPointSize(1.0f);
    smallStarBatch.Draw();
            
    // Draw medium sized stars
    glPointSize(4.0f);
    mediumStarBatch.Draw();
    
    // Draw largest stars
    glPointSize(8.0f);
    largeStarBatch.Draw();
        
    // Draw the "moon"
    moonBatch.Draw();

    // Draw distant horizon
    glLineWidth(3.5);
    mountainRangeBatch.Draw();
    
    moonBatch.Draw();

    // Swap buffers
    glutSwapBuffers();
    }


// This function does any needed initialization on the rendering
// context. 
void SetupRC()
    {
    M3DVector3f vVerts[SMALL_STARS];       // SMALL_STARS is the largest batch we are going to need
    int i;
        
    shaderManager.InitializeStockShaders();
        
    // Populate star list
    smallStarBatch.Begin(GL_POINTS, SMALL_STARS);
    for(i = 0; i < SMALL_STARS; i++)
        {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f;
        }
    smallStarBatch.CopyVertexData3f(vVerts);
    smallStarBatch.End();
            
    // Populate star list
    mediumStarBatch.Begin(GL_POINTS, MEDIUM_STARS);
    for(i = 0; i < MEDIUM_STARS; i++)
        {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f; 
        }
    mediumStarBatch.CopyVertexData3f(vVerts);
    mediumStarBatch.End();

    // Populate star list
    largeStarBatch.Begin(GL_POINTS, LARGE_STARS);
    for(i = 0; i < LARGE_STARS; i++)
        {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f;
        }
    largeStarBatch.CopyVertexData3f(vVerts);
    largeStarBatch.End();
            
    M3DVector3f vMountains[12] = { 0.0f, 25.0f, 0.0f, 
                                 50.0f, 100.0f, 0.0f,
                                 100.0f, 25.0f, 0.0f,
                                225.0f, 125.0f, 0.0f,
                                300.0f, 50.0f, 0.0f,
                                375.0f, 100.0f, 0.0f,
                                460.0f, 25.0f, 0.0f,
                                525.0f, 100.0f, 0.0f,
                                600.0f, 20.0f, 0.0f,
                                675.0f, 70.0f, 0.0f,
                                750.0f, 25.0f, 0.0f,
                                800.0f, 90.0f, 0.0f };    
        
    mountainRangeBatch.Begin(GL_LINE_STRIP, 12);
    mountainRangeBatch.CopyVertexData3f(vMountains);
    mountainRangeBatch.End();
    
    // The Moon
    GLfloat x = 700.0f;     // Location and radius of moon
    GLfloat y = 500.0f;
    GLfloat r = 50.0f;
    GLfloat angle = 0.0f;   // Another looping variable
        
    moonBatch.Begin(GL_TRIANGLE_FAN, 34);
    int nVerts = 0;
    vVerts[nVerts][0] = x;
    vVerts[nVerts][1] = y;
    vVerts[nVerts][2] = 0.0f;
        for(angle = 0; angle < 2.0f * 3.141592f; angle += 0.2f) {
           nVerts++;
           vVerts[nVerts][0] = x + float(cos(angle)) * r;
           vVerts[nVerts][1] = y + float(sin(angle)) * r;
           vVerts[nVerts][2] = 0.0f;
           }
    nVerts++;
   
    vVerts[nVerts][0] = x + r;;
    vVerts[nVerts][1] = y;
    vVerts[nVerts][2] = 0.0f;
    moonBatch.CopyVertexData3f(vVerts);
    moonBatch.End();     
            
    // Black background
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
    }



void ChangeSize(int w, int h)
    {
    // Prevent a divide by zero
    if(h == 0)
        h = 1;

    // Set Viewport to window dimensions
    glViewport(0, 0, w, h);

    // Establish clipping volume (left, right, bottom, top, near, far)
    viewFrustum.SetOrthographic(0.0f, SCREEN_X, 0.0f, SCREEN_Y, -1.0f, 1.0f);
    }

int main(int argc, char* argv[])
	{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(800, 600);
	glutCreateWindow("Smoothing Out The Jaggies");
	
	// Create the Menu
	glutCreateMenu(ProcessMenu);
	glutAddMenuEntry("Antialiased Rendering",1);
	glutAddMenuEntry("Normal Rendering",2);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	
	glutReshapeFunc(ChangeSize);
	glutDisplayFunc(RenderScene);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
        }
        
	SetupRC();
	glutMainLoop();

	return 0;
	}

      
      
     
     
    
    
   
   

此源码示例运用了混合的功能,展示了平滑像素的效果。对比两个效果图,明显毛刺被平滑了。


源码解析:

此示例实际上是使用点、线以及图元画了一幅星星、月亮和山脉的黑白画,通过开启平滑的功能实现图形的平滑

#define SMALL_STARS     100
#define MEDIUM_STARS     40
#define LARGE_STARS      15
     //定义了各种星星的数量

#define SCREEN_X        800
#define SCREEN_Y        600
//定义窗口大小

1、 void SetupRC()
    {
    M3DVector3f vVerts[SMALL_STARS];      
//
定义小星星的顶点

int i;

shaderManager.InitializeStockShaders();

//开始设置小星星的批次图元,并根据小星星的数量,循环设置星星的顶点坐标

smallStarBatch.Begin(GL_POINTS, SMALL_STARS);

for(i = 0; i < SMALL_STARS; i++)
   
        {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f;
     
          }

smallStarBatch.CopyVertexData3f(vVerts);
  smallStarBatch.End();

mediumStarBatch.Begin(GL_POINTS, MEDIUM_STARS);
 
        for(i = 0; i < MEDIUM_STARS; i++)
   
        {
       
  vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
      vVerts[i][2] = 0.0f; 
   
        }
    mediumStarBatch.CopyVertexData3f(vVerts);
    mediumStarBatch.End();

    largeStarBatch.Begin(GL_POINTS, LARGE_STARS);
    for(i = 0; i < LARGE_STARS; i++)
        {
        vVerts[i][0] = (GLfloat)(rand() % SCREEN_X);
        vVerts[i][1] = (GLfloat)(rand() % (SCREEN_Y - 100)) + 100.0f;
        vVerts[i][2] = 0.0f;
        }
    largeStarBatch.CopyVertexData3f(vVerts);
    largeStarBatch.End();

//设置山脉图形的顶点坐标,把顶点连起来看起来像山脉,并设置批次图元

M3DVector3f vMountains[12] = { 0.0f, 25.0f, 0.0f, 
                                 50.0f, 100.0f, 0.0f,
                                 100.0f, 25.0f, 0.0f,
                                225.0f, 125.0f, 0.0f,
                                300.0f, 50.0f, 0.0f,
                                375.0f, 100.0f, 0.0f,
                                460.0f, 25.0f, 0.0f,
                                525.0f, 100.0f, 0.0f,
                                600.0f, 20.0f, 0.0f,
                                675.0f, 70.0f, 0.0f,
                                750.0f, 25.0f, 0.0f,
                                800.0f, 90.0f, 0.0f }; 

//根据上面的12个顶点,画相连的线带  P67

 mountainRangeBatch.Begin(GL_LINE_STRIP, 12);
    mountainRangeBatch.CopyVertexData3f(vMountains);
    mountainRangeBatch.End();

//设置月亮的位置坐标、半径和弧度

GLfloat x = 700.0f;    
   GLfloat y = 500.0f;
    GLfloat r = 50.0f;
    GLfloat angle = 0.0f;  

//月亮的绘制是使用34个三角形扇拼接而成,

 moonBatch.Begin(GL_TRIANGLE_FAN, 34);
   
//初始化坐

 int nVerts = 0;
    vVerts[nVerts][0] = x;
    vVerts[nVerts][1] = y;
   
vVerts[nVerts][2] = 0.0f;

//循环弧度值画圆(2.0f*3.141592f就是2π,即一个圆周)

for(angle = 0; angle < 2.0f * 3.141592f; angle += 0.2f) {

//设置批次图元的坐标(是拼接圆周的三角形的坐标),x和y的坐标等于初始坐标加上弧度的余弦值、弧度的正弦与半径的成绩(),并++三角形扇的个数。

           nVerts++;
           vVerts[nVerts][0] = x + float(cos(angle)) * r;
           vVerts[nVerts][1] = y + float(sin(angle)) * r;
           vVerts[nVerts][2] = 0.0f;
           }
    nVerts++;

        //最终的三角形扇图元的拷贝,并完成批次图元的设置

 vVerts[nVerts][0] = x + r;
   vVerts[nVerts][1] = y;
   
   vVerts[nVerts][2] = 0.0f;
    moonBatch.CopyVertexData3f(vVerts);
    moonBatch.End();  

   glClearColor(0.0f, 0.0f, 0.0f, 1.0f );//设置背景的清除颜色是黑色
   }

三角形扇:可以看书理解一下三角形扇行程过程 p71

2、void ChangeSize(int w,int h)

在函数中设置投影模式是正投影,设置裁剪范围,在范围内的图形会被显示在屏幕上

viewFrustum.SetOrthographic(0.0f, SCREEN_X, 0.0f, SCREEN_Y, -1.0f, 1.0f);

3、void RenderScene(void)

    {        
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//设置所有将要渲染的批次图元的颜色都是白色,并选择着色器(平面着色器),提供投影矩阵。把所有批次图元提交给着色器

    GLfloat vWhite [] = { 1.0f, 1.0f, 1.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_FLAT, viewFrustum.GetProjectionMatrix(), vWhite);
    
    glPointSize(1.0f);
//设置点的大小

    smallStarBatch.Draw();
            
    glPointSize(4.0f);
    mediumStarBatch.Draw();
    
    glPointSize(8.0f);
    largeStarBatch.Draw();
        
    moonBatch.Draw();

    glLineWidth(3.5);
//设置线宽

    mountainRangeBatch.Draw();
    
    moonBatch.Draw();


    glutSwapBuffers();
    }
  

4、void ProcessMenu(int value) //在main函数中创建的菜单栏的回调函数
    {
    switch(value)
        {
        case 1:
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//设置混合因子,注意在开启了混合之后,图形图元不但被平滑了,颜色的白色也变暗了
            glEnable(GL_BLEND);  //开启混合模式
            glEnable(GL_POINT_SMOOTH);  //开启点抗锯齿(平滑)
            glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
            glEnable(GL_LINE_SMOOTH);  //开启线抗锯齿(平滑)
            glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
            glEnable(GL_POLYGON_SMOOTH);  //开启多边形抗锯齿(平滑)
            glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
            break;

//关闭混合和平滑的功能

case 2:
            glDisable(GL_BLEND);
            glDisable(GL_LINE_SMOOTH);
            glDisable(GL_POINT_SMOOTH);
            break;

  default:
            break;
        }

//触发重绘(RenderScene)

 glutPostRedisplay();
    }

小结

抗锯齿(平滑)功能其实是混合功能的一个用途,在开启平滑功能前,要开启混合功能,关闭同样如此。此示例展示2维图形,在ChangeSize方法中设置了正投影的模式。我觉得其中要理解的地方是“月亮”的绘制,它应用了三角形扇的拼接,要理解顶点连接的顺序以及根据圆周的弧度值与弧长来判断顶点的坐标。再就是应用了平面着色器,需要给着色器提供一个投影矩阵。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值