渲染世界的Opengl<5>基础渲染代码分析

1.混合知识
OpenGL渲染的时候会把颜色值放在颜色缓冲区当中。每个片段的深度值放在深度缓冲区中
打开了OpenGL的混合功能方法:

glEnable(GL_BLEND);

打开混合功能,新的颜色会与已经存在的颜色值在颜色缓冲区中进行组合。这些颜色的组合方式不同会导致很多不同的特殊效果。

(1)组合颜色术语
目标颜色:已经存储在颜色缓冲区中的颜色。这个颜色包含单独的红绿蓝以及一个可选的alpha值。
源颜色:作为当前渲染命令的结果进入颜色缓冲区。可能与目标颜色进行交互。也可以不与之进行交互。源颜色可以包含三种或者四种颜色成分。
混合方式启用的时候,默认情况下混合方程式:

Cf=(Cs*S)+(Cd*D)

Cf:最终产生的颜色,Cs是源颜色,Cd是目标颜色。
S、D为混合因子,并且都是枚举值。
调用下面的函数对其进行设置:

glBlendFunc(GLenum S, GLenum D);

(2)改变混合方程式
其中有五个混合方程式进行选择。

GL_FUNC_ADD:Cf=(Cs*S)+(Cd*D)
GL_FUNC_SUBTRACT:Cf=(Cs*S)-(Cd*D)
GL_FUNC_REVERSE_SUBTRACT:Cf=(Cd*D)-(Cs*S)
GL_MIN:MIN(Cs,Cd)
GL_MAX:MAX(Cs,Cd)

选择函数为:

void glBlendEquation(GLenum mode);
//使用上述枚举值对混合方程式进行选择。

void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);

注意glBlendFuncSeparate函数则允许为RGB和alpha成分单独指定混合函数。

void glBlendColor(GLclampf red,GLclampf green, GLclampf blue, GLclampf alpha);

这个函数可以对常量混合函数颜色进行修改。

(3)抗锯齿
在绝大多数情况,一个独立的渲染片段会映射到计算机屏幕上的一个像素。这些像素是正方形,通常可以相当清楚地看到两种颜色的分界,他们常常被称为锯齿,会吸引眼睛的注意力,让人觉得图像非常不自然。
解决方法:OpenGL使用混合功能来混合片段的颜色,也就是把像素的目标颜色和周围的颜色进行混合。

步骤:

//首先开启抗锯齿功能,首先必须启动混合功能
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

//并且把默认的混合方程式设置为GL_ADD。
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
//使用GL_POLYGON_SMOOTH的时候,需要很多其他规则:重叠的几何图形需要不同的混合模式、并可能对场景从前向后进行排序。

glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
//对其渲染模式进行微调。并且根据需要选择GL_NICEST或者GL_FASTEST。

(4)多重采样
抗锯齿处理最大优点之一是能够使得多边形边缘能够更加平滑,使渲染效果显得更加自然和逼真。然而多边形的平滑处理并不方便。抗锯齿处理是基于混合操作的。
多重采样可以解决这个问题。所有图元在每个像素上都进行多次采样,结果就存储在这个缓冲区中,每次当这个像素进行更新的时候,这些采样值进行解析,以产生一个单独的值。
如下请求一个多重采样:

//请求一个帧缓冲区作为多重采样的缓冲区。
glutDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_MULTISAMPLE);
//打开或者关闭多重采样
glEnable(GL_MULTISAMPLE);
glDisable(GL_MULTISAMPLE);

注意:关于多重采样,当它被启用的时候,点、线、多边形平滑特性都将被忽略。二者不可兼得。一种策略是:绘制直线的时候,可以考虑关闭多重采样,绘制其他实心几何图形时再打开多重采样。
注意:状态排序:上面的一种策略,导致的状态改变可能会对渲染的性能造成影响,这样需要相同状态的几何图形就可以在一起绘制。这种状态排序是在游戏中常用的提高速度的方法之一。

