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)环带渲染模式示例代码分析
#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;
}