最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

opengl教程

旗下网站admin41浏览0评论

opengl教程

opengl教程

ppt2003官方下载免费完整版-怎么截取视频片段

2023年4月6日发(作者:cs6中文版下载)

Qt5OpenGL教程系列1:基础渲染

⽂章⽬录

OpenGLBuffer

OpenGL中的QOpenGLBuffer对象有点像GPU上动态内存的唯⼀ID。这样理解有点困难,但是对于那些不熟悉的⼈,可以将它们近似为

GPU动态内存。我们可以给GPU提供有关如何使⽤内存的提⽰,并且根据我们的选择,它会更改信息的访问位置和访问效率。

Qt5提供了⼀个帮助器类,该类封装了提供OpenGL缓冲区的所有功能,称为QOpenGLBuffer。

这些缓冲区不会在CPU端动态分配(通过new/delete),它们在内部由OpenGL返回给我们的整数id表⽰。因此,QOpenGLBuffers可

以⾃由传递,⽽不会出现效率问题。

但是,当调⽤destroy()时,该缓冲区会变得⽆效,并且之后不应在该点之后使⽤。

QOpenGLVertexArrayObject

⼀遍⼜⼀遍地为对象绑定和取消绑定OpenGL缓冲区会变得很⿇烦。因此,引⼊了QOpenGLVertexArrayObjects(VAO)。顶点数组对

象只是存储在GPU上的对象,该对象跟踪所有缓冲区并绑定与绘图调⽤关联的信息。

这只是减少代码重复的另⼀种⽅法。它⼏乎是⼀种便利,它可能带来也可能不会带来速度上的好处。但是,我们希望以创建美观且易于理解

的OpenGL代码为⽬标。我们将在初始化时绑定信息,然后允许“顶点数组对象”(VAO)为我们记住我们的绑定信息。

典型的使⽤模式是:

对于每个视觉对象

绑定顶点数组对象(VAO)

设置顶点状态,绑定属性等。

取消绑定顶点数组对象(VAO)

然后,我们不再渲染时为每个对象再次绑定所有属性信息,我们可以

对于每个视觉对象

绑定顶点数组对象(VAO)

使⽤glDraw*()函数绘制对象。

取消绑定顶点数组对象(VAO)

QOpenGLShaderProgram

这确实是本教程的核⼼。通常,对于⾸次使⽤OpenGL的⽤户⽽⾔,着⾊器编译有些棘⼿。但是,Qt5提供了功能的

QOpenGLShaderProgram类抽象,使我们的编程更加轻松。此类可以采⽤源字符串,QOpenGLShader类型或⽂件路径。

着⾊器程序(shaderprogram,如果您不熟悉它们的话)是在GPU上运⾏以处理数据的⼀些代码。通常,我们从CPU端获取数据,该数据

将位置信息与⼀些属性信息配对,这就是着⾊器程序将处理的数据。保留位置和属性信息的结构通常称为“顶点”(Vertex)。

简单的着⾊器管道仅涉及单遍和两种着⾊器类型,可以概括如下:

着⾊器有很多种,但是现在我们仅使⽤如上所述的“顶点着⾊器”和“⽚段着⾊器”。

顶点着⾊器(VertexShader)

获取输⼊信息(通常以顶点信息的形式)并处理该信息以找到GPU必须在其间绘制和插值的最终位置。插值将由“顶点着⾊

器”和“⽚段着⾊器”之间的设备⾃动处理。我们将使⽤的顶点信息是:位置和颜⾊。

⽚段着⾊器(FragmentShader)

从“顶点着⾊器”获取插值结果,并将计算结果输出到某处。现在,这听起来似乎很神秘,但是FragmentShader的基本情况是

输出到后台缓冲区,因此我们可以调⽤特定于系统的SwapBuffer()命令使其可见。

基本渲染

1.创建⼀个Vertex类(以简化操作)。

由于顶点信息(组成⼀个⼏何图形的信息)是⽤户定义的,因此Qt不会提供现成的QVertex类。为了简化问题,我们将创建⼀个类作为顶点

信息

我们将创建⼀个名为vertex.h的新头⽂件,并将以下代码放⼊。

#ifndefVERTEX_H

#defineVERTEX_H

#include

classVertex

{

public:

//Constructors

Q_DECL_CONSTEXPRVertex();

Q_DECL_CONSTEXPRexplicitVertex(constQVector3D&position);

Q_DECL_CONSTEXPRVertex(constQVector3D&position,constQVector3D&color);

//Accessors/Mutators

Q_DECL_CONSTEXPRconstQVector3D&position()const;

Q_DECL_CONSTEXPRconstQVector3D&color()const;

voidsetPosition(constQVector3D&position);

voidsetColor(constQVector3D&color);

//OpenGLHelpers

staticconstintPositionTupleSize=3;

staticconstintColorTupleSize=3;

staticQ_DECL_CONSTEXPRintpositionOffset();

staticQ_DECL_CONSTEXPRintcolorOffset();

staticQ_DECL_CONSTEXPRintstride();

private:

QVector3Dm_position;

QVector3Dm_color;

};

/*******************************************************************************

*InlineImplementation

******************************************************************************/

//Note:Q_MOVABLE_TYPEmeansitcanbememcpy'd.

Q_DECLARE_TYPEINFO(Vertex,Q_MOVABLE_TYPE);

//Constructors

Q_DECL_CONSTEXPRinlineVertex::Vertex(){}

Q_DECL_CONSTEXPRinlineVertex::Vertex(constQVector3D&position):m_position(position){}

Q_DECL_CONSTEXPRinlineVertex::Vertex(constQVector3D&position,constQVector3D&color):m_position(position),m_color(color){}

//Accessors/Mutators

Q_DECL_CONSTEXPRinlineconstQVector3D&Vertex::position()const{returnm_position;}

Q_DECL_CONSTEXPRinlineconstQVector3D&Vertex::color()const{returnm_color;}

voidinlineVertex::setPosition(constQVector3D&position){m_position=position;}

voidinlineVertex::setColor(constQVector3D&color){m_color=color;}

//OpenGLHelpers

Q_DECL_CONSTEXPRinlineintVertex::positionOffset(){returnoffsetof(Vertex,m_position);}

Q_DECL_CONSTEXPRinlineintVertex::colorOffset(){returnoffsetof(Vertex,m_color);}

Q_DECL_CONSTEXPRinlineintVertex::stride(){returnsizeof(Vertex);}

#endif//VERTEX_H

在进⾏下⼀步之前,让我们讨论⼀下这个Vertex类。实际上,这⾥只有⼀些Qt特定的东西。

Q_DECL_CONSTEXPR

Qt提供的宏,如果编译器⽀持,它将设置为constexpr。如果您不知道这意味着什么,请不必担⼼太多。此处是为了保持完整性,

并且仅加快编译时已知的值。(在这种情况下,我们的应⽤程序确实受益,但是当我们动态加载数据时不会。)

Q_DECLARE_TYPEINFO(Vertex,,Q_MOVABLE_TYPE)

为Qt创建详细的运⾏时类型信息。在这种情况下,好处来⾃Q_MOVABLE_TYPE,这意味着可以通过memcpy()移动整个类

型。

如您所见,我们还将QVector3D类⽤于位置和颜⾊。通常,我这样做是为了减少创建⾃⼰的向量类型的需要。稍后,这可能会很有⽤,尽

管您可以告诉您仅定义哑的Vertex类型就可以。

如果您不熟悉OpenGL或Vertex信息,可能会对*TupleSize,*Offset()和stride()符号感到困惑。

*TupleSize

表⽰该数据的信息集合中存在多少个元素。例如,PositionTupleSize为3:x,y,z。

*Offset()

⽤于访问该数据的结构偏移量。例如,颜⾊必须使⾃⾝偏移1个QVector3D类。因为我们不想考虑填充,所以我们只使⽤

offsetof(structure,member)。

stride()

跨度(stride)就是如果数据保存在连续数组中,任何给定属性将必须移动以获取下⼀个数据位的信息量。步幅通常是

sizeof(Type),但是在这⾥我们将其封装在静态的类函数中,以使代码更简洁。

2.将QOpenGL*类添加到Window类

在此应⽤程序中,我们将在屏幕上绘制⼀些内容。因此,我们将不得不创建和分配⼀些信息。但是,我们仍然做得很少,因此更改将很

⼩。

您需要对window.h进⾏的更改在下⾯突出显⽰:

#ifndefWINDOW_H

#defineWINDOW_H

#include

#include

#include

#include

classQOpenGLShaderProgram;

classWindow:publicQOpenGLWindow,

protectedQOpenGLFunctions

{

Q_OBJECT

//OpenGLEvents

public:

~Window();

voidinitializeGL();

voidresizeGL(intwidth,intheight);

voidpaintGL();

voidteardownGL();

private:

//OpenGLStateInformation

QOpenGLBufferm_vertex;

QOpenGLVertexArrayObjectm_object;

QOpenGLShaderProgram*m_program;

//PrivateHelpers

voidprintVersionInformation();

};

#endif//WINDOW_H

实现部分需要将其分解为⼏个部分,让我来讨论⼀下。

因此,第2节中此点之后的所有内容都将与有关。

第⼀个更改是在的顶部:

#include"window.h"

#include

#include

#include

#include"vertex.h"

//Createacoloredtriangle

staticconstVertexsg_vertexes[]={

Vertex(QVector3D(0.00f,0.75f,1.0f),QVector3D(1.0f,0.0f,0.0f)),

Vertex(QVector3D(0.75f,-0.75f,1.0f),QVector3D(0.0f,1.0f,0.0f)),

Vertex(QVector3D(-0.75f,-0.75f,1.0f),QVector3D(0.0f,0.0f,1.0f))

};

//...

乍⼀看可能有点怪异,但请记住我们所讨论的QOpenGLShaderProgram和Vertex信息。特定的顶点信息数组形成⼀个适合屏幕边界的三

⾓形,每个位置具有⼀个属性(在这种情况下,该属性将被认为是颜⾊,尽管可以代表任何东西)。

因此,我们有⼀些点可以逆时针移动以形成三⾓形:

(0.0f,0.75f,1.0f)->(-0.75f,-0.75f,1.0f)->(0.75f,-0.75f,1.0f)

每个点对应⼀个不同的属性,我们称其为颜⾊:

红⾊->绿⾊->蓝⾊

接下来,我们将编辑initializeGL()函数:

//...

voidWindow::initializeGL()

{

//InitializeOpenGLBackend

initializeOpenGLFunctions();

printVersionInformation();

//Setglobalinformation

glClearColor(0.0f,0.0f,0.0f,1.0f);

//Application-specificinitialization

{

//CreateShader(DonotreleaseuntilVAOiscreated)

m_program=newQOpenGLShaderProgram();

m_program->addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/");

m_program->addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/");

m_program->link();

m_program->bind();

//CreateBuffer(DonotreleaseuntilVAOiscreated)

m_();

m_();

m_gePattern(QOpenGLBuffer::StaticDraw);

m_te(sg_vertexes,sizeof(sg_vertexes));

//CreateVertexArrayObject

m_();

m_();

m_program->enableAttributeArray(0);

m_program->enableAttributeArray(1);

m_program->setAttributeBuffer(0,GL_FLOAT,Vertex::positionOffset(),Vertex::PositionTupleSize,Vertex::stride());

m_program->setAttributeBuffer(1,GL_FLOAT,Vertex::colorOffset(),Vertex::ColorTupleSize,Vertex::stride());

//Release(unbind)all

m_e();

m_e();

m_program->release();

}

}

//...

以上就是我们的⼤部分变化。通常,我们将准备⼤量数据,并准备使⽤glDraw*()进⾏绘制。让我们来谈谈这些部分,

创建着⾊器(Shader)

这是唯⼀通过new动态分配的东西,因为这个对象可能会被当作参数传递.删除实例即可从GPU内存中释放着⾊器。

正如我们所讨论的,顶点着⾊器将采⽤我们的顶点(Vertex)类型,并⽣成插值的⽚段数据。Fragmet着⾊器将从VertexShader

获取⽚段输出,并将最终结果数据输出到某个缓冲区。在我们的例⼦中,结果数据将被简单地绘制到屏幕上。

注意:我们将在本教程的后⾯部分创建着⾊器。

将所有已加载的着⾊器链接在⼀起。理想情况下,我们应该检查此调⽤的返回值,因为它可能会失败。

绑定着⾊器,使其成为当前活动的着⾊器。

创建缓冲区(Buffer)

创建⼀个缓冲区,以便以后进⾏动态分配。

绑定缓冲区,使其成为当前活动缓冲区。

由于我们不会更改将要存⼊Buffer的数据,因此我们将使⽤StaticDraw模式。