多重采样缓冲区在默认情况下使用片段的RGB值,并不包括颜色的alpha成分。我们可以通过glEnable来修改这些行为。
GL_SAMPLE_ALPHA_TO_COVERAGE:使用alpha值。
GL_SAMPLE_ALPHA_TO_ON:将alpha值设置为1,并且使用它。
GL_SAMPLE_COVERAGE:使用glSampleCoverage。
当启用GL_SAMPLE_COVERAGE时,glSampleConverage函数允许指定一个特定的值,他是与片段覆盖值进行按位与操作的结果。

void glSampleCoverage(GLclampf value, GLclampf invert);
  1. 基础渲染代码分析

下面列出本章节所涉及到的代码分析
(1)环带渲染模式示例代码分析

#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>    // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <math.h>
#include <GL/glut.h>



GLFrame             viewFrame;
GLFrustum           viewFrustum;
GLTriangleBatch     torusBatch;
GLMatrixStack       modelViewMatix;
GLMatrixStack       projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager     shaderManager;

//面剔除选项,以及深度测试选项
int iCull = 0;
int iDepth = 0;

//右键可以打开相应的菜单对其渲染模式进行选择。
//注意main函数当中的glutCreateMenu回调函数
//就是调用这个函数创建相应的菜单。
//注意这个函数的格式。
//value值为菜单条目的索引值。
void ProcessMenu(int value)
{
    switch (value)
    {
    case 1:
        //打开或者关闭深度测试
        iDepth = !iDepth;
        break;

    case 2:
        //打开或者关闭背面剔除
        iCull = !iCull;
        break;

    case 3:
        //设置,正面反面,全部面渲染。
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        break;

    case 4:
        //设置正面反面,全部线框渲染。
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        break;

    case 5:
        //设置正面背面全部点渲染
        glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
        break;
    }

    glutPostRedisplay();
}


//实际绘制函数
void RenderScene(void)
{
    // 清除屏幕和缓冲区当中数据
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 决定是否开启相关的功能。
    //是否开启表面剔除
    if (iCull)
        glEnable(GL_CULL_FACE);
    else
        glDisable(GL_CULL_FACE);

    // 是否开启深度测试
    if (iDepth)
        glEnable(GL_DEPTH_TEST);
    else
        glDisable(GL_DEPTH_TEST);

    //向矩阵堆栈中压栈
    modelViewMatix.PushMatrix(viewFrame);
    //红色
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    //shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, 
        transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), 
        vRed);

    //绘制相应的批次序列
    torusBatch.Draw();
    //弹栈
    modelViewMatix.PopMatrix();

    //手动刷新
    glutSwapBuffers();
}

// 渲染的基础环境设置
void SetupRC()
{
    // 背景色设置
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    //初始化渲染器
    shaderManager.InitializeStockShaders();
    viewFrame.MoveForward(7.0f);

    // 初始化torusBatch
    //绘制花边环,特殊的函数,使得torusBatch初始化为
    //花边环。
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
    //设置点的大小
    glPointSize(4.0f);
}

//旋转的设置
void SpecialKeys(int key, int x, int y)
{
    if (key == GLUT_KEY_UP)
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);

    if (key == GLUT_KEY_DOWN)
        viewFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);

    if (key == GLUT_KEY_LEFT)
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);

    if (key == GLUT_KEY_RIGHT)
        viewFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);

    // 手动刷新
    glutPostRedisplay();
}


void ChangeSize(int w, int h)
{
    // 避免宽高比计算错误。
    if (h == 0)
        h = 1;

    // 设置视口大小
    glViewport(0, 0, w, h);
    //设置为透视模式
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 100.0f);

    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}



int main(int argc, char* argv[])
{
    //默认的工作目录
    gltSetWorkingDirectory(argv[0]);

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Geometry Test Program");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);

    // 注意其设置菜单的方式
    //注意其为渲染菜单的回调函数。
    //添加相关的项目条
    glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("Toggle depth test", 1);
    glutAddMenuEntry("Toggle cull backface", 2);
    glutAddMenuEntry("Set Fill Mode", 3);
    glutAddMenuEntry("Set Line Mode", 4);
    glutAddMenuEntry("Set Point Mode", 5);
    //绑定触发菜单的按键。
    glutAttachMenu(GLUT_RIGHT_BUTTON);

    //对程序的运行结果进行测试
    //如果初始化错误,那么就返回。
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    //初始化渲染环境。
    SetupRC();

    glutMainLoop();
    return 0;
}

