首页 > 代码库 > openGL超级宝典第三章例子——贴花

openGL超级宝典第三章例子——贴花

1、又和上次一样犯了个错误,深度缓冲标识位GL_DEPTH_BUFFER_BIT写成GL_COLOR_BUFFER_BIT。导致图形绘制没有在窗口中出现

2、注释是我的。

3、好消息:code compare插件和工具的使用。之前朋友推荐我使用,一直没有场景。现在知道:svn同文件的不同版本在同一路径下的对比使用smartSVN;不同文件或者不同路径任何版本对比使用code compare工具,比如根据别人的教程写代码或把开源的代码转化为自己的代码这工具很适合。今天就是用这个工具查找到书写错误,这种错误需要用倒校等文字编辑的方式,但是我们是编码设计人员,不应该浪费时间在无谓的事件上。

4、主要的功能时实现贴花绘制和首个3D项目。


#ifdef WIN32

#pragma comment(lib, "freeglut_static.lib")

#endif





#include <GLTools.h>
#include <GLFrustum.h>
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLBatch.h>
//Geometry 几何学
#include <GLGeometryTransform.h>

#include <GLFrame.h>
#include <math.h>

#define FREEGLUT_STATIC
#include <GL/glut.h>

GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame;
GLFrame objectFrame;
GLFrustum viewFrustum;



GLBatch pointBatch;
GLBatch lineBatch;
GLBatch lineStripBatch;
GLBatch lineLoopBatch;
GLBatch triangleBatch;
GLBatch triangleStripBatch;
GLBatch triangleFanBatch;


//变换管线
GLGeometryTransform transformPipeline;



GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };

int nStep = 0;


void SetupRC(void)
{
	//Black background
	glClearColor(0.7f, 0.7f, 0.7f, 1.0f);

	//初始化shader
	shaderManager.InitializeStockShaders();

	glEnable(GL_DEPTH_TEST);

	transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

	cameraFrame.MoveForward(-15.0f);


	//没理解,其实就是美国佛罗里达地形边框。。
	//////////////////////////////////////////////////////////////////////
	// Some points, more or less in the shape of Florida
	GLfloat vCoast[24][3] = { { 2.80, 1.20, 0.0 }, { 2.0, 1.20, 0.0 },
	{ 2.0, 1.08, 0.0 }, { 2.0, 1.08, 0.0 },
	{ 0.0, 0.80, 0.0 }, { -.32, 0.40, 0.0 },
	{ -.48, 0.2, 0.0 }, { -.40, 0.0, 0.0 },
	{ -.60, -.40, 0.0 }, { -.80, -.80, 0.0 },
	{ -.80, -1.4, 0.0 }, { -.40, -1.60, 0.0 },
	{ 0.0, -1.20, 0.0 }, { .2, -.80, 0.0 },
	{ .48, -.40, 0.0 }, { .52, -.20, 0.0 },
	{ .48, .20, 0.0 }, { .80, .40, 0.0 },
	{ 1.20, .80, 0.0 }, { 1.60, .60, 0.0 },
	{ 2.0, .60, 0.0 }, { 2.2, .80, 0.0 },
	{ 2.40, 1.0, 0.0 }, { 2.80, 1.0, 0.0 } };

	//Load point batch
	pointBatch.Begin(GL_POINTS, 24);
	pointBatch.CopyVertexData3f(vCoast);
	pointBatch.End();

	// Load as a bunch聚束 of line segments
	lineBatch.Begin(GL_LINES, 24);
	lineBatch.CopyVertexData3f(vCoast);
	lineBatch.End();

	// Load as a single line segment
	lineStripBatch.Begin(GL_LINE_STRIP, 24);
	lineStripBatch.CopyVertexData3f(vCoast);
	lineStripBatch.End();

	// Single line, connect first and last points
	lineLoopBatch.Begin(GL_LINE_LOOP, 24);
	lineLoopBatch.CopyVertexData3f(vCoast);
	lineLoopBatch.End();

	// For Triangles, we'll make a Pyramid:金字塔,y轴为塔顶。,有个问题,怎么把底部封住?
	GLfloat vPyramid[12][3] = { -2.0f, 0.0f, -2.0f,
		2.0f, 0.0f, -2.0f,
		0.0f, 4.0f, 0.0f,

		2.0f, 0.0f, -2.0f,
		2.0f, 0.0f, 2.0f,
		0.0f, 4.0f, 0.0f,

		2.0f, 0.0f, 2.0f,
		-2.0f, 0.0f, 2.0f,
		0.0f, 4.0f, 0.0f,

		-2.0f, 0.0f, 2.0f,
		-2.0f, 0.0f, -2.0f,
		0.0f, 4.0f, 0.0f };

	triangleBatch.Begin(GL_TRIANGLES, 12);
	triangleBatch.CopyVertexData3f(vPyramid);
	triangleBatch.End();

	
	// For a Triangle fan, just a 6 sided hex. Raise the center up a bit
	GLfloat vPoints[100][3];    // Scratch array, more than we need

	// For triangle strips, a little ring or cylinder segment
	int iCounter = 0;
	GLfloat radius = 3.0f;
	for (GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
	{
		//以z轴为中心,长度为radius,用圆弧滚动0.3f生成间隔点
		GLfloat x = radius * sin(angle);
		GLfloat y = radius * cos(angle);

		//从计算远点再到近点,组成strip环
		// Specify the point and move the Z value up a little	
		vPoints[iCounter][0] = x;
		vPoints[iCounter][1] = y;
		vPoints[iCounter][2] = -0.5;
		iCounter++;

		vPoints[iCounter][0] = x;
		vPoints[iCounter][1] = y;
		vPoints[iCounter][2] = 0.5;
		iCounter++;
	}

	// Close up the loop
	vPoints[iCounter][0] = vPoints[0][0];
	vPoints[iCounter][1] = vPoints[0][1];
	vPoints[iCounter][2] = -0.5;
	iCounter++;

	vPoints[iCounter][0] = vPoints[1][0];
	vPoints[iCounter][1] = vPoints[1][1];
	vPoints[iCounter][2] = 0.5;
	iCounter++;

	// Load the triangle strip
	triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
	triangleStripBatch.CopyVertexData3f(vPoints);
	triangleStripBatch.End();


	
	int nVerts = 0;
	GLfloat r = 3.0f;
	

	for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
		nVerts++;
		vPoints[nVerts][0] = float(cos(angle)) * r;
		vPoints[nVerts][1] = float(sin(angle)) * r;
		vPoints[nVerts][2] = -0.5f;
	}

	// Close the fan
	nVerts++;
	vPoints[nVerts][0] = r;
	vPoints[nVerts][1] = 0;
	vPoints[nVerts][2] = 0.0f;

	// Load it up
	triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
	triangleFanBatch.CopyVertexData3f(vPoints);
	triangleFanBatch.End();

}

