OpenGL(六)——创建三维图形

                               OpenGL(六)——创建三维图形

一、知识点

在绘制三维图形前,需要了解下,OpenGL的常见概念,可以打开前两篇文章查看:

OpenGL(二)——OpenGL基础知识点(一)

OpenGL(三)——OpenGL知识点二

如果你看完了,还是没有头绪,不知道绘制的流程。你且记住下面的内容,以后再慢慢消化理解:

1、你要知道从构造模型到最终渲染到屏幕坐标,这其中有6种坐标系。

2、他们的变换过程,是下图这样的:

3、可能有点绕,没关系,至少你记住下面这几个流程:

OpenGL渲染3D物体到屏幕上的过程其实类似我们平时用照相机拍照的过程,这个步骤大致如下:
一、把照相机固定在三脚架并让它对准场景(视图变换)

二、把场景中的物体调整摆放好(模型变换)

三、选择照相机的镜头,并调整放大倍数(投影变换)

四、确定最终照片的大小(视口变换)


其中视图变换必须要在模型变换之前,其它可以在任何时候。

4、变换的概念你可以看下面的图片:

上面的你先记住3中的内容就行,我们就开始我们的3维绘图。

二、绘制3位图形:

1、通过glutWireCube函数绘制:

#include <GLTools.h>
#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <math.h>

//不显示控制台窗口
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

void draw3D_1(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0,0,0);
	glLoadIdentity();

	//1-视图变换
	gluLookAt(6, 0, 2.5, 0, 0, 0, 1, 1, 0);//设置相机位置.
	//前三个参数设置观察者的观察位置,中三个参数设置观察点的位置,后三个参数设置观察者的观察方向
	glLineWidth(2.0f);
	glutWireCube(2.0);
	glFlush();
}

//当窗口初次创建或者改变时会被调用.
void shapeWidget(int w, int h)
{
	glMatrixMode(GL_PROJECTION);//设置当前矩阵为投影矩阵.
	glLoadIdentity();

	//投影变换.三维变二维
	glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 10.0);//透视投影.
	//glOrtho(-1.0, 1.0, -1.0, 1.0, 2.0, 20.0);

	glMatrixMode(GL_MODELVIEW);//设置当前矩阵为模型视图矩阵.

	//视口变换
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}

int main(int argc, char ** argv)
{
	glutInit(&argc, argv); //来初始化GLUT库并同窗口系统对话协商

	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //用来确定所创建窗口的显示模式。本例中的参数GLUT_SINGLE 指定单缓存窗口,\
		这也是缺省模式,对应的模式为GLUT_DOUBLE 双缓存窗口。参数GLUT_RGB指定颜色RGBA模式,这也是缺省模式,\
		对应的模式为GLUT_INDEX 颜色索引模式窗口。

	glutInitWindowPosition(100, 100);

	glutInitWindowSize(500, 500);

	glutInitDisplayMode(GLUT_RGBA);

	glutCreateWindow("3D widget");

	glutDisplayFunc(draw3D_1);//册当前窗口的显示回调函数。当一个窗口的图像层需要重新绘制时,GLUT将调用该窗口的的显示回调函数。在此例中的mydisplay就是显示回调函数,\
		显示回调函数不带任何参数,它负责整个图像层的绘制。我们的大部分工作将集中在这个函数中。

	glutReshapeFunc(shapeWidget);

	glutMainLoop();//进入GLUT事件处理循环。glutMainLoop函数在GLUT程序中最多只能调用一次,它一旦被调用就不再返回,\
		并且调用注册过的回调函数。所以这个函数必须放在注册回调函数的后面,比如glutReshapeFunc, glutDisplayFunc。

	return 0;
}

我们看下运行的效果:

2、通过绘制坐标点绘图:

#include <GLTools.h>
#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <math.h>

//不显示控制台窗口
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

