OPENGL学习(四)GLUT三维图像绘制


对于三维目标来说,最主要的就是有坐标变换问题,也就是说有视角问题

1.绘制一个旋转的立方体(普通视角变换)

下面这个程序只是我们看的方向一直在转,不是物体真的在转

#include <gl/glut.h>
#include <iostream>
#include <vector>

//绕每个轴旋转的角度
GLfloat angle_x = 30;
GLfloat angle_y = 30;
GLfloat angle_z = 30;

//点结构体
struct Point {
	GLfloat x, y, z;//位置
	GLfloat r, g, b;//颜色
	Point() = default;
};

//定义一个Point数组为面,每个面包括四个点
using face=std::vector<Point>;
//faces数组中存了所有面
std::vector<face> Faces;

//立方体顶点
GLfloat vertexes[8][3] = { { 1.0, 1.0, 1.0},
						   { 1.0,-1.0, 1.0},
						   {-1.0,-1.0, 1.0},
						   {-1.0, 1.0, 1.0},
						   { 1.0, 1.0,-1.0},
						   { 1.0,-1.0,-1.0},
						   {-1.0,-1.0,-1.0},
						   {-1.0, 1.0,-1.0} };
//立方体六个面
int facesId[6][4] = { { 0, 1, 2, 3},
					{ 4, 5, 6, 7},
					{ 0, 4, 7, 3},
					{ 1, 5, 6, 2},
					{ 0, 4, 5, 1},
					{ 3, 7, 6, 2} };
//六个面分别的颜色
GLfloat facesColor[6][3] = { { 1.0, 1.0, 0.0},
						   { 1.0, 0.0, 1.0},
						   { 0.0, 1.0, 1.0},
						   { 1.0, 0.0, 0.0},
						   { 0.0, 1.0, 0.0},
						   { 0.0, 0.0, 1.0}};


//画一个面
void drawFace(face& points)
{
	glBegin(GL_POLYGON);
		for(auto &pt:points)
		{
			glColor3f(pt.r, pt.g, pt.b);
			glVertex3f(pt.x, pt.y, pt.z);
		}
	glEnd();
}

//当窗口发生变化(如改变大小)时自动调用
void mydisplay()
{
	//清除颜色缓存
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	for (auto &tmp_face : Faces)
	{
		drawFace(tmp_face);
	}
	//修改视角
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glRotatef(angle_x, 1, 0, 0);
	glRotatef(angle_y, 0, 1, 0);
	glRotatef(angle_z, 0, 0, 1);
	//使用DOUBLE_BUFFER后,使用以下代码来交换前后台内存
	glutSwapBuffers();
}

//初始化函数,一般包括视角等
void init()
{
	//全屏颜色变成黑色
	glClearColor(0.0, 0.0, 0.0, 1.0);
	//开启深度,阻挡后面的元素
	glEnable(GL_DEPTH_TEST);
	//改变投影视图,
	glMatrixMode(GL_PROJECTION);
	//opengl是一个状态机,要先清空之前的变换矩阵数据,所以每次视角操作时都要先变为单位矩阵
	glLoadIdentity();
	glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
	//修改视角
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glRotatef(angle_x, 1, 0, 0);
	glRotatef(angle_y, 0, 1, 0);
	glRotatef(angle_z, 0, 0, 1);
}

//初始化六个面数组
void initVertexes()
{
	for (int i = 0; i < 6; i++)
	{
		face tmp_face;
		for (int j = 0; j < 4; j++)
		{
			Point pt;
			pt.x = vertexes[facesId[i][j]][0];
			pt.y = vertexes[facesId[i][j]][1];
			pt.z = vertexes[facesId[i][j]][2];
			pt.r = facesColor[i][0];
			pt.g = facesColor[i][1];
			pt.b = facesColor[i][2];
			tmp_face.emplace_back(pt);
		}
		Faces.push_back(tmp_face);
	}
}

//旋转函数
void rotate(int x)
{
	angle_x += 1;
	if (angle_x >= 360)angle_x = 0;
	//立刻绘制
	glutPostRedisplay();
	//设置新定时器
	glutTimerFunc(10, rotate, 0);
}


