当前位置: 首页 > news >正文

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];
			}

			
		}
	}
}

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

 

 

 

 

相关文章:

  • QT三维图形2
  • QT三维图形3
  • QT三维图形4
  • icache的方面以及使用
  • cmp bne 以及sub指令的详解
  • 关于ARM Cortex a 系列的看门狗定时器
  • C语言之 认识可变参数
  • ARM cortex a 的SDRAM (DDR)
  • C语言 之递归函数
  • C语言 之建立静态链接库
  • ARM的PWM定时器1
  • RTC闹钟的中断处理方法以及程序设计
  • altium designer 制作元器件封装库
  • VTK的Mapper
  • VTK交互系统 1 交互模式入门
  • 时间复杂度分析经典问题——最大子序列和
  • 【技术性】Search知识
  • ComponentOne 2017 V2版本正式发布
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • JAVA 学习IO流
  • Laravel Mix运行时关于es2015报错解决方案
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • LeetCode18.四数之和 JavaScript
  • nodejs:开发并发布一个nodejs包
  • Rancher-k8s加速安装文档
  • select2 取值 遍历 设置默认值
  • ubuntu 下nginx安装 并支持https协议
  • vue-router的history模式发布配置
  • webpack入门学习手记(二)
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 反思总结然后整装待发
  • 复习Javascript专题(四):js中的深浅拷贝
  • 工作中总结前端开发流程--vue项目
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 前端相关框架总和
  • 如何在GitHub上创建个人博客
  • 山寨一个 Promise
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 智能合约开发环境搭建及Hello World合约
  • 做一名精致的JavaScripter 01:JavaScript简介
  • kubernetes资源对象--ingress
  • linux 淘宝开源监控工具tsar
  • 阿里云ACE认证学习知识点梳理
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • !!Dom4j 学习笔记
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #Z2294. 打印树的直径
  • $L^p$ 调和函数恒为零
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (四)Android布局类型(线性布局LinearLayout)
  • (一)Linux+Windows下安装ffmpeg
  • (原創) 物件導向與老子思想 (OO)