//没有使用现场保留,所以后面多了一堆的代码
void DrawWireFramedBatch(GLBatch * pBatch)
{
	//画绿图
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
	pBatch->Draw();

	//绘制黑线贴花
	//Draw black outline
	glPolygonOffset(-1.0f, -1.0f);//shift depth values
	glEnable(GL_POLYGON_OFFSET_LINE);//开启线偏移——用于绘制贴花

	// Draw lines antialiased 抗锯齿属性
	glEnable(GL_LINE_SMOOTH);
	//混合
	glEnable(GL_BLEND);
	//这样子混合会产生什么样的效果 ??不开启混合则会导致黑线没有完全与相邻的已有像素点(即原模型)贴近,出现一些较明显的间隔
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	//Draw black wireframe version of geometry 画黑线
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glLineWidth(2.5f);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
	pBatch->Draw();

	// Put everything back the way we found it
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glDisable(GL_POLYGON_OFFSET_LINE);
	glLineWidth(1.0f);
	glDisable(GL_BLEND);
	glDisable(GL_LINE_SMOOTH);

}

void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	//保存当前场景的信息
	modelViewMatrix.PushMatrix();

	//设置将要使用的状态机

	//设置摄像机,没看懂是怎么设置,当前状态*摄像机,做出什么变化? 待续
	M3DMatrix44f mCamera;
	cameraFrame.GetCameraMatrix(mCamera);
	modelViewMatrix.MultMatrix(mCamera);//摄像机作用于model坐标系

	M3DMatrix44f mObjectFrame;
	objectFrame.GetMatrix(mObjectFrame);
	modelViewMatrix.MultMatrix(mObjectFrame);//旋转的是对象坐标,要作用于模型坐标系

	//Stock 库存

	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);


	switch (nStep) {
	case 0:
		glPointSize(4.0f);
		pointBatch.Draw();
		glPointSize(1.0f);
		break;
	case 1:
		glLineWidth(2.0f);
		lineBatch.Draw();
		glLineWidth(1.0f);
		break;
	case 2:
		glLineWidth(2.0f);
		lineStripBatch.Draw();
		glLineWidth(1.0f);
		break;
	case 3:
		glLineWidth(2.0f);
		lineLoopBatch.Draw();
		glLineWidth(1.0f);
		break;
	case 4:
		DrawWireFramedBatch(&triangleBatch);
		break;
	case 5:
		DrawWireFramedBatch(&triangleStripBatch);
		break;
	case 6:
		DrawWireFramedBatch(&triangleFanBatch);
		break;
	}

	modelViewMatrix.PopMatrix();

	//Flush drawing commands
	glutSwapBuffers();

}



void ChangeSize(int w, int h)
{

	glViewport(0, 0, w, h);
	//当发现绘制的图形看不到,多半是视角或摄像机的远近问题。
	viewFrustum.SetPerspective(35, (float)w / (float)h, 1.0f, 500.0f);

	projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

	modelViewMatrix.LoadIdentity();
}

void KeyPressFunc(unsigned char key, int x, int y)
{
	//32是空格
	if (key == 32)
	{
		++nStep;

		if (nStep>6)
		{
			nStep = 0;
		}
	}


	switch (nStep)
	{
	case 0:
		glutSetWindowTitle("GL_POINTS");
		break;

	case 1:
		glutSetWindowTitle("GL_LINES");
		break;

	case 2:
		glutSetWindowTitle("GL_LINE_STRIPS");
		break;

	case 3:
		glutSetWindowTitle("GL_LINE_LOOP");
		break;

	case 4:
		glutSetWindowTitle("GL_TRIANGLES");
		break;

	case 5:
		glutSetWindowTitle("GL_TRIANGLE_STRIPS");
		break;
	case 6:
		glutSetWindowTitle("GL_TRIANGLE_FAN");
		break;
	}

	glutPostRedisplay();

}


void SpecialKeys(int key, int x, int y)
{
	if (key == GLUT_KEY_UP)
	{
		objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
	}

	if (key == GLUT_KEY_DOWN)
	{
		objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
	}

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

	if (key == GLUT_KEY_RIGHT)
	{
		objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
	}

	glutPostRedisplay();
}

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("GL_POINTS");
	glutReshapeFunc(ChangeSize);//窗口
	glutKeyboardFunc(KeyPressFunc);//空白键
	glutSpecialFunc(SpecialKeys);//上下左右旋转视角
	glutDisplayFunc(RenderScene);//重绘

	GLenum err = glewInit();
	if (GLEW_OK != err) {
		fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
		return 1;
	}


	SetupRC();

	glutMainLoop();
	return 0;

}


openGL超级宝典第三章例子——贴花