int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	//displayMode,增加GLUT_DEPTH使得深度
	glutInitDisplayMode( GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
	//设置窗口名
	glutCreateWindow("Cubic");

	//初始化六个面
	initVertexes();

	//设置定时函数
	glutTimerFunc(10, rotate, 0);
	//绑定display函数
	glutDisplayFunc(mydisplay);
	//设定opengl初始状态
	init();

	//开启窗口循环
	glutMainLoop();
	return 0;
}

在这里插入图片描述

2.绘制一个旋转的立方体(透视视角变化)

透视函数参数图下所示
在这里插入图片描述

#include <gl/glut.h>
#include <iostream>
#include <vector>

//绕每个轴旋转的角度
GLfloat angle_x = 30;
GLfloat angle_y = 30;
GLfloat angle_z = 30;

//点结构体
struct Point {
	GLfloat x, y, z;//位置
	GLfloat r, g, b;//颜色
	Point() = default;
};

//定义一个Point数组为面,每个面包括四个点
using face=std::vector<Point>;
//faces数组中存了所有面
std::vector<face> Faces;

//立方体顶点
GLfloat vertexes[8][3] = { { 1.0, 1.0, 1.0},
						   { 1.0,-1.0, 1.0},
						   {-1.0,-1.0, 1.0},
						   {-1.0, 1.0, 1.0},
						   { 1.0, 1.0,-1.0},
						   { 1.0,-1.0,-1.0},
						   {-1.0,-1.0,-1.0},
						   {-1.0, 1.0,-1.0} };
//立方体六个面
int facesId[6][4] = { { 0, 1, 2, 3},
					{ 4, 5, 6, 7},
					{ 0, 4, 7, 3},
					{ 1, 5, 6, 2},
					{ 0, 4, 5, 1},
					{ 3, 7, 6, 2} };
//六个面分别的颜色
GLfloat facesColor[6][3] = { { 1.0, 1.0, 0.0},
						   { 1.0, 0.0, 1.0},
						   { 0.0, 1.0, 1.0},
						   { 1.0, 0.0, 0.0},
						   { 0.0, 1.0, 0.0},
						   { 0.0, 0.0, 1.0}};


//画一个面
void drawFace(face& points)
{
	glBegin(GL_POLYGON);
		for(auto &pt:points)
		{
			glColor3f(pt.r, pt.g, pt.b);
			glVertex3f(pt.x, pt.y, pt.z);
		}
	glEnd();
	//修改视角
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0, 0, 4, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glRotatef(angle_x, 1, 0, 0);
	glRotatef(angle_y, 0, 1, 0);
	glRotatef(angle_z, 0, 0, 1);
}

//当窗口发生变化(如改变大小)时自动调用
void mydisplay()
{
	//清除颜色缓存
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	for (auto &tmp_face : Faces)
	{
		drawFace(tmp_face);
	}
	//使用DOUBLE_BUFFER后,使用以下代码来交换前后台内存
	glutSwapBuffers();
}


//初始化函数,一般包括视角等
void init()
{
	//全屏颜色变成黑色
	glClearColor(0.0, 0.0, 0.0, 1.0);
	//开启深度,阻挡后面的元素
	glEnable(GL_DEPTH_TEST);
	//改变投影视图,
	glMatrixMode(GL_PROJECTION);
	//opengl是一个状态机,要先清空之前的变换矩阵数据,所以每次视角操作时都要先变为单位矩阵
	glLoadIdentity();
	//使用透视变换,也可以使用gluPerspective函数,参数有所不同
	glFrustum(-2.0, 2.0, -2.0, 2.0, 2.0, 20.0);
	//修改视角
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0, 0, 4, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glRotatef(angle_x, 1, 0, 0);
	glRotatef(angle_y, 0, 1, 0);
	glRotatef(angle_z, 0, 0, 1);
}

