以下程序是OpenGL超级宝典中的block例子,我对其做了比较详细的注释。
这个程序里的内容涉及到变换、着色、纹理与混合,这四种技术的组合几乎能生成任何计算机渲染场景……
// Block.cpp
// OpenGL SuperBible, Chapter 1
// Demonstrates an assortment of basic 3D concepts
// Program by Richard S. Wright Jr.
#include <GLTools.h> // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLGeometryTransform.h>
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
/
// An assortment of needed classes
GLShaderManager shaderManager;//声明一个着色器管理器实例
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;//投影矩阵
GLFrame cameraFrame;
GLFrustum viewFrustum;//视锥
GLBatch cubeBatch;//顶点的批次
GLBatch floorBatch;
GLBatch topBlock;
GLBatch frontBlock;
GLBatch leftBlock;
GLGeometryTransform transformPipeline;//几何变换管线
M3DMatrix44f shadowMatrix;//阴影矩阵
// Keep track of effects step
int nStep = 0;
// Lighting data
GLfloat lightAmbient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat lightDiffuse[] = { 0.7f, 0.7f, 0.7f, 1.0f };
GLfloat lightSpecular[] = { 0.9f, 0.9f, 0.9f };
GLfloat vLightPos[] = { -8.0f, 20.0f, 100.0f, 1.0f };
GLuint textures[4];
///
// Make a cube out of a batch of triangles. Texture coordinates and normals
// are also provided.
void MakeCube(GLBatch& cubeBatch)
{
//组建三角形批次,最后一个参数是1,意味着在这个批次中将应用一个纹理,36表示有36个顶点
cubeBatch.Begin(GL_TRIANGLES, 36, 1);
/
// Top of cube
// Normal3f方法向批次中添加了一个表面法线
// MultiTexCoord2f添加了一个纹理坐标,第一个参数是一个整数用来指定纹理层次,另外两个参数表示纹理坐标(比如(1.0f, 1.0f)就是将纹理的右上角映射到此点)
// Vertex3f添加了顶点的位置
// 底面的四方形由两个三角形组成
cubeBatch.Normal3f(0.0f, 1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, 1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, 1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, 1.0f);
// Bottom of cube
cubeBatch.Normal3f(0.0f, -1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, -1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, -1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, -1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, -1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, -1.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, 1.0f);
///
// Left side of cube
cubeBatch.Normal3f(-1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(-1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(-1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(-1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(-1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(-1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, 1.0f);
// Right side of cube
cubeBatch.Normal3f(1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, 1.0f);
cubeBatch.Normal3f(1.0f, 0.0f, 0.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, -1.0f);
// Front and Back
// Front
cubeBatch.Normal3f(0.0f, 0.0f, 1.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, 1.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, 1.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, 1.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, 1.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, 1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, 1.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, 1.0f);
// Back
cubeBatch.Normal3f(0.0f, 0.0f, -1.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, -1.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
cubeBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, -1.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, -1.0f);
cubeBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
cubeBatch.Vertex3f(-1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, -1.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
cubeBatch.Vertex3f(1.0f, 1.0f, -1.0f);
cubeBatch.Normal3f(0.0f, 0.0f, -1.0f);
cubeBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
cubeBatch.Vertex3f(1.0f, -1.0f, -1.0f);
cubeBatch.End();
}
/
// Make the floor, just the verts and texture coordinates, no normals
void MakeFloor(GLBatch& floorBatch)
{
GLfloat x = 5.0f;
GLfloat y = -1.0f;//恰好将三角形放在这个平面上
//顶点v1,v2,v3,v4
//GL_TRIANGLE_FAN
//先v1,v2,v3再v1,v3,v4这样可以形成一个扇形状得图形。
//GL_TRIANGLE_STRIP
//先v1, v2, v3, 再 v3, v2, v4 并且确定这些顶点可以形成某个多边形。
floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);//4个顶点,应用1个纹理
floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(-x, y, x);
floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
floorBatch.Vertex3f(x, y, x);
floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
floorBatch.Vertex3f(x, y, -x);
floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
floorBatch.Vertex3f(-x, y, -x);
floorBatch.End();
}
///
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.
void SetupRC()
{
GLbyte *pBytes;
GLint nWidth, nHeight, nComponents;
GLenum format;
//着色器管理器需要编译和链接它自己的着色器,故对其进行初始化
shaderManager.InitializeStockShaders();
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
glEnable(GL_DEPTH_TEST);
glLineWidth(2.5f);
//OpenGL 会把源颜色和目标颜色各自取出,并乘以一个系数(源颜色乘以的系数称为“源因子”,目标颜色乘以的系数称为“目标因子”),然后相加,这样就得到了新的颜色
//源因子和目标因子是可以通过glBlendFunc函数来进行设置
//GL_SRC_ALPHA:表示使用源颜色的alpha值来作为因子
//GL_ONE_MINUS_SRC_ALPHA:表示用1.0减去源颜色的alpha值来作为因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//GL_LINE_SMOOTH_HINT:指定反走样线段的采样质量。如果应用较大的滤波函数,GL_NICEST在光栅化期间可以生成更多的像素段
//GL_NICEST:选择最高质量选项
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
//设置变换管线以使用两个矩阵堆栈(将它的内部指针设置为指向模型视图矩阵堆栈和投影矩阵堆栈)
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//摄像机前进-15.0f
cameraFrame.MoveForward(-15.0f);
//摄像机上移6.0f
cameraFrame.MoveUp(6.0f);
//m3dDegToRad将角度值转化为弧度值
cameraFrame.RotateLocalX(float(m3dDegToRad(20.0f)));
MakeCube(cubeBatch);
MakeFloor(floorBatch);
// Make top
topBlock.Begin(GL_TRIANGLE_FAN, 4, 1);
topBlock.Normal3f(0.0f, 1.0f, 0.0f);//表面法线
topBlock.MultiTexCoord2f(0, 0.0f, 0.0f);//纹理坐标
topBlock.Vertex3f(-1.0f, 1.0f, 1.0f);//顶点位置
topBlock.Normal3f(0.0f, 1.0f, 0.0f);
topBlock.MultiTexCoord2f(0, 1.0f, 0.0f);
topBlock.Vertex3f(1.0f, 1.0f, 1.0f);
topBlock.Normal3f(0.0f, 1.0f, 0.0f);
topBlock.MultiTexCoord2f(0, 1.0f, 1.0f);
topBlock.Vertex3f(1.0f, 1.0f, -1.0f);
topBlock.Normal3f(0.0f, 1.0f, 0.0f);
topBlock.MultiTexCoord2f(0, 0.0f, 1.0f);
topBlock.Vertex3f(-1.0f, 1.0f, -1.0f);
topBlock.End();
// Make Front
frontBlock.Begin(GL_TRIANGLE_FAN, 4, 1);
frontBlock.Normal3f(0.0f, 0.0f, 1.0f);
frontBlock.MultiTexCoord2f(0, 0.0f, 0.0f);
frontBlock.Vertex3f(-1.0f, -1.0f, 1.0f);
frontBlock.Normal3f(0.0f, 0.0f, 1.0f);
frontBlock.MultiTexCoord2f(0, 1.0f, 0.0f);
frontBlock.Vertex3f(1.0f, -1.0f, 1.0f);
frontBlock.Normal3f(0.0f, 0.0f, 1.0f);
frontBlock.MultiTexCoord2f(0, 1.0f, 1.0f);
frontBlock.Vertex3f(1.0f, 1.0f, 1.0f);
frontBlock.Normal3f(0.0f, 0.0f, 1.0f);
frontBlock.MultiTexCoord2f(0, 0.0f, 1.0f);
frontBlock.Vertex3f(-1.0f, 1.0f, 1.0f);
frontBlock.End();
// Make left
leftBlock.Begin(GL_TRIANGLE_FAN, 4, 1);
leftBlock.Normal3f(-1.0f, 0.0f, 0.0f);
leftBlock.MultiTexCoord2f(0, 0.0f, 0.0f);
leftBlock.Vertex3f(-1.0f, -1.0f, -1.0f);
leftBlock.Normal3f(-1.0f, 0.0f, 0.0f);
leftBlock.MultiTexCoord2f(0, 1.0f, 0.0f);
leftBlock.Vertex3f(-1.0f, -1.0f, 1.0f);
leftBlock.Normal3f(-1.0f, 0.0f, 0.0f);
leftBlock.MultiTexCoord2f(0, 1.0f, 1.0f);
leftBlock.Vertex3f(-1.0f, 1.0f, 1.0f);
leftBlock.Normal3f(-1.0f, 0.0f, 0.0f);
leftBlock.MultiTexCoord2f(0, 0.0f, 1.0f);
leftBlock.Vertex3f(-1.0f, 1.0f, -1.0f);
leftBlock.End();
// Create shadow projection matrix
// 构造投影平面
GLfloat floorPlane[] = { 0.0f, 1.0f, 0.0f, 1.0f};
//shadowMatrix是要返回的一个变换矩阵,用当前的模型视图矩阵乘以这个矩阵,随后的所有被绘制的物体都会被压平到这个投影平面上
//floorPlane投影平面
//vLightPos光源位置
m3dMakePlanarShadowMatrix(shadowMatrix, floorPlane, vLightPos);
// Load up four textures----glGenTextures函数根据纹理参数返回n个纹理索引
glGenTextures(4, textures);
// Wood floor
pBytes = gltReadTGABits("floor.tga", &nWidth, &nHeight, &nComponents, &format);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//根据指定的参数,生成一个2D纹理(Texture)
//void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data)
//target变量用来指定一维、二维和三维的纹理贴图
//level参数指定了这些函数所加载的mip贴图层次。对于非mip贴图的纹理,总是可以把这个参数设置为0
//internalformat参数会告诉OpenGL我们希望在每个纹理单元中储存多少颜色成分
//width、height指定了被加载纹理的宽度和高度,如果是三维则还有深度。这些值必须是2的整数次方
//border参数允许为纹理贴图指定一个边界宽度。目前可以把这个值设置为0
//最后3个参数format、type和data与用于把图像数据放入颜色缓冲区的glDrawPixels函数的对应参数相同
//format像素数据的颜色格式,必须和internalformatt取值必须相同
//type指定像素数据的数据类型
//data指定内存中指向图像数据的指针
glTexImage2D(GL_TEXTURE_2D,0,nComponents,nWidth, nHeight, 0,
format, GL_UNSIGNED_BYTE, pBytes);
free(pBytes);
// One of the block faces
pBytes = gltReadTGABits("Block4.tga", &nWidth, &nHeight, &nComponents, &format);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D,0,nComponents,nWidth, nHeight, 0,
format, GL_UNSIGNED_BYTE, pBytes);
free(pBytes);
// Another block face
pBytes = gltReadTGABits("block5.tga", &nWidth, &nHeight, &nComponents, &format);
glBindTexture(GL_TEXTURE_2D, textures[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D,0,nComponents,nWidth, nHeight, 0,
format, GL_UNSIGNED_BYTE, pBytes);
free(pBytes);
// Yet another block face
pBytes = gltReadTGABits("block6.tga", &nWidth, &nHeight, &nComponents, &format);
glBindTexture(GL_TEXTURE_2D, textures[3]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D,0,nComponents,nWidth, nHeight, 0,
format, GL_UNSIGNED_BYTE, pBytes);
free(pBytes);
}
///
// Render the block
void RenderBlock(void)
{
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f};
GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
switch(nStep)
{
// Wire frame(线框)
case 0:
//打开混合功能
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
//一组表示红色的浮点数传递到存储着色器,着色器使用指定的颜色以默认的笛卡尔坐标系在屏幕上渲染几何图形
//GLT_SHADER_IDENTITY 单位着色器
//GLT_SHADER_FLAT 平面着色器
//GLT_SHADER_SHADED 上色着色器
//GLT_SHADER_DEFAULT_LIGHT 默认光源着色器
//GLT_SHADER_POINT_LIGHT_DIFF 点光源着色器
//GLT_SHADER_TEXTURE_REPLACE 纹理替换着色器
//GLT_SHADER_TEXTURE_MODULATE 纹理调整着色器
//GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF 纹理光源着色器
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
//void glPolygonMode(GLenum face,GLenum mode)用于控制多边形的显示方式
//GL_FRONT_AND_BACK表示显示模式将适用于物体的所有面
//GL_POINT表示只显示顶点,多边形用点显示;GL_LINE表示显示线段,多边形用轮廓显示;GL_FILL表示显示面,多边形采用填充形式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_CULL_FACE);//关闭剔除操作效果
// Draw the cube
cubeBatch.Draw();
break;
// Wire frame, but not the back side... we also want the block to be in the stencil buffer
case 1:
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
// Draw solid block(即用到填充) in stencil buffer(模板缓冲区)
// Back face culling prevents the back sides from showing through
// The stencil pattern is used to mask when we draw the floor under it
// to keep it from showing through.
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//开启模板测试
glEnable(GL_STENCIL_TEST);
//模板是这样的一种机制,他用来控制深度在模板其后的物体,在模板区域的某个位置是否被显示
//void glStencilFunc(
// GLenum func,
// GLint ref, //参考值
// GLuint mask //掩码 通常为1
// );
//GL_NEVER 从不通过模板测试
//GL_ALWAYS 总是通过模板测试
//GL_LESS 只有参考值<(模板缓存区的值&mask)时才通过
//GL_LEQUAL 只有参考值<=(模板缓存区的值&mask)时才通过
//GL_EQUAL 只有参考值=(模板缓存区的值&mask)时才通过
//GL_GEQUAL 只有参考值>=(模板缓存区的值&mask)时才通过
//GL_GREATER 只有参考值>(模板缓存区的值&mask)时才通过
//GL_NOTEQUAL 只有参考值!=(模板缓存区的值&mask)时才通过
glStencilFunc(GL_NEVER, 0, 0);
//void glStencilOp(
// GLenum fail, //模板测试失败时的动作
// GLenum zfail, //深度测试失败时的动作
// GLenum zpass //模板测试和深度测试都通过时的动作
// );
//GL_KEEP 保持当前的模板缓存区值
//GL_ZERO 把当前的模板缓存区值设为0
//GL_REPLACE 用glStencilFunc函数所指定的参考值替换模板参数值
//GL_INCR 增加当前的模板缓存区值,但限制在允许的范围内
//GL_DECR 减少当前的模板缓存区值,但限制在允许的范围内
//GL_INVERT 将当前的模板缓存区值进行逐位的翻转
glStencilOp(GL_INCR, GL_INCR, GL_INCR);
cubeBatch.Draw();//指示将几何图形提交到着色器
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);//无论测试通过与否深度缓冲区的值都不会被改变
//关闭模板测试
glDisable(GL_STENCIL_TEST);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Draw the front side cube
cubeBatch.Draw();
break;
// Solid(纯色填充)
case 2:
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
// Draw the cube
cubeBatch.Draw();
break;
// Lit
case 3:
//GLT_SHADER_POINT_LIGHT_DIFF 点光源着色器
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, modelViewMatrix.GetMatrix(),
projectionMatrix.GetMatrix(), vLightPos, vRed);
// Draw the cube
cubeBatch.Draw();
break;
// Textured & Lit
case 4:
case 5:
default:
glBindTexture(GL_TEXTURE_2D, textures[2]);
//GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF 纹理光源着色器
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, modelViewMatrix.GetMatrix(),
projectionMatrix.GetMatrix(), vLightPos, vWhite, 0);
glBindTexture(GL_TEXTURE_2D, textures[1]);
topBlock.Draw();
glBindTexture(GL_TEXTURE_2D, textures[2]);
frontBlock.Draw();
glBindTexture(GL_TEXTURE_2D, textures[3]);
leftBlock.Draw();
break;
}
// Put everything back
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//控制多边形以填充的方式显示
glEnable(GL_CULL_FACE);//打开剔除操作
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_STENCIL_TEST);
}
///
// Render the floor
void RenderFloor(void)
{
GLfloat vBrown [] = { 0.55f, 0.292f, 0.09f, 1.0f};
GLfloat vFloor[] = { 1.0f, 1.0f, 1.0f, 0.6f };
switch(nStep)
{
// Wire frame
case 0:
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);//线段的平滑处理
//GLT_SHADER_FLAT 平面着色器
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBrown);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_CULL_FACE);//关闭剔除操作
break;
// Wire frame, but not the back side.. and only where stencil == 0
case 1:
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_STENCIL_TEST);//开启模板测试
glStencilFunc(GL_EQUAL, 0, 0xff);//GL_EQUAL 只有参考值=(模板缓存区的值&mask)时才通过,参考RenderBlock中的注释
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBrown);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
// Solid
case 2:
case 3:
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBrown);
break;
// Textured
case 4:
case 5:
default:
glBindTexture(GL_TEXTURE_2D, textures[0]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vFloor, 0);
break;
}
// Draw the floor
floorBatch.Draw();
// Put everything back
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_STENCIL_TEST);
}
///
// Called to draw scene
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);
// Reflection step... draw cube upside down, the floor
// blended on top of it
// 平面与平面下方正方体的混合
if(nStep == 5) {
glDisable(GL_CULL_FACE);
modelViewMatrix.PushMatrix();
//Scale函数表示模型在各轴上是如何进行缩放的,此时表示x和z不变,y变为原来相反的方向
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
//向y轴的正方向移动2.0f(由于y坐标轴变为原来相反的方向)
modelViewMatrix.Translate(0.0f, 2.0f, 0.0f);
//35.0f表示旋转的角度,(0.0f, 1.0f, 0.0f)表示转轴
modelViewMatrix.Rotate(35.0f, 0.0f, 1.0f, 0.0f);
RenderBlock();
modelViewMatrix.PopMatrix();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderFloor();
glDisable(GL_BLEND);
}
modelViewMatrix.PushMatrix();
// Draw normally 画平面上的正方体
modelViewMatrix.Rotate(35.0f, 0.0f, 1.0f, 0.0f);
RenderBlock();
modelViewMatrix.PopMatrix();
// If not the reflection pass, draw floor last
if(nStep != 5)
RenderFloor();
modelViewMatrix.PopMatrix();
// Flush drawing commands
glutSwapBuffers();
}
///
// A normal ASCII key has been pressed.
// In this case, advance the scene when the space bar is pressed
void KeyPressFunc(unsigned char key, int x, int y)
{
if(key == 32)
{
nStep++;
if(nStep > 5)
nStep = 0;
}
// Refresh the Window
glutPostRedisplay();
}
///
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions(尺寸) to set the viewport(视口) and the projection matrix.
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
//创建投影矩阵,并将它载入到投影矩阵堆栈中
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
modelViewMatrix.LoadIdentity();
}
///
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
//设置当前的工作目录,在windows中不必要
gltSetWorkingDirectory(argv[0]);
//传递命令行参数并初始化GLUT库
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);//这里还开启了模板测试
glutInitWindowSize(800, 600);
glutCreateWindow("3D Effects Demo");
//检查确定初始化过程中没有出现任何问题
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutKeyboardFunc(KeyPressFunc);
glutDisplayFunc(RenderScene);
SetupRC();
glutMainLoop();
glDeleteTextures(4,textures);
return 0;
}
运行结果: