OpenGL画自行车+菜单设置(附源码)

OpenGL大作业是画一个自行车,难度不高,但是代码量还是比较大的,所以放到博客上展示一下,不具备什么技术性。

全部代码放在最后,可以先看源码再看讲解。

0、准备工作

我们首先各种include

之后定义pi。因为这个程序是我之前画的一个贪吃蛇程序改的,所以画布的定义通过定义格子的数量及大小确定的,这里没有改所以就放在这了。

#define pi 3.1415926535897932
//这里是定义画布的大小,按格子划分画布,一个格子50,一行20个格子
#define gridSize 50
#define gridnum 20

然后为了方便我定义了一个点类,虽然也可以用二维数组或者结构体,不过还是习惯了定义成class。为了方便,全部public,大作业而已要什么严谨,因为OpenGL主要都是float类型,所以这里也用的float而不是double,理论上高精度转低精度问题不大,但是不想管了。

class Point
{
public:
	float x;
	float y;
	Point(float x, float y) {
		this->x = x;
		this->y = y;
	}
};

定义一个点A(1,1)的时候可以直接写

Point A=Point(1,1);

1、Bike类的结构

下面就是这次作业的主要内容了

1.0 成员变量

为了方便,我们需要先定义好这个自行车的特征点。车轮位置、车把位置、旋转过的角度等。

    bool Fill = true;					//定义是填充还是线框,true是填充
	double roAngle = 0;					//绘图的初始角度,逐渐改变roAngle可以让图像运动
	Point wheel1 = Point(300, 0);		//前轮中心的位置
	Point wheel2 = Point(-300, 0);		//后轮的中心位置
	Point Pedal = Point(0, 0);			//脚踏板的中心位置
	char mode = 'L';	                //运行速度可选low mid high

1.1 画圆

我搜索发现OpenGL是没有什么画圆的函数的,所以找到了别人的代码,稍微修改了一下。原理就是利用for循环画多边形,其中accuracy是控制圆的精度的。传入参数Point O是圆心坐标,float r是圆的半径。

没有加控制颜色的内容,所以使用时要先用修改颜色的函数,否则就是跟前面的颜色一样,也行。

void DrawCircular(Point O, float r) {
		int accuracy = 72;
		glBegin(GL_POLYGON);
		for (int i = 0; i < accuracy; ++i)
			glVertex2f(O.x + r * cos(2 * pi / accuracy * i), O.y + r * sin(2 * pi / accuracy * i));
		glEnd();
		glFlush();
	}

1.2 旋转点

在实现过程中发现画一个斜着的矩形比较麻烦,要输入四个点。而且自行车车轮的辐条也需要利用旋转才可以实现,所以我定义了一个将点绕另一个点旋转的函数。返回的结果是一个Point类型。

实现的功能就是将点p绕点o旋转angle°,这里用的角度制,会比较方便使用。

Point PointRotate(Point o, Point p, double angle) {
		angle = (angle / 180) * pi;
		float px = p.x - o.x;
		float py = p.y - o.y;
		float tempx = px * cos(angle) - py * sin(angle);
		float tempy = px * sin(angle) + py * cos(angle);
		return Point(o.x + tempx, o.y + tempy);
	}

1.3 绘制斜矩形

OpenGL提供的绘制矩形的函数只能是一个方向的,而自行车绘图里会有很多斜的矩形,所以定义了斜着绘制矩形的函数。

把斜的长方形看成一条线段,那么线段的端点就是p1和p2,width是线宽的一半。

原理就是p1p点在选段上,距离p1点width,然后将这个p1p点绕p1点旋转±90°得到两个点。同样找到p2p点,绕p2点旋转±90°,就可以得到四个点ABCD,最后调用绘制多边形,输入这四个点就可以实现了。

但是最后会出现bug,某条长边的边会出现曲线,原因未知,所以我就画两个三角形,最后看的效果还是一样的。

