QT三维图形1

先说一下我们想要做什么,以及这个小的系列会讲些什么。

首先这个系列很小,我觉得大概也就几节罢了,不可能给大家把三维Opengl讲透,所以读者应该是有点基础的。

在做体渲染的时候,我们有时候只需要渲染里面的一部分内容,也就是说我们不需要把整个体空间都渲染出来,这个时候,我们就应该建立一个窗口,里面有一个可以移动的矩形体来调节我们想要渲染的内容,注意要是矩形的。

在我们已有的工程上,建立一个DockWidget。然后再定义一个具体的Opengl类:

class My3DDisplayWidget : public QOpenGLWidget,protected QOpenGLFunctions

同时继承自两个Opengl类,一个是控件,一个是功能。在里面声明这些函数:

	void initializeGL();
	void paintGL();
	void resizeGL(int width, int height);
	void keyPressEvent(QKeyEvent *event);
	void mousePressEvent(QMouseEvent *event);
	void mouseMoveEvent(QMouseEvent *event);
	void mouseReleaseEvent(QMouseEvent *event);

其中前三个是系统自动调用的,用来进行初始化,绘制以及大小改变的时候进行一些修改。

按键事件暂时用不到。我们主要使用鼠标事件。

然后定义私有变量:

private:
	QOpenGLShaderProgram *program;
	QOpenGLBuffer vbo;
	GLfloat xRot, yRot, zRot;
	GLfloat translateX, translateY, translateZ;

这些私有变量第一个是用来设置着色器程序的,第二个是缓冲区,然后是x,y,z轴的旋转角度,以及针对x,y,z方向的平移量。

在构造函数中,我们定义:

My3DDisplayWidget::My3DDisplayWidget(QWidget *parent)
	: QOpenGLWidget(parent)
{
	xRot = 0.0;
	yRot = 0.0;
	zRot = 0.0;
	translateX = 0;
	translateY = 0;
	translateZ = -3.0;
	setMinimumSize(240,240);
	
}

进行了一些数据的初始化工作。

然后开始做Opengl初始化:

void My3DDisplayWidget::initializeGL()
{
	// 为当前环境初始化OpenGL函数
	initializeOpenGLFunctions();
	QSurfaceFormat surfaceFormat;
	surfaceFormat.setSamples(4);//多重采样
	setFormat(surfaceFormat); //setFormat是QOpenGLWidget的函数
							  //glEnable( GL_BLEND );
	glEnable(GL_DEPTH_TEST);
	//glClearColor(255, 25, 15, 255);
	glClearColor(0, 0, 0, 255);
	// 创建顶点着色器
	QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
	const char *vsrc =
		"#version 330                              \n"
		"in vec4 vPosition;                        \n"
		"in vec4 vColor;                           \n"
		"out vec4 color;                           \n"
		"uniform mat4 matrix;                      \n"
		"void main() {                             \n"
		"   color = vColor;                        \n"
		"   gl_Position = matrix * vPosition;      \n"
		"}                                         \n";
	vshader->compileSourceCode(vsrc);
	// 创建片段着色器
	QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
	const char *fsrc =
		"#version 330                               \n"
		"in vec4 color;                             \n"
		"out vec4 fColor;                           \n"
		"void main() {                              \n"
		"   fColor = color;                         \n"
		"}                                          \n";
	fshader->compileSourceCode(fsrc);

	// 创建着色器程序
	program = new QOpenGLShaderProgram;
	program->addShader(vshader);
	program->addShader(fshader);

	program->link();
	program->bind();
}

注意如果你的程序调用一直失败,就一定要在着色器的程序里加上:

"#version 330                              \n"

来强调使用的着色器OpenGL版本。

resizeGL以及按键响应都不添加了,在这里没什么用。

因为鼠标事件和旋转有关,我们待会再讲。先看一下我们定义的立方体:

// 顶点位置
GLfloat vertices[6][4][3] = {
	//{ {-0.8f, 0.8f, 0.8f}, {-0.8f, -0.8f, 0.8f}, {0.8f, -0.8f, 0.8f}, {0.8f, 0.8f, 0.8f} },
	//{ {0.8f, 0.8f, 0.8f}, {0.8f, -0.8f, 0.8f}, {0.8f, -0.8f, -0.8f}, {0.8f, 0.8f, -0.8f} },
	{ { 0.5f, -0.5f, -0.5f },{ 0.5f, 0.5f, -0.5f },{ -0.5f, 0.5f, -0.5f },{ -0.5f, -0.5f, -0.5f } },
	{ { -0.5f, 0.5f, 0.5f },{ -0.5f, -0.5f, 0.5f },{ -0.5f, -0.5f, -0.5f },{ -0.5f, 0.5f, -0.5f } },
	//{ {0.8f, 0.8f, 0.8f}, {0.8f, 0.8f, -0.8f}, {-0.8f, 0.5f, -0.8f}, {-0.8f, 0.8f, 0.8f} },
	{ { 0.5f, -0.5f, 0.5f },{ 0.5f, -0.5f, -0.5f },{ -0.5f, -0.5f, -0.5f },{ -0.5f, -0.5f, 0.5f } }
};
// 顶点颜色
GLfloat colors[6][4][3] = {
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0f } },
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0f } },
};
GLfloat rvs[6][4][3] = {
	{ { -0.4f, 0.4f, 0.4f },{ -0.4f, -0.4f, 0.4f },{ 0.4f, -0.4f, 0.4f },{ 0.4f, 0.4f, 0.4f } },
	{ { 0.4f, 0.4f, 0.4f },{ 0.4f, -0.4f, 0.4f },{ 0.4f, -0.4f, -0.4f },{ 0.4f, 0.4f, -0.4f } },
	{ { -0.4f, 0.4f, -0.4f },{ -0.4f, -0.4f, -0.4f },{ 0.4f, -0.4f, -0.4f },{ 0.4f, 0.4f, -0.4f } },
	{ { -0.4f, 0.4f, 0.4f },{ -0.4f, -0.4f, 0.4f },{ -0.4f, -0.4f, -0.4f },{ -0.4f, 0.4f, -0.4f } },
	{ { 0.4f, 0.4f, 0.4f },{ 0.4f, 0.4f, -0.4f },{ -0.4f, 0.4f, -0.4f },{ -0.4f, 0.4f, 0.4f } },
	{ { 0.4f, -0.4f, 0.4f },{ 0.4f, -0.4f, -0.4f },{ -0.4f, -0.4f, -0.4f },{ -0.4f, -0.4f, 0.4f } }
};
GLfloat vertices2[6][4][3] = {};
GLfloat colors2[6][4][3] = {
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 0.0f, 1.0f, 0.0f },{ 1.0f, 1.0f, 1.0f } },
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
	{ { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } }
};

这里大立方体和内部小立方体的顶点和颜色坐标。注意我们的内部小立方体是可以进行大小的调节的,但是为什么这里还要定义成常量的赋值呢?这样做有一个好处:为了方便再赋值:即我们根据rvs这里面初始值的正负来判断里面的值是vertices的左边界还是右边界。

我们在DockWidget里面定义一个

GLfloat centralRectPos[3] = { 0,0,0 };
GLfloat halfBoundaries[3] = { 0.5,0.5,0.5 };

这个变量的值先赋一个初始值,这两个数组代表了大立方体内部的小立方体的位置和大小。其中上面的代表中心点的位置,我们设置为0,0,0,即中心点,然后下面的代表长度的一半。即总长度是1.0,这样,初始值正好让小立方体和大立方体重合了。

之后我们在OpenGL类里面写一个更新边界的函数:

void updateVetices() {
	for (int i = 0;i<6;i++) {
		for (int j = 0;j<4;j++) {
			if (rvs[i][j][0] < 0) {
				vertices2[i][j][0] = centralRectPos[0] - halfBoundaries[0];
			}
			else {
				vertices2[i][j][0] = centralRectPos[0] + halfBoundaries[0];
			}
			if (rvs[i][j][1] < 0) {
				vertices2[i][j][1] = centralRectPos[1] - halfBoundaries[1];
			}
			else {
				vertices2[i][j][1] = centralRectPos[1] + halfBoundaries[1];
			}
			if (rvs[i][j][2] < 0) {
				vertices2[i][j][2] = centralRectPos[2] - halfBoundaries[2];
			}
			else {
				vertices2[i][j][2] = centralRectPos[2] + halfBoundaries[2];
			}

			
		}
	}
}

它可以根据变化的中心点的量生成新的小立方体各个顶点的数组。

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dezeming

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值