*Draw共有三种类型:静态,动态和流(tatic,Dynamic,andStream)。稍后,我们将使⽤这些使⽤模式进⾏更多探索。

分配并初始化信息。

创建顶点数组对象(VertexArrayObject)

创建顶点数组对象(从此处开始为VAO)。

绑定VAO,使其成为当前活动的VAO。

注意:从这⾥到释放/解除绑定VAO的所有内容都与⽤于绘制缓冲区数据的缓冲区信息有关。

启⽤属性(Attribute)0和1。

将属性0设置为位置,并将属性1设置为颜⾊。

这是我们*Offset(),*TupleSize和stride()的辅助函数发挥作⽤的地⽅。如您所见,这⼤⼤简化了我们的代码。

释放(取消绑定)全部

解除绑定的发⽣顺序是正式的。因此,我们将解除绑定VAO,然后缓冲区和着⾊器。

接下来,我们可以更新paintGL()以实际绘制三⾓形:

//...

voidWindow::paintGL()

{

//Clear

glClear(GL_COLOR_BUFFER_BIT);

//Renderusingourshader

m_program->bind();

{

m_();

glDrawArrays(GL_TRIANGLES,0,sizeof(sg_vertexes)/sizeof(sg_vertexes[0]));

m_e();

}

m_program->release();

}

//...

如您所见,这很简单,因为我们使⽤的是VAO。

绑定我们要绘制的着⾊器。

绑定我们要绘制的VAO。

从第0个索引开始绘制⼀个带有3个索引的三⾓形。

解除绑定VAO。

取消绑定着⾊器。

最后,我们需要通过teardownGL()函数发布信息:

//...

voidWindow::teardownGL()

{

//ActuallydestroyourOpenGLinformation

m_y();

m_y();

deletem_program;

}

//...

3.创建我们的着⾊器资源

接下来,我们需要⼀些⽂件才能实际加载到着⾊器程序中。稍后,我们将动态加载⽂件,但现在,我们将它们作为Qt资源烘焙到可执⾏⽂

件中。

因此,创建⼀个Qt资源,我们将开始使⽤(我将资源⽂件命名为)。

之后,我们将从“GLSL”“⽂件和类”模板创建两个着⾊器。⼀个将是⼀个名为的顶点着⾊器,另⼀个将是⼀个名为

的⽚段着⾊器。我们将它们保存在项⽬⽬录中创建的⼦⽬录中。

注意:这两个⽂件都应保存在:

/shaders/simple.{vert|frag}

:=.pro⽂件所在的位置。

因此,如果我的项⽬名为“1_BasicRendering”,并且保存在“C:QtProjects1_BasicRendering”中,那么我将创建⼀个名

为“shaders”的⽂件夹,并保存以下两个⽂件:

“C:QtProjects1_”

“C:QtProjects1_”

然后,我们将通过⾸先创建⼀个空的前缀,然后添加这两个⽂件,将这两个⽂件添加到中。

如果正确完成,您的项⽬布局应如下所⽰:

最后我们所需要做的是编辑我们的着⾊器代码

shaders/:

#version330

layout(location=0)invec3position;

layout(location=1)invec3color;

outvec4vColor;

voidmain()

{

gl_Position=vec4(position,1.0);

vColor=vec4(color,1.0);

}

在⽂件顶部,通常会加⼀个注释,指出您希望该⽂件在哪个版本的着⾊器语⾔上运⾏。这说明着⾊器应在OpenGL3.3上运⾏。着⾊器接

受两个输⼊(位置和颜⾊),并具有⼀个输出:vColor。在着⾊器的源代码中,我们要做的就是通过强制转换将两种vec3类型升级为

vec4。

shaders/:

#version330

invec4vColor;

outvec4fColor;

voidmain()

{

fColor=vColor;

}

⽚段着⾊器更简单,仅仅是将⼊参vColor传给fColor,

在这完成之后执⾏这个程序,我们会看到如下

总结

在本教程中,我们学习了……

为了⽅便起见,该Qt5封装了⼀些OpenGL数据类型。

如何创建⽤于将信息传递到GPU的Vertex类。

QOpenGL*类的怪癖和怪异之处,以及如何代替QOpenGLFunctions*类使⽤它们。

着⾊器管道的更新,以及如何向我们的Qt应⽤程序添加资源。

最后,我们学习了如何在屏幕上渲染三⾓形!

代码可以在上下载

opengl教程

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论