void DrawLine(Point p1, Point p2, float width) {
		float lineLength = sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
		float x_p1p = p1.x + (p2.x - p1.x) * width / lineLength;
		float y_p1p = p1.y + (p2.y - p1.y) * width / lineLength;
		Point p1p = Point(x_p1p, y_p1p);
		float x_p2p = p2.x + (p1.x - p2.x) * width / lineLength;
		float y_p2p = p2.y + (p1.y - p2.y) * width / lineLength;
		Point p2p = Point(x_p2p, y_p2p);
		Point A = PointRotate(p1, p1p, 90);
		Point B = PointRotate(p1, p1p, -90);
		Point C = PointRotate(p2, p2p, -90);
		Point D = PointRotate(p2, p2p, 90);
		glBegin(GL_POLYGON);
		glVertex2f(D.x, D.y);
		glVertex2f(C.x, C.y);
		glVertex2f(B.x, B.y);
		glEnd();
		glBegin(GL_POLYGON);
		glVertex2f(A.x, A.y);
		glVertex2f(C.x, C.y);
		glVertex2f(B.x, B.y);
		glEnd();
	}

1.4 画车架

首先为了方便,把自行车的几个特征点记下来,车轮wheel1和wheel2,车座底端vertex,车座Seat,车头head,车把Handle,脚踏板旋转中心Pedal。

之后要做的就是调用 绘制斜长方形的函数DrawLine,连接这几个点就行了。

void DrawFrame() {
		Point Seat = Point(-150, 300);
		Point vertex = Point(-125, 250);
		glColor3f(0.0, 1.0, 0.0);
		DrawLine(wheel2, Pedal, 10);
		DrawLine(wheel2, vertex, 10);
		DrawLine(Pedal, Seat, 10);
		DrawLine(Point(Seat.x - 50, Seat.y), Point(Seat.x + 100, Seat.y), 15);
		Point head(200, 250);
		Point Handle(170, 350);
		DrawLine(head, vertex, 10);
		DrawLine(head, Pedal, 10);
		DrawLine(Handle, wheel1, 10);
		DrawLine(Point(Handle.x + 10, Handle.y), Point(Handle.x - 70, Handle.y), 10);
		DrawCircular(wheel1, 20);
		DrawCircular(wheel2, 20);
		DrawCircular(Pedal, 20);
	}

1.5 画脚踏板

设置脚踏板的旋转中心为Point O

圆环用画圆函数,画一个大圆,一个白色的小同心圆盖住即可。

脚踏杆用DrawLine函数。但是因为设计到旋转,所以这个脚踏杆的初始位置一端就是旋转中心O,另一端就是绕O旋转angle°,由于这个角度需要随时间变化,所以这个在类里设计了一个成员变量roAngle记录当前旋转到的角度就可以了。

void DrawPedal(Point O) {
		double angle = (roAngle - 60) * pi / 180;
		DrawCircular(O, 50);
		glColor3f(1.0, 1.0, 1.0);
		DrawCircular(O, 30);
		glColor3f(1.0f, 0.0, 0.0);
		double length = 120;
		Point p3 = Point(O.x + length * cos(angle), O.y + length * sin(angle));
		glColor3f(0.0f, 1.0, 0.0);
		DrawLine(O, p3, 10);
		DrawLine(Point(p3.x - 50, p3.y), Point(p3.x + 50, p3.y), 10);
		DrawCircular(p3, 10);

	}

1.6 滑轮子

和脚踏板没啥区别,还是圆和斜线,还是绕roAngle°,所以直接上代码。