(2)裁剪窗口的渲染示例代码分析

#pragma comment(lib,"GLTools.lib")
#include <GL/glut.h>
//这个程序实例完成了对裁剪的说明
//裁剪仅仅刷新屏幕上发生变化的部分,
//可以提高渲染性能。


//图形渲染函数
void RenderScene(void)
{
    //用蓝色来清除视窗
    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    //设置更小的裁剪框以及更新清除颜色
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    //指定裁切窗口大小
    glScissor(100, 100, 600, 400);
    //开启裁剪测试
    glEnable(GL_SCISSOR_TEST);
    //清除颜色缓冲区当中数据
    glClear(GL_COLOR_BUFFER_BIT);

    // 最后再次绘制一个更小的裁剪窗口
    glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
    //指定裁切窗口大小
    glScissor(200, 200, 400, 200);
    //清除缓冲区当中的数据
    glClear(GL_COLOR_BUFFER_BIT);


    //在最后还原默认模式:裁剪测试关闭
    glDisable(GL_SCISSOR_TEST);

    glutSwapBuffers();
}


///////////////////////////////////////////////////////////
// 对视窗大小的更新
void ChangeSize(int w, int h)
{

    if (h == 0)
        h = 1;


    glViewport(0, 0, w, h);
}


///////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    //申请缓冲区
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL Scissor");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutMainLoop();

    return 0;
}

(3)混合代码示例分析

#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>    // OpenGL toolkit
#include <GLShaderManager.h>
#include <GL/glut.h>

//设置相关的渲染批次序列
GLBatch squareBatch;
GLBatch greenBatch;
GLBatch redBatch;
GLBatch blueBatch;
GLBatch blackBatch;
//渲染器管理器
GLShaderManager shaderManager;

//方块大小大小
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize,  blockSize, 0.0f,
-blockSize,  blockSize, 0.0f };

///////////////////////////////////////////////////////////////////////////////
// 渲染环境设置
void SetupRC()
{
    // 设置背景颜色为白色
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    //初始化渲染器管理器
    shaderManager.InitializeStockShaders();

    // 对各种批次渲染进行装载
    squareBatch.Begin(GL_TRIANGLE_FAN, 4);//这里使用三角形Fan形式完成对方形的渲染
    squareBatch.CopyVertexData3f(vVerts);
    squareBatch.End();

    //设置固定的方块。
    GLfloat vBlock[] = { 0.25f, 0.25f, 0.0f,
        0.75f, 0.25f, 0.0f,
        0.75f, 0.75f, 0.0f,
        0.25f, 0.75f, 0.0f };

    greenBatch.Begin(GL_TRIANGLE_FAN, 4);
    greenBatch.CopyVertexData3f(vBlock);
    greenBatch.End();


    GLfloat vBlock2[] = { -0.75f, 0.25f, 0.0f,
        -0.25f, 0.25f, 0.0f,
        -0.25f, 0.75f, 0.0f,
        -0.75f, 0.75f, 0.0f };

    redBatch.Begin(GL_TRIANGLE_FAN, 4);
    redBatch.CopyVertexData3f(vBlock2);
    redBatch.End();


    GLfloat vBlock3[] = { -0.75f, -0.75f, 0.0f,
        -0.25f, -0.75f, 0.0f,
        -0.25f, -0.25f, 0.0f,
        -0.75f, -0.25f, 0.0f };

    blueBatch.Begin(GL_TRIANGLE_FAN, 4);
    blueBatch.CopyVertexData3f(vBlock3);
    blueBatch.End();


    GLfloat vBlock4[] = { 0.25f, -0.75f, 0.0f,
        0.75f, -0.75f, 0.0f,
        0.75f, -0.25f, 0.0f,
        0.25f, -0.25f, 0.0f };

    blackBatch.Begin(GL_TRIANGLE_FAN, 4);
    blackBatch.CopyVertexData3f(vBlock4);
    blackBatch.End();
    //装填完毕
}