//初始化六个面数组
void initVertexes()
{
	for (int i = 0; i < 6; i++)
	{
		face tmp_face;
		for (int j = 0; j < 4; j++)
		{
			Point pt;
			pt.x = vertexes[facesId[i][j]][0];
			pt.y = vertexes[facesId[i][j]][1];
			pt.z = vertexes[facesId[i][j]][2];
			pt.r = facesColor[i][0];
			pt.g = facesColor[i][1];
			pt.b = facesColor[i][2];
			tmp_face.emplace_back(pt);
		}
		Faces.push_back(tmp_face);
	}
}

//旋转函数
void rotate(int x)
{
	angle_x += 1;
	if (angle_x >= 360)angle_x = 0;
	//立刻绘制
	glutPostRedisplay();
	//设置新定时器
	glutTimerFunc(10, rotate, 0);
}


int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	//displayMode,增加GLUT_DEPTH使得深度
	glutInitDisplayMode( GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
	//设置窗口名
	glutCreateWindow("Cubic");

	//初始化六个面
	initVertexes();

	//设置定时函数
	glutTimerFunc(10, rotate, 0);
	//绑定display函数
	glutDisplayFunc(mydisplay);
	//设定opengl初始状态
	init();

	//开启窗口循环
	glutMainLoop();
	return 0;
}

在这里插入图片描述

3.画两个旋转方向不同的立方体

核心在于理解这段代码:
下面这段代码使我们看到 ( − 1.1 , − 1.1 , 0 ) (-1.1,-1.1,0) (1.1,1.1,0)处一个立方体在绕自己的轴旋转。
M1,M2,M3,M4分别代表四个变换矩阵的话, p ′ = M 1 M 2 M 3 M 4 p p'=M_1M_2M_3M_4p p=M1M2M3M4p,越后面的代码越先作用于p,是一个从物体坐标系转移到视角坐标系的过程。M4、M3、M2都可以理解为以物体坐标系为基准的操作(即直接操作物体)M4将其移动到原点,M3将其绕y轴旋转,M2将其移动回去,连起来就是原地旋转。最后M1将它投射到我们的视角坐标系中。

	glLoadIdentity();
	gluLookAt(0, 0, 6, 0, 0, 0.0, 0.0, 1.0, 0.0); //M1
	glTranslatef(-1.1,-1.1,0.0); //M2
	glRotatef(angle_x, 0, 1, 0); //M3
	glTranslatef(1.1, 1.1, 0.0); //M4

完整代码:

#include <gl/glut.h>
#include <iostream>
#include <vector>

//绕每个轴旋转的角度
GLfloat angle_x = 30;
GLfloat angle_y = 30;
GLfloat angle_z = 30;

//点结构体
struct Point {
	GLfloat x, y, z;//位置
	GLfloat r, g, b;//颜色
	Point() = default;
};

//定义一个Point数组为面,每个面包括四个点
using face=std::vector<Point>;
//faces数组中存了所有面
std::vector<face> Cube1;
std::vector<face> Cube2;

//立方体顶点
GLfloat vertexes[8][3] = { { 1.0, 1.0, 1.0},
						   { 1.0,-1.0, 1.0},
						   {-1.0,-1.0, 1.0},
						   {-1.0, 1.0, 1.0},
						   { 1.0, 1.0,-1.0},
						   { 1.0,-1.0,-1.0},
						   {-1.0,-1.0,-1.0},
						   {-1.0, 1.0,-1.0} };
//立方体六个面
int facesId[6][4] = { { 0, 1, 2, 3},
					{ 4, 5, 6, 7},
					{ 0, 4, 7, 3},
					{ 1, 5, 6, 2},
					{ 0, 4, 5, 1},
					{ 3, 7, 6, 2} };
//六个面分别的颜色
GLfloat facesColor[6][3] = { { 1.0, 1.0, 0.0},
						   { 1.0, 0.0, 1.0},
						   { 0.0, 1.0, 1.0},
						   { 1.0, 0.0, 0.0},
						   { 0.0, 1.0, 0.0},
						   { 0.0, 0.0, 1.0}};