轮子的中心Point O

	void DrawWheel(Point O) {
		glColor3f(1.0f, 0.0, 0.0);
		DrawCircular(O, 200);
		glColor3f(1.0, 1.0, 1.0);
		DrawCircular(O, 180);
		glColor3f(1.0, 0.0, 0.0);
		glBegin(GL_POLYGON);               
		float weidth = 10;
		float length = 200;
		Point p1 = Point(-1 * weidth + O.x, -1 * length + O.y);
		Point p2 = Point(weidth + O.x, -1 * length + O.y);
		Point p3 = Point(weidth + O.x, O.y);
		Point p4 = Point(-1 * weidth + O.x, O.y);
		double angle = roAngle;
		for (int i = 0; i < 6; i++) {
			Point p5 = PointRotate(O, p1, angle);
			Point p6 = PointRotate(O, p2, angle);
			Point p7 = PointRotate(O, p3, angle);
			Point p8 = PointRotate(O, p4, angle);
			glBegin(GL_POLYGON);
			glVertex2f(p5.x, p5.y);
			glVertex2f(p6.x, p6.y);
			glVertex2f(p7.x, p7.y);
			glVertex2f(p8.x, p8.y);
			glEnd();
			angle = angle + 60;
		}
	}

1.7 画自行车

画元素的函数都编完了,那剩下的就是调用就行了。开始前先clear清除一下画布。

由于有要求说可选填充或者线框,所以做一个判断,是否Fill,决定使用GL_FILL还是GL_LINE。其他的注意遮挡关系,先后画图就好。

最后glFlush刷新到画布上,清空缓存。

    void BikeDisplay() {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		if (Fill)
		{
			glPolygonMode(GL_FRONT, GL_FILL);
			glPolygonMode(GL_BACK, GL_FILL);
		}
		else {
			glPolygonMode(GL_FRONT, GL_LINE);
			glPolygonMode(GL_BACK, GL_LINE);
		}
		glFrontFace(GL_CW);
		DrawWheel(wheel1);
		DrawWheel(wheel2);
		DrawPedal(Pedal);
		DrawFrame();
		glFlush();
		glutSwapBuffers();
	}

1.8 旋转函数

很简单就是让旋转过的角度roAngle增加就行,不过需要根据运行速度低中高,分别设置增量。直接用Switch分支结构就行。

    void Rotate() {
		switch (mode)
		{
		case 'L': {roAngle = roAngle - 5; break; }
		case 'M': {roAngle = roAngle - 10; break; }
		case 'H': {roAngle = roAngle - 25; break; }
		default:
			break;
		}
	}

2、子菜单定义

下面的代码一次添加到主函数里就行

先定义子菜单1,速度菜单

glutCreateMenu(speed_menu);是调用speed_menu函数,

传入的参数就是glutAddMenuEntry("低速", 2);中的这个2。每个标签分别对应一个传入参数。

所以点击子菜单中的"低速",相当于运行speed_menu(2)。

	int sub_menu1 = glutCreateMenu(speed_menu);
	glutAddMenuEntry("低速", 2);
	glutAddMenuEntry("中速", 3);
	glutAddMenuEntry("高速", 4);

定义子菜单2,线框、填充

	int sub_menu2 = glutCreateMenu(mode_menu);
	glutAddMenuEntry("填充", 5);
	glutAddMenuEntry("线框", 6);

定义主菜单

	//定义主菜单,并将前面的两个子菜单填入
	glutCreateMenu(main_menu);
	glutAddSubMenu("速度", sub_menu1);
	glutAddSubMenu("模式", sub_menu2);

	//设置鼠标右键为开启菜单的开关
	glutAttachMenu(GLUT_RIGHT_BUTTON);

回调函数

写在main前面

void main_menu(int id)
{
}

void speed_menu(int id) {
	switch (id)
	{
	case 2: bike.mode = 'L';
		break;
	case 3: bike.mode = 'M';
		break;
	case 4: bike.mode = 'H';
		break;
	}
}


void mode_menu(int id) {
	switch (id)
	{
	case 5:bike.Fill = true;
		break;
	case 6:bike.Fill = false;
		break;
	}
}

3、OpenGL要求使用的函数

初始化函数

确定初始化画布的颜色、大小、窗口位置、显示范围。照抄就行

void init() {
	glClearColor(1.0, 1.0, 1.0, 1.0);
	glColor3f(1.0f, 0.0f, 0.0f);           	
	gluOrtho2D(0.0, (gridnum + 2) * gridSize / 2, 0.0, (gridnum + 2) * gridSize / 2);
}

改变窗口尺寸时的函数