void draw3D_2(void)
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();

	//1-视图变换
	gluLookAt(4, 0, 1.5, 0, 0, 0, 1, 1, 0);//设置相机位置.

	glColor3f(1.0, 1.0, 1.0);
	glBegin(GL_QUADS);

	glNormal3f(-1, 0, 0);//设置点的法向量
	glVertex3f(0.5, 0.5, 0.5);
	glVertex3f(0.5, -0.5, 0.5);
	glVertex3f(0.5, -0.5, -0.5);
	glVertex3f(0.5, 0.5, -0.5);

	//---2---
	glNormal3f(-1, 0, 0);
	glVertex3f(-0.5, 0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(-0.5, 0.5, -0.5);
	//---3---
	glNormal3f(0, 1, 0);
	glVertex3f(0.5, 0.5, 0.5);
	glVertex3f(-0.5, 0.5, 0.5);
	glVertex3f(-0.5, 0.5, -0.5);
	glVertex3f(0.5, 0.5, -0.5);
	//---4---
	glNormal3f(0, -1, 0);
	glVertex3f(0.5, -0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(0.5, -0.5, -0.5);
	//---5---
	glNormal3f(0, 0, 1);
	glVertex3f(0.5, 0.5, 0.5);
	glVertex3f(-0.5, 0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(0.5, -0.5, 0.5);
	//---6---
	glNormal3f(0, 0, -1);
	glVertex3f(0.5, 0.5, 0.5);
	glVertex3f(-0.5, 0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(0.5, -0.5, 0.5);
	glEnd();

	glColor3f(0, 0, 0);
	glLineWidth(2.0f);
	//绘制正方体的边
	glBegin(GL_LINES);
	//---1---
	glVertex3f(0.5, 0.5, 0.5);
	glVertex3f(-0.5, 0.5, 0.5);
	glVertex3f(-0.5, 0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(0.5, -0.5, 0.5);
	glVertex3f(0.5, -0.5, 0.5);
	glVertex3f(0.5, 0.5, 0.5);
	//---2---
	glVertex3f(0.5, 0.5, -0.5);
	glVertex3f(-0.5, 0.5, -0.5);
	glVertex3f(-0.5, 0.5, -0.5);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(0.5, -0.5, -0.5);
	glVertex3f(0.5, -0.5, -0.5);
	glVertex3f(0.5, 0.5, -0.5);
	//---3---
	glVertex3f(0.5, 0.5, 0.5);
	glVertex3f(0.5, -0.5, 0.5);
	glVertex3f(0.5, -0.5, 0.5);
	glVertex3f(0.5, -0.5, -0.5);
	glVertex3f(0.5, -0.5, -0.5);
	glVertex3f(0.5, 0.5, -0.5);
	glVertex3f(0.5, 0.5, -0.5);
	glVertex3f(0.5, 0.5, 0.5);
	//---4---
	glVertex3f(-0.5, 0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(-0.5, -0.5, 0.5);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(-0.5, 0.5, -0.5);
	glVertex3f(-0.5, 0.5, -0.5);
	glVertex3f(-0.5, 0.5, 0.5);
	glEnd();

	glFlush();
}

//当窗口初次创建或者改变时会被调用.
void shapeWidget(int w, int h)
{
	glMatrixMode(GL_PROJECTION);//设置当前矩阵为投影矩阵.
	glLoadIdentity();

	//投影变换.三维变二维
	glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 10.0);//透视投影.
	//glOrtho(-1.0, 1.0, -1.0, 1.0, 2.0, 20.0);

	glMatrixMode(GL_MODELVIEW);//设置当前矩阵为模型视图矩阵.

	//视口变换
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}

int main(int argc, char ** argv)
{
	glutInit(&argc, argv); //来初始化GLUT库并同窗口系统对话协商

	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //用来确定所创建窗口的显示模式。本例中的参数GLUT_SINGLE 指定单缓存窗口,\
		这也是缺省模式,对应的模式为GLUT_DOUBLE 双缓存窗口。参数GLUT_RGB指定颜色RGBA模式,这也是缺省模式,\
		对应的模式为GLUT_INDEX 颜色索引模式窗口。

	glutInitWindowPosition(100, 100);

	glutInitWindowSize(500, 500);

	glutInitDisplayMode(GLUT_RGBA);

	glutCreateWindow("3D widget");

	glutDisplayFunc(draw3D_2);//册当前窗口的显示回调函数。当一个窗口的图像层需要重新绘制时,GLUT将调用该窗口的的显示回调函数。在此例中的mydisplay就是显示回调函数,\
		显示回调函数不带任何参数,它负责整个图像层的绘制。我们的大部分工作将集中在这个函数中。

	glutReshapeFunc(shapeWidget);

	glutMainLoop();//进入GLUT事件处理循环。glutMainLoop函数在GLUT程序中最多只能调用一次,它一旦被调用就不再返回,\
		并且调用注册过的回调函数。所以这个函数必须放在注册回调函数的后面,比如glutReshapeFunc, glutDisplayFunc。

	return 0;
}

我们看下运行效果:

通过上面的代码你可能知道了,绘制图形中各种变换的顺序。

本文原创作者:冯一川([email protected]),未经作者授权同意,请勿转载。如需获取本程序源代码和资源,欢迎发邮件与我联系。

Guess you like

Origin blog.csdn.net/ifeng12358/article/details/105998982