//画一个面
void drawFace(face& points)
{
	glBegin(GL_POLYGON);
		for(auto &pt:points)
		{
			glColor3f(pt.r, pt.g, pt.b);
			glVertex3f(pt.x, pt.y, pt.z);
		}
	glEnd();
}

//当窗口发生变化(如改变大小)时自动调用
void mydisplay()
{
	//清除颜色缓存
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//修改视角
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0, 0, 6, 0, 0, 0.0, 0.0, 1.0, 0.0);
	glTranslatef(-1.1,-1.1,0.0);
	glRotatef(angle_x, 0, 1, 0);
	glTranslatef(1.1, 1.1, 0.0);
	for (auto &tmp_face : Cube1)
	{
		drawFace(tmp_face);
	}
	//修改视角
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0, 0, 6, 0, 0, 0.0, 0.0, 1.0, 0.0);
	glTranslatef(1.1, 1.1, 0.0);
	glRotatef(angle_x, 0, -1, 0);
	glTranslatef(-1.1, -1.1, 0.0);
	for (auto& tmp_face : Cube2)
	{
		drawFace(tmp_face);
	}
	//使用DOUBLE_BUFFER后,使用以下代码来交换前后台内存
	glutSwapBuffers();
}


//初始化函数,一般包括视角等
void init()
{
	//全屏颜色变成黑色
	glClearColor(0.0, 0.0, 0.0, 1.0);
	//开启深度,阻挡后面的元素
	glEnable(GL_DEPTH_TEST);
	//改变投影视图,
	glMatrixMode(GL_PROJECTION);
	//opengl是一个状态机,要先清空之前的变换矩阵数据,所以每次视角操作时都要先变为单位矩阵
	glLoadIdentity();
	//使用透视变换,也可以使用gluPerspective函数,参数有所不同
	glFrustum(-2.0, 2.0, -2.0, 2.0, 2.0, 20.0);
}

//初始化六个面数组
void initVertexes()
{
	for (int i = 0; i < 6; i++)
	{
		face tmp_face1;
		face tmp_face2;
		for (int j = 0; j < 4; j++)
		{
			Point pt;
			pt.x = vertexes[facesId[i][j]][0]-1.1;
			pt.y = vertexes[facesId[i][j]][1]-1.1;
			pt.z = vertexes[facesId[i][j]][2];
			pt.r = facesColor[i][0];
			pt.g = facesColor[i][1];
			pt.b = facesColor[i][2];
			tmp_face1.emplace_back(pt);
			pt.x = vertexes[facesId[i][j]][0]+1.1;
			pt.y = vertexes[facesId[i][j]][1]+1.1;
			pt.r = facesColor[i][0];
			pt.g = facesColor[i][1];
			pt.b = facesColor[i][2];
			tmp_face2.emplace_back(pt);
		}
		Cube1.push_back(tmp_face1);
		Cube2.push_back(tmp_face2);
	}
}

//旋转函数
void rotate(int x)
{
	angle_x += 1;
	if (angle_x >= 360)angle_x = 0;
	//立刻绘制
	glutPostRedisplay();
	//设置新定时器
	glutTimerFunc(10, rotate, 0);
}


int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	//displayMode,增加GLUT_DEPTH使得深度
	glutInitDisplayMode( GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
	//设置窗口名
	glutCreateWindow("Cubic");

	//初始化六个面
	initVertexes();

	//设置定时函数
	glutTimerFunc(10, rotate, 0);
	//绑定display函数
	glutDisplayFunc(mydisplay);
	//设定opengl初始状态
	init();

	//开启窗口循环
	glutMainLoop();
	return 0;
}