void changSize(GLint w, GLint h) {
	GLfloat ratio;
	GLfloat coordinatesize = 1000.0f;
	if ((w == 0) || (h == 0))
		return;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	ratio = (GLfloat)w / (GLfloat)h;
	if (w < h)
		glOrtho(-coordinatesize, coordinatesize, -coordinatesize / ratio, coordinatesize / ratio, -coordinatesize, coordinatesize);
	else
		glOrtho(-coordinatesize * ratio, coordinatesize * ratio, -coordinatesize, coordinatesize, -coordinatesize, coordinatesize);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

初始化一个自行车对象

Bike bike;

显示函数

void MyDisplay() {
	bike.Rotate();
	bike.BikeDisplay();
}

定时函数

负责100ms之后再次显示,里面嵌套一次定时函数,就可以实现一直运动的效果。

void TimerFunc(int value)
{
	glutPostRedisplay();
	glutTimerFunc(100, TimerFunc, 1);
}

主函数

依次调用前面定义好的函数就行,没说到的代码基本是OpenGL项目都要写的代码。

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);	
	glutInitWindowPosition(200, 50);				
	glutInitWindowSize(gridnum * gridSize, gridnum * gridSize);
	glutCreateWindow("Point");						
	init();											
	glutDisplayFunc(MyDisplay);						
	glutTimerFunc(100, TimerFunc, 1);
	glutReshapeFunc(changSize);	
	int sub_menu1 = glutCreateMenu(speed_menu);
	glutAddMenuEntry("低速", 2);
	glutAddMenuEntry("中速", 3);
	glutAddMenuEntry("高速", 4);
	int sub_menu2 = glutCreateMenu(mode_menu);
	glutAddMenuEntry("填充", 5);
	glutAddMenuEntry("线框", 6);
	glutCreateMenu(main_menu);
	glutAddSubMenu("速度", sub_menu1);
	glutAddSubMenu("模式", sub_menu2);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	glutMainLoop();
	return 0;
}

4、全部代码

//这里的include要配置一下不然找不到glut.h,可以参考其他博客
#include <GL/glut.h>
#include <iostream>
#include <stdlib.h>
#include <thread>
#include <math.h>
using namespace std;

//这里进行了一些宏定义,pi为圆周率已经定义到double的极限了
#define pi 3.1415926535897932
//这里是定义画布的大小,按格子划分画布,一个格子50,一行20个格子
#define gridSize 50
#define gridnum 20

//定义一个点类,方便后续操作,二维数组也行,不过我习惯了定义成类
class Point
{
public:
	float x;
	float y;
	Point(float x, float y) {
		this->x = x;
		this->y = y;
	}
};

//定义画自行车的类
class Bike
{
public:
	bool Fill = true;					//定义是填充还是线框,true是填充
	double roAngle = 0;					//绘图的初始角度,逐渐改变roAngle可以让图像运动
	Point wheel1 = Point(300, 0);		//前轮中心的位置
	Point wheel2 = Point(-300, 0);		//后轮的中心位置
	Point Pedal = Point(0, 0);			//脚踏板的中心位置
	char mode = 'L';					//运动速度,L、M、H分别是低中高速


	//绘图函数,将整个自行车画出来
	void BikeDisplay() {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		if (Fill)
		{
			glPolygonMode(GL_FRONT, GL_FILL);
			glPolygonMode(GL_BACK, GL_FILL);
		}
		else {
			glPolygonMode(GL_FRONT, GL_LINE);
			glPolygonMode(GL_BACK, GL_LINE);
		}
		glFrontFace(GL_CW);
		DrawWheel(wheel1);
		DrawWheel(wheel2);
		DrawPedal(Pedal);
		DrawFrame();
		glFlush();
		glutSwapBuffers();
	}