// 对按键的设置
void SpecialKeys(int key, int x, int y)
{
    GLfloat stepSize = 0.025f;//设置每一次触发移动的距离。

    //各个点的参考值
    GLfloat blockX = vVerts[0];   // 移动方块左下x值
    GLfloat blockY = vVerts[7];  // 移动方块右上y值。

    if (key == GLUT_KEY_UP)
        blockY += stepSize;

    if (key == GLUT_KEY_DOWN)
        blockY -= stepSize;

    if (key == GLUT_KEY_LEFT)
        blockX -= stepSize;

    if (key == GLUT_KEY_RIGHT)
        blockX += stepSize;

    // 设置碰撞
    if (blockX < -1.0f) blockX = -1.0f;
    if (blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;;
    if (blockY < -1.0f + blockSize * 2)  blockY = -1.0f + blockSize * 2;
    if (blockY > 1.0f) blockY = 1.0f;

    // 对四个点的值进行更新
    vVerts[0] = blockX;
    vVerts[1] = blockY - blockSize * 2;

    vVerts[3] = blockX + blockSize * 2;
    vVerts[4] = blockY - blockSize * 2;

    vVerts[6] = blockX + blockSize * 2;
    vVerts[7] = blockY;

    vVerts[9] = blockX;
    vVerts[10] = blockY;
    //重新对图形进行复制。
    squareBatch.CopyVertexData3f(vVerts);
    //手动刷新
    glutPostRedisplay();
}





///////////////////////////////////////////////////////////////////////////////
// 真正的渲染窗口
void RenderScene(void)
{
    // 清楚缓冲区数据
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };//半透明的红色
    GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };

    //绘制出相应的四个固定图元
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
    greenBatch.Draw();

    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    redBatch.Draw();

    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
    blueBatch.Draw();

    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
    blackBatch.Draw();

    //重点!!!
    //打开混合模式
    glEnable(GL_BLEND);
    //设置对应的混合因子
    //以下函数告诉OPENGL接受源颜色与alpha值相乘。
    //然后把这个结果加上目标函数目标颜色乘以“1减去源颜色的alpha值”
    //S为源颜色alpha值,D为1-源alpha值。
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //渲染器设置对可移动的物体进行渲染
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    squareBatch.Draw();
    glDisable(GL_BLEND);


    // 刷新
    glutSwapBuffers();
}



///////////////////////////////////////////////////////////////////////////////
// 视窗大小调节函数
void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
}

///////////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Move Block with Arrow Keys to see blending");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);



    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        // Problem: glewInit failed, something is seriously wrong.
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();

    glutMainLoop();
    return 0;
}

(4)抗锯齿以及多重采样的示例程序

#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>    // OpenGL toolkit
#include <GLFrustum.h>
#include <GL/glut.h>


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

// 定义这些星星的数量
#define SMALL_STARS     100
#define MEDIUM_STARS     40
#define LARGE_STARS      15
//定义视窗的x,y的大小。
#define SCREEN_X        800
#define SCREEN_Y        600

///
// 就如同之前的程序,对menu进行处理
void ProcessMenu(int value)
{
    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;
    }

    // Trigger a redraw
    glutPostRedisplay();
}


///
// 绘制函数
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();
}


// 渲染环境设置
void SetupRC()
{
    //注意这里利用m3d类当中的特定数据结构来存储相应的点。
    //和相应的二维数组等价
    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 };

    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;   // 循环值

    //注意这个moon的初始化是以三角形fan的方式进行初始化
    //并且设置为34个点。正常应该是32个点。
    //包含一个重复点,还有一个圆心
    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();

    // 背景颜色处理
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}



void ChangeSize(int w, int h)
{

    if (h == 0)
        h = 1;

    glViewport(0, 0, w, h);

    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");

    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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值