在这里插入图片描述

  • 9
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: OpenGL是一种图库,可以用来绘制三维图。地绘制是其中的一种应用。 要绘制三维地,可以通过高度图来创建地模型。高度图是一种灰度图像,其中每个像素的颜色值表示了该位置的海拔高度。首先,我们需要将高度图加载到程序中,并进行解析。然后,根据像素的位置和灰度值来确定地的高度。 一种常见的绘制的方法是使用三角网格。将地分割成很多小的三角,并为每个三角指定顶点的坐标和纹理坐标。然后,通过使用适当的纹理映射来为地上色。 绘制文本也是我们常见的需求。OpenGL本身不直接支持绘制文本,但可以通过使用TrueType字体库(TTF)来实现。我们可以将TTF字体加载到程序中,并根据需要创建文本纹理。然后,通过使用纹理映射的方式将文本绘制到我们的场景中。 要同时绘制三维地和文本,我们可以在绘制之前,先绘制文本。我们可以根据需要选择合适的位置和大小,将文本添加到地场景中。将文本转换为纹理并将其绘制到需要的地方。 总结来说,要使用OpenGL绘制三维地和TTF字体,我们需要加载高度图和TTF字体,创建地模型和文本纹理,并使用合适的纹理映射和绘制顺序来完成绘制。这样可以实现将三维地和文本结合在一起的效果。 ### 回答2: OpenGL可以用来绘制三维地和TTF字体。 首先,绘制三维地可以使用高度图和顶点缓冲对象(VBO)来实现。高度图是一个灰度图像,其中每个像素的灰度值表示该位置的高度。通过将高度图映射到一个平面上的网格上,可以创建一个具有凹凸效果的地。在OpenGL中,可以使用纹理来加载和绑定高度图,然后使用VBO来存储地的顶点、法线和纹理坐标等信息。通过使用合适的着色器程序,可以根据顶点的位置和光照计算出地的颜色和阴影效果。 其次,绘制TTF字体可以使用FreeType库来实现。FreeType库是一个广泛使用的字体渲染库,可以加载和渲染TTF字体文件。首先,需要加载和初始化FreeType库,并加载所需的TTF字体文件。然后,使用FreeType库的函数来获取每个字符的位图和字信息。然后,将字符的位图转换为纹理。在OpenGL中,可以使用纹理贴图的方式将字符的纹理应用到一个矩上,并通过适当的着色器程序来渲染和渲染字符。 绘制三维地和TTF字体是OpenGL中复杂和有趣的任务之一。通过充分利用OpenGL的功能和库,可以实现逼真和可交互的三维地和TTF字体渲染效果。这需要深入学习和理解OpenGL的核心概念和技术,并进行相关编程和实践。 ### 回答3: OpenGL是一种开放源代码的图库,可用于绘制2D和3D图。要使用OpenGL绘制三维地和TrueType字体(TTF),我们可以采用以下步骤: 1. 导入所需的库:首先,我们需要导入OpenGL库和相关的扩展库,如GLUTOpenGL实用工具包)。 2. 创建窗口:使用OpenGL函数创建一个窗口来显示我们的地和字体。这可以通过调用glutInit函数和glutCreateWindow函数来完成。 3. 绘制:使用OpenGL的顶点和多边绘制功能,我们可以通过提供地的顶点和法线数据来绘制一个网格。这些数据可以从高度图或其他地数据源中获取。我们可以使用glBegin函数来指定要绘制的图元类型(例如三角、线条),使用glVertex函数来指定顶点的坐标,使用glNormal函数来指定法线的方向。 4. 加载TTF字体:我们可以使用一些库(如FreeType)来加载TTF字体文件,并将其转换为OpenGL支持的格式。这可以通过提取字的轮廓数据,并生成多边网格来完成。 5. 绘制字体:使用OpenGL的多边绘制功能,我们可以通过提供字体的多边数据来绘制字体。这些数据可以从加载的TTF字体中获取。类似于绘制,我们可以使用glBegin函数来指定要绘制的图元类型,使用glVertex函数来指定顶点的坐标。 6. 控制摄像机:为了观察地和字体,我们可以使用OpenGL的摄像机函数来控制视角。这包括设置摄像机位置、目标和上向量,并通过gluLookAt函数将其应用于当前视图矩阵。 7. 更新窗口:使用glutMainLoop函数开始主循环,以更新和显示窗口中的图。这将使OpenGL在需要时调用我们指定的绘制函数。 通过以上步骤,我们可以使用OpenGL绘制三维地并渲染TTF字体。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值