	//逐渐改变绘制图形的初始角度,让自行车轮及脚踏板旋转的函数
	void Rotate() {
		switch (mode)
		{
		case 'L': {roAngle = roAngle - 5; break; }
		case 'M': {roAngle = roAngle - 10; break; }
		case 'H': {roAngle = roAngle - 25; break; }
		default:
			break;
		}
	}

private:
	//定义一个画圆的函数,圆心点O,半径为r
	void DrawCircular(Point O, float r) {
		int accuracy = 72;
		glBegin(GL_POLYGON);
		for (int i = 0; i < accuracy; ++i)
			glVertex2f(O.x + r * cos(2 * pi / accuracy * i), O.y + r * sin(2 * pi / accuracy * i));
		glEnd();
		glFlush();
	}

	//将P点绕o点旋转angle度
	Point PointRotate(Point o, Point p, double angle) {
		angle = (angle / 180) * pi;
		float px = p.x - o.x;
		float py = p.y - o.y;
		float tempx = px * cos(angle) - py * sin(angle);
		float tempy = px * sin(angle) + py * cos(angle);
		return Point(o.x + tempx, o.y + tempy);
	}

	//画一条“线”,是一个斜着的矩形,短边中心点为p1和p2,长方形的宽度为width
	//直接绘制斜的矩形会出长边变曲线的问题,所以分成两个三角形画
	void DrawLine(Point p1, Point p2, float width) {
		float lineLength = sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
		float x_p1p = p1.x + (p2.x - p1.x) * width / lineLength;
		float y_p1p = p1.y + (p2.y - p1.y) * width / lineLength;
		Point p1p = Point(x_p1p, y_p1p);
		float x_p2p = p2.x + (p1.x - p2.x) * width / lineLength;
		float y_p2p = p2.y + (p1.y - p2.y) * width / lineLength;
		Point p2p = Point(x_p2p, y_p2p);

		Point A = PointRotate(p1, p1p, 90);
		Point B = PointRotate(p1, p1p, -90);
		Point C = PointRotate(p2, p2p, -90);
		Point D = PointRotate(p2, p2p, 90);
		glBegin(GL_POLYGON);
		glVertex2f(D.x, D.y);
		glVertex2f(C.x, C.y);
		glVertex2f(B.x, B.y);
		glEnd();
		glBegin(GL_POLYGON);
		glVertex2f(A.x, A.y);
		glVertex2f(C.x, C.y);
		glVertex2f(B.x, B.y);
		glEnd();

	}

	//利用定义好的DrawLine函数,绘制自行车的车架
	void DrawFrame() {
		Point Seat = Point(-150, 300);
		Point vertex = Point(-125, 250);
		glColor3f(0.0, 1.0, 0.0);
		DrawLine(wheel2, Pedal, 10);
		DrawLine(wheel2, vertex, 10);
		DrawLine(Pedal, Seat, 10);
		DrawLine(Point(Seat.x - 50, Seat.y), Point(Seat.x + 100, Seat.y), 15);
		Point head(200, 250);
		Point Handle(170, 350);
		DrawLine(head, vertex, 10);
		DrawLine(head, Pedal, 10);
		DrawLine(Handle, wheel1, 10);
		DrawLine(Point(Handle.x + 10, Handle.y), Point(Handle.x - 70, Handle.y), 10);
		DrawCircular(wheel1, 20);
		DrawCircular(wheel2, 20);
		DrawCircular(Pedal, 20);
	}

	//利用DrawCircular和DrawLine函数,绘制脚踏板及轴
	void DrawPedal(Point O) {
		double angle = (roAngle - 60) * pi / 180;
		DrawCircular(O, 50);
		glColor3f(1.0, 1.0, 1.0);
		DrawCircular(O, 30);
		glColor3f(1.0f, 0.0, 0.0);
		double length = 120;
		Point p3 = Point(O.x + length * cos(angle), O.y + length * sin(angle));
		glColor3f(0.0f, 1.0, 0.0);
		DrawLine(O, p3, 10);
		DrawLine(Point(p3.x - 50, p3.y), Point(p3.x + 50, p3.y), 10);
		DrawCircular(p3, 10);

	}

	//利用DrawCircular、PointRotate函数,绘制车轮
	void DrawWheel(Point O) {
		glColor3f(1.0f, 0.0, 0.0);
		DrawCircular(O, 200);
		glColor3f(1.0, 1.0, 1.0);
		DrawCircular(O, 180);
		glColor3f(1.0, 0.0, 0.0);
		glBegin(GL_POLYGON);               
		float weidth = 10;
		float length = 200;
		Point p1 = Point(-1 * weidth + O.x, -1 * length + O.y);
		Point p2 = Point(weidth + O.x, -1 * length + O.y);
		Point p3 = Point(weidth + O.x, O.y);
		Point p4 = Point(-1 * weidth + O.x, O.y);
		double angle = roAngle;
		for (int i = 0; i < 6; i++) {
			Point p5 = PointRotate(O, p1, angle);
			Point p6 = PointRotate(O, p2, angle);
			Point p7 = PointRotate(O, p3, angle);
			Point p8 = PointRotate(O, p4, angle);
			glBegin(GL_POLYGON);
			glVertex2f(p5.x, p5.y);
			glVertex2f(p6.x, p6.y);
			glVertex2f(p7.x, p7.y);
			glVertex2f(p8.x, p8.y);
			glEnd();
			angle = angle + 60;
		}
	}
};

//初始化函数
void init() {
	glClearColor(1.0, 1.0, 1.0, 1.0);
	glColor3f(1.0f, 0.0f, 0.0f);           	
	gluOrtho2D(0.0, (gridnum + 2) * gridSize / 2, 0.0, (gridnum + 2) * gridSize / 2);
}

//改变尺寸时的函数
void changSize(GLint w, GLint h) {
	GLfloat ratio;
	GLfloat coordinatesize = 1000.0f;
	if ((w == 0) || (h == 0))
		return;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	ratio = (GLfloat)w / (GLfloat)h;
	if (w < h)
		glOrtho(-coordinatesize, coordinatesize, -coordinatesize / ratio, coordinatesize / ratio, -coordinatesize, coordinatesize);
	else
		glOrtho(-coordinatesize * ratio, coordinatesize * ratio, -coordinatesize, coordinatesize, -coordinatesize, coordinatesize);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

//初始化全局变量bike
Bike bike;

//主函数的display回调函数,旋转车轮并让bike画图
void MyDisplay() {
	bike.Rotate();
	bike.BikeDisplay();
}

//设置定时的回调函数,调用MyDisplay,并再次定时完成循环绘图
void TimerFunc(int value)
{
	glutPostRedisplay();
	glutTimerFunc(100, TimerFunc, 1);
}

//主菜单的回调函数,主菜单没有独立子项,所以什么也不用做,不报错就行
void main_menu(int id)
{
}

//调节速度的子菜单,id:2,3,4分别代表低中高速度
void speed_menu(int id) {
	switch (id)
	{
	case 2: bike.mode = 'L';
		break;
	case 3: bike.mode = 'M';
		break;
	case 4: bike.mode = 'H';
		break;
	}
}


//调节显示模式的子菜单,id:5,6分别代表填充与线框
void mode_menu(int id) {
	switch (id)
	{
	case 5:bike.Fill = true;
		break;
	case 6:bike.Fill = false;
		break;
	}
}


int main(int argc, char** argv) {
	//常规的初始化、定义窗口大小及位置的步骤
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);	
	glutInitWindowPosition(200, 50);				
	glutInitWindowSize(gridnum * gridSize, gridnum * gridSize);
	glutCreateWindow("Point");						
	init();											
	glutDisplayFunc(MyDisplay);						
	glutTimerFunc(100, TimerFunc, 1);
	glutReshapeFunc(changSize);	

	//定义速度子菜单及内容
	int sub_menu1 = glutCreateMenu(speed_menu);
	glutAddMenuEntry("低速", 2);
	glutAddMenuEntry("中速", 3);
	glutAddMenuEntry("高速", 4);

	//定义模式子菜单及内容
	int sub_menu2 = glutCreateMenu(mode_menu);
	glutAddMenuEntry("填充", 5);
	glutAddMenuEntry("线框", 6);

	//定义主菜单,并将前面的两个子菜单填入
	glutCreateMenu(main_menu);
	glutAddSubMenu("速度", sub_menu1);
	glutAddSubMenu("模式", sub_menu2);

	//设置鼠标右键为开启菜单的开关
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	glutMainLoop();
	return 0;
}

  • 21
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
实验一 OpenGL+GLUT开发平台搭建 5 小实验1: 开发环境设置 5 小实验2: 控制窗口位置和大小 6 小实验3:默认的可视化范围 6 小实验4:自定义可视化范围 7 小实验5: 几何对象变形的原因 8 小实验6: 视口坐标系及视口定义 8 小实验7:动态调整长宽比例,保证几何对象不变形 9 实验二 动和交互 10 小实验1: 单缓冲动技术 10 小实验2: 双缓冲动技术 11 小实验3:键盘控制 13 小实验4:鼠标控制【试着单击鼠标左键或者右键,试着按下鼠标左键后再移动】 14 实验三 几何变换、观察变换、三维对象 16 小实验1:二维几何变换 16 小实验2:建模观察(MODELVIEW)矩阵堆栈 17 小实验3:正平行投影1 19 小实验4:正平行投影2 19 小实验5:正平行投影3 20 小实验6:透射投影1 21 小实验6:透射投影2 22 小实验7:三维对象 24 实验四 光照模型和纹理映射 26 小实验1:光照模型1----OpenGL简单光照效果的关键步骤。 26 小实验2:光照模型2----光源位置的问题 28 小实验3:光照模型3----光源位置的问题 31 小实验4:光照模型4----光源位置的问题 33 小实验5:光照模型5----光源位置的问题 35 小实验6:光照模型6----光源位置的问题 38 小实验7:光照模型7----光源位置的动态变化 40 小实验8:光照模型8----光源位置的动态变化 43 小实验9:光照模型9---光源位置的动态变化 45 小实验10:光照模型10---聚光灯效果模拟 48 小实验11:光照模型11---多光源效果模拟 50 小实验12:光照效果和雾效果的结合 53 小实验13:纹理映射初步—掌握OpenGL纹理映射的一般步骤 56 小实验13:纹理映射—纹理坐标的自动生成(基于参数的曲面映射) 59 小实验14:纹理映射—纹理坐标的自动生成(基于参考面距离) 61
要在OpenGL中绘制动态线,你可以使用OpenGL的缓冲区对象和顶点数组对象来实现。以下是一种可以实现动态线的基本方法: 1. 创建一个顶点数组对象(VAO)和一个顶点缓冲区对象(VBO)。 2. 绑定VAO和VBO,并将线的顶点数据传递给VBO。 3. 在渲染循环中,绑定VAO并调用绘制命令来渲染线。 4. 更新线的顶点数据以实现动态效果。 下面是一个简单的示例代码: ```c++ // 初始化OpenGL和GLFW窗口 // ... GLuint vao, vbo; GLfloat lineVertices[] = { // 线的顶点坐标 0.0f, 0.0f, 0.0f, // 起点 1.0f, 1.0f, 0.0f // 终点 }; // 创建VAO和VBO glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); // 绑定VAO和VBO glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); // 将线的顶点数据传递给VBO glBufferData(GL_ARRAY_BUFFER, sizeof(lineVertices), lineVertices, GL_DYNAMIC_DRAW); // 设置顶点属性指针 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0); glEnableVertexAttribArray(0); // 解绑VAO和VBO glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); // 渲染循环 while (!glfwWindowShouldClose(window)) { // 清空屏幕 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // 绑定VAO并绘制线 glBindVertexArray(vao); glDrawArrays(GL_LINES, 0, 2); glBindVertexArray(0); // 更新线的顶点数据,实现动态效果 // ... // 交换缓冲区并处理事件 glfwSwapBuffers(window); glfwPollEvents(); } // 清理资源 glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); // 终止OpenGL和GLFW // ... ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值