[OpenGL]第一章 OpenGL概述

2023-11-10

第一章 OpenGL概述


1.1 什么是OpenGL

OpenGLwikipedia是一种应用程序编程接口(API),它是一种可以对图形硬件设备特性进行访问的软件库。

一个用来渲染图像的OpenGL程序需要执行的主要操作如下:

  1. 从OpenGL的几何图元中设置数据,用于构建形状。
  2. 使用不同的着色器(shader)对输入的图元数据执行计算操作,判断它们的位置、颜色,以及其他渲染属性。
  3. 将输入图元的数学描述转化为与屏幕位置对应的像素片元(fragment)。这一步也称为光栅化(rasterization)。
  4. 最后,针对光栅化过程产生的每个片元,执行片元着色器(fragment shader),从而决定这个片元的最终颜色和位置。
  5. 如果有必要,还需要对每个片元执行一些额外的操作,例如判断片元对应的对象是否可见,或者将片元的颜色与当前屏幕位置的颜色进行融合。

何为光栅化(rasterization)?
将输入图元的数学描述转换为与屏幕位置对应的像素片元,称为光栅化。

1.2 初识OpenGL程序

一些图形学名词:

  1. 几何图元,包括点、线、三角形以及Patch。
  2. 渲染(render),表示计算机从模型创建最终图像的过程。
  3. 着色器(shader),专为图形处理单元(GPU)编译的一种小型程序。
  4. 四种不同的着色阶段(shander stage),其中最常用的包括顶点着色器(vertex shader)以及片元着色器,前者用于处理顶点数据,后者用于处理光栅化后的片元数据。所有OpenGL程序都需要用到这两类着色器。
  5. 帧缓存(framebuffer),像素(pixel),是显示器上最小的可见单元。计算机系统将所有的像素保存到帧缓存当中,后者是有图形硬件设备管理的一块独立内存区域,可以直接映射到最终的显示设备上。

例1.1 第一个OpenGL程序triangles.cpp
代码(坚果云)
在VS 2013上实现,其中包含了红书官网所提供的源文件中的头文件,以及其中的库文件。运行结果如下:
运行结果

1.3 OpenGL语法

本书所使用的GLUT(OpenGL Utility Toolkit)版本为Freeglut,是原始GLUT库的一个新变种。

1.4 OpenGL渲染管线

rendering pipeline,它是一系列数据处理过程,并且将应用程序的数据转换到最终渲染的图像。下图为OpenGL4.3版本的管线。包括:
顶点数据,顶点着色器,细分着色器(细分控制着色器,细分计算着色器),几何着色器,图元设置,剪切,光栅化,片元着色器
RenderingPipeline

1.4.1 准备向OpenGL传输数据

OpenGL需要将所有的数据都保存到缓存对象(buffer object)中。
我们可以使用多种方式创建这样的数据缓存,最常用的是glBufferData()wiki

Buffer Objects are OpenGL Objects that store an array of unformatted memory allocated by the OpenGL context (aka: the GPU). These can be used to store vertex data, pixel data retrieved from images or the framebuffer, and a variety of other things.
--from wiki

1.4.2 将数据传输到OpenGL

当将缓存初始化完毕后,通过调用OpenGL的一个绘制命令来请求渲染几何图元。glDrawArrays()wiki就是一个常用的绘制命令。OpenGL的绘制通常就是将顶点数据传输到OpenGL服务端。

1.4.3 顶点着色

对于绘制命令传输的每个顶点,OpenGL都会调用一个顶点着色器来处理顶点相关的数据。
只是将数据复制并传递到下一个着色阶段,叫做传递着色器(pass-through shader)。
通常来说,一个复杂的应用程序可能包含许多顶点着色器,但在同一时刻只能有一个顶点着色器起作用。

1.4.4 细分着色

顶点着色器处理每个顶点的关联数据之后,如果同时激活了细分着色器,那么它将进一步处理这些数据。(第9章介绍)
细分着色器阶段会用到两个着色器来分别管理Patch数据并产生最终的形状。

1.4.5 几何着色

第10章介绍。

1.4.6 图元装配

图元装配将顶点及相关的集合图元之间组织起来,准备下一步剪切和光栅化操作。

1.4.7 剪切

顶点可能落在视口(viewport)之外,此时与顶点相关的图元会做出改动,以保证相关的像素不会在视口外绘制。剪切(clipping)由OpenGL自动完成。

1.4.8 光栅化

将更新后的图元(primitive)传递到光栅化单元,生成对应的片元(fragment)。我们将一个片元是为一个“候选的像素”。也就是可以放置在帧缓存(framebuffer)中的像素,但是它也可能被最终剔除,不再更新对应的像素位置。之后两个阶段将会执行片元的处理。

1.4.9 片元着色

最后一个可以通过编程控制屏幕上显示颜色的阶段。在Fragment Shader阶段中,我们使用着色器计算片元的最终颜色和它的深度值。

顶点着色器与片元着色器之间的区别:
顶点着色(包括细分和几何着色)决定了一个图元应该位于屏幕的什么位置,而片元着色使用这些信息来决定某个片元的颜色应该是什么。

1.4.10 逐片元的操作

在这个阶段会使用深度测试(depth test,或者通常也称为z-bufffering)和模板测试(stencil test)的方式来决定一个片元是否是可见的。

1.5 第一个程序:深入分析

1.5.1 进入main()函数

int main (int argc, char ** argv)
{
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_RGBA);
    glutInitWindowSize (512, 512);
    glutInitContextVersion (4, 3);                  
    glutInitContextProfile (GLUT_CORE_PROFILE); 
    glutCreateWindow (argv[0]);
    glewExperimental = GL_TRUE;     
    
    if (glewInit ()) {
        cerr << "Unable to initialize GLEW ... exiting..." << endl;
        exit (EXIT_FAILURE);
    }
    
    init ();
    
    glutDisplayFunc (display);
    
    glutMainLoop ();
    

前面的6行使用GLUT(OpenGL Utility Toolkit)初始化和打开了一个渲染用的窗口:

  1. glutInit()负责初始化GLUT库,负责设置其他GLUT例程所必须的数据结构。
  2. glutInitDisplayMode()设置了程序所使用的窗口的类型。在这个例子中只设置了窗口使用的RGBA颜色空间。
  3. glutInitWindowSize()设置所需的窗口大小。
  4. glutInitContextVersion()、glutInitContextProfile设置所需的OpenGL环境(context)的类型。这个例子中使用OpenGL 4.3版本的核心模式(core profile)来创建环境。这个模式确保使用的只是OpenGL的最新特性,否则也可以使用兼容模式,这样自OpenGL 1.0以来的所有特性都可以在程序中使用。
  5. glutCreateWindow(),如果当前的系统环境可以满足glutInitDisplayMode()的显示模式要求,这里就会创建一个窗口(此时会调用计算机窗口系统的接口)。只有GLUT创建了一个窗口之后(其中包含创建创建OpenGL环境的过程),我们才可以使用OpenGL相关的函数。
    接下来会调用glewInit()函数,属于另一个辅助库GLEW(OpenGL Extention Wrangler)。GLEW可以简化获取函数地址的过程,并且包含了可以跨平台使用的其他一些OpenGL编程方法。

到这,完成了使用OpenGL之前的全部设置工作。之后init()函数初始化OpenGL相关的所有数据。在之后完成渲染工作。

  1. glutDisplayFunc(),它设置了一个显示回调(diplay callback),即GLUT在每次更新窗口内容的时候回自动调用该例程。
  2. glutMainLoop(),这是一个无限执行的循环,它会负责一直处理窗口和操作系统的用户输入等操作。(注意:不会执行在glutMainLoop()之后的所有命令。)

1.5.2 OpenGL的初始化过程

void init (void)
{
    glGenVertexArrays (NumVAOs, VAOs);
    glBindVertexArray (VAOs[Triangles]);
    GLfloat vertices[NumVertices][2] = {
        { -0.90, -0.90 },       // Triangle 1
        { 0.85, -0.90 },
        { -0.90, 0.85 },
        { 0.90, -0.85 },        // Triangle 2,
        { 0.90,  0.90 },
        { -0.85, 0.90 }
    };

    glGenBuffers (NumBuffers, Buffers);
    glBindBuffer (GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW);
    ShaderInfo shaders[] = {                            
        { GL_VERTEX_SHADER, "triangles.vert" },
        { GL_FRAGMENT_SHADER, "triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders (shaders); 
    glUseProgram (program);
    glVertexAttribPointer (vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET (0));
    glEnableVertexAttribArray (vPosition);
}

初始化顶点数组对象

  • glGenVertexArrays(NumVAOs, VAOs)分配顶点数组对象(vertext array object)。OpenGL会因此分配一部分(NumVAOs个)顶点数组对象的名称供我们使用,保存到数组VAOs中。

void glGenVertexArrays(GLsizei n​, GLuint *arrays​);
n
Specifies the number of vertex array object names to generate.
arrays
Specifies an array in which the generated vertex array object names are stored.
The names returned in arrays​ are marked as used, for the purposes of glGenVertexArrays only, but they acquire state and type only when they are first bound.

很多OpenGL命令都是glGen的形式,它们负责分配不同类型的OpenGL对象的名称。这里的名称类似C语言中的指针变量,必须分配内存并且用名称引用它之后,名称才有意义。在OpenGL中,这个分配的机制叫做绑定对象(bind an object)。这通过一系列glBind形式的OpenGL函数集合去实现。

  • glBindVertexArray (VAOs[Triangles])创建一个顶点数组对象,并与其名称(VAOs[Triangles])关联起来。

    void glBindVertexArray(GLuint array​);
    array
    Specifies the name of the vertex array to bind.

  • 当我们第一次绑定对象时(例如,第一次用指定的对象名作为参数调用glBind*()),OpenGL内部会分配这个对象所需的内存并且将它作为当前对象,即后继的操作都会作用于这个被绑定的对象。例如,这里的顶点数组对象就会被后面执行的代码所改变。
    有两种情况我们需要绑定一个对象:
  1. 创建对象并初始化它所对应的数据时。
  2. 每次我们准备使用这个对象,而它并不是当前绑定的对象时。
  • (未使用)glDeleteVertexArrays(),当我们完成对顶点数组对象的操作之后,可以调用此函数将它(们)释放。

    void glDeleteVertexArrays(GLsizei n​, const GLuint *arrays​);
    n
    Specifies the number of vertex array objects to be deleted.
    arrays
    Specifies the address of an array containing the n​ names of the objects to be deleted.

  • (未使用)glIsVertexArray(),检查某个名称是否已经关联到一个顶点数组对象了。

    GLboolean glIsVertexArray(GLuint array​);
    array
    Specifies a value that may be the name of a vertex array object.

分配顶点缓存对象

顶点数组对象(VAO)负责保存一系列顶点的数据。这些数据保存到缓存对象(Buffer Object)中,并且由当前绑定的顶点数组对象管理。

官方解释:A Vertex Array Object (VAO) is an OpenGL Object that stores all of the state needed to supply vertex data (with one minor exception noted below). It stores the format of the vertex data as well as the Buffer Objects providing the vertex data arrays.

  • glGenBuffers (NumBuffers, Buffers) 返回NumBuffers个当前未使用的缓存对象名称到数组Buffers中。(名称不一定是连续的整型数据)

    void glGenBuffers(GLsizei n​, GLuint * buffers​);
    n
    Specifies the number of buffer object names to be generated.
    buffers
    Specifies an array in which the generated buffer object names are stored.
    No buffer objects are associated with the returned buffer object names until they are first bound by calling glBindBuffer​.

  • glBindBuffer (GL_ARRAY_BUFFER, Buffers[ArrayBuffer])在分配缓存的名称之后,就可以调用glBindBuffer()来绑定它们了。由于OpenGL中有很多种不同类型的缓存对象,因此绑定一个缓存时,需要指定它所对应的类型。此例中由于是将顶点数据保存到缓存中(故为顶点缓存对象VBO),因此使用GL_ARRAY_BUFFER类型。

    void glBindBuffer(GLenum target​, GLuint buffer​);
    target
    Specifies the target buffer object. The symbolic constant must be GL_ARRAY_BUFFER, GL_ATOMIC_COUNTER_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_DRAW_INDIRECT_BUFFER, GL_DISPATCH_INDIRECT_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_QUERY_BUFFER, GL_SHADER_STORAGE_BUFFER, GL_TEXTURE_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, or GL_UNIFORM_BUFFER.
    buffer
    Specifies the name of a buffer object.
    When a buffer object is bound to a target, the previous binding for that target is automatically broken.

  • (未使用)glDeleteBuffers(),所有的缓存对象都可以使用glDeleteBuffers()直接释放。

    void glDeleteBuffers(GLsizei n​, const GLuint * buffers​);
    n
    Specifies the number of buffer objects to be deleted.
    buffers
    Specifies an array of buffer objects to be deleted.

  • glIsBuffer(),使用此函数来判断一个整数值是否为缓存对象的名称。

    GLboolean glIsBuffer(GLuint buffer);
    buffer
    Specifies a value that may be the name of a buffer object.
    A name returned by glGenBuffers​, but not yet associated with a buffer object by calling glBindBuffer​, is not the name of a buffer object.

将数据载入缓存对象

  • glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW),初始化顶点缓存对象之后(VBO),我们需要把顶点数据传输到缓存对象中。它主要有两个任务:分配顶点数据所需的存储空间(内存中),然后将数据从应用程序的数组中拷贝到OpenGL服务端的内存中。

    void glBufferData(GLenum target​, GLsizeiptr size​, const GLvoid * data​, GLenum usage​);
    target
    Specifies the target buffer object. The symbolic constant must be GL_ARRAY_BUFFER, GL_ATOMIC_COUNTER_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_DRAW_INDIRECT_BUFFER, GL_DISPATCH_INDIRECT_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_QUERY_BUFFER, GL_SHADER_STORAGE_BUFFER, GL_TEXTURE_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, or GL_UNIFORM_BUFFER.
    size
    Specifies the size in bytes of the buffer object's new data store.
    data
    Specifies a pointer to data that will be copied into the data store for initialization, or NULL if no data is to be copied.
    usage
    Specifies the expected usage pattern of the data store. The symbolic constant must be GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY.

初始化顶点与片元着色器

  • 对于每一个OpenGL程序,当它所使用的OpenGL版本高于或等于3.1时,就需要指定至少两个着色器:顶点着色器和片元着色器。这个例子中,我们使用LoadShaders()来实现这个要求。
    对于OpenGL程序员而言,着色器就是使用OpenGL着色语言(GLSL,OpenGL Shading Language)编写的一个小型函数。

例1.2 triangles.cpp对应的顶点着色器:triangles.vert

#version 430 core
layout (location = 0) in vec4 vPosition;
void
main ()
{
        gl_Position = vPosition;
}

事实上这就是我们所说的传递着色器(pass-through shader)。它只负责将输入数据拷贝到输出数据中。
第一行

 #version 430 core

指定了OpenGL着色语言的版本。每个着色器的第一行都应该设置#version,否则就会假设使用“110”版本。
下一步,分配了一个着色器变量,着色器变量是着色器与外部世界的联系所在。着色器并不知道自己的数据从哪里来,它只是在每次运行时直接获取数据对应的输入变量。而我们必须自己完成着色管线的装配,然后才可以将应用程序中的数据与不同的OpenGL着色阶段相互关联。

layout (location = 0) in vec4 vPosition;
  • vPosition 是变量的名称。这个变量保存的是顶点的位置信息。(字符“v”作为这个顶点属性名称的前缀)
  • vec4,是vPosition的类型,在这里它是一个GLSL的四维浮点数向量。、
  • in,它指定了数据进入着色器的流向。
  • layout(location = 0),叫做布局限定符(layout qualifier),目的是为变量提供元数据(meta data)。这里设置vPosition的位置属性location为0。这个设置与init()函数的最后两行会共同起作用。

最后,在着色器的main()函数中实现它的主体部分。对于这个着色器而言,它所实现的就是将输入的顶点位置(存在vPosition中)复制到顶点着色器的指定输出位置gl_Position

例1.3 triangles.cpp对应的片元着色器:triangles.frag

@version 430 core
out vec4 fColor
void
main()
{
    fColor = vec4(0.0, 0.0, 1.0, 1.0);
}
  • 变量名为fColor,使用了out限定符,在这里着色器将会把fColor对应的数值输出,而这也就是片元所对应的颜色值。(因此这里前缀“f”)
  • OpenGL使用了RGBA颜色空间,A即aplha值(透明度)。1.0为不透明。

init()中的最后两个函数指定了顶点着色器的变量与我们存储在缓存对象中的数据的关系。这也就是我们所说的着色管线的装配过程,即将程序与着色器之间,以及不同着色阶段之间的数据通道连接起来。

  • glVertexAttribPointer (vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET (0));
    为了输入顶点着色器所需的数据,也就是OpenGL将要处理的所有顶点数据,需要在着色器中声明一个in变量,然后使用glVertexAttribPointer()将它关联到一个顶点属性数组。glVertexAttribPointer()是一个非常灵活的命令,只要内存中的数据是规范组织的(保存在一个连续的数组中,不使用其他基于节点的容器,如链表),我们就可以使用glVertexArrtibPointer()告诉OpenGL直接从内存中获取数据。

    void glVertexAttribPointer(GLuint index​, GLint size​, GLenum type​, GLboolean normalized​, GLsizei stride​, const GLvoid * pointer​);
    void glVertexAttribIPointer(GLuint index​, GLint size​, GLenum type​, GLsizei stride​, const GLvoid * pointer​);
    void glVertexAttribLPointer(GLuint index​, GLint size​, GLenum type​, GLsizei stride​, const GLvoid * pointer​);
    index
    Specifies the index of the generic vertex attribute to be modified.
    size
    Specifies the number of components per generic vertex attribute. Must be 1, 2, 3, 4. Additionally, the symbolic constant GL_BGRA is accepted by glVertexAttribPointer. The initial value is 4.
    type
    Specifies the data type of each component in the array. The different functions take different values.
    glVertexAttribPointer and glVertexAttribIPointer both take: GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, and GL_UNSIGNED_INT
    glVertexAttribPointer also can take: GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, GL_FIXED, GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV, and GL_UNSIGNED_INT_10F_11F_11F_REV.
    glVertexAttribLPointer takes only GL_DOUBLE.
    The initial value is GL_FLOAT.
    normalized
    For glVertexAttribPointer, specifies whether fixed-point data values should be normalized (GL_TRUE) or converted directly as fixed-point values (GL_FALSE) when they are accessed.
    stride
    Specifies the byte offset between consecutive generic vertex attributes. If stride​ is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.
    pointer
    Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of the buffer currently bound to the GL_ARRAY_BUFFER target. The initial value is 0.

  • glEnableVertexAttribArray (vPosition);
    我们通过glEnableVertexAttribArray()来启用顶点属性数组。glVertexAttribPointer()初始化的属性数组指针索引传入这个函数。

    void glEnableVertexAttribArray(GLuint index​);
    void glDisableVertexAttribArray(GLuint index​);
    index
    Specifies the index of the generic vertex attribute to be enabled or disabled.

1.5.3 第一次使用OpenGL进行渲染

void display (void)
{
    glClear (GL_COLOR_BUFFER_BIT);
    glBindVertexArray (VAOs[Triangles]);
    glDrawArrays (GL_TRIANGLES, 0, NumVertices);
    glFlush ();
}
  • glClear(GL_COLOR_BUFFER_BIT),清除帧缓存的数据。

    void glClear(GLbitfield mask​);
    mask
    Bitwise OR of masks that indicate the buffers to be cleared. The three masks are GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT.

  • (未使用)glClearColor(GLfloat red​, GLfloat green​, GLfloat blue​, GLfloat alpha​),设置当前使用的清除颜色值,用于RGBA模式下对颜色缓存的清除工作。

    清除颜色本身也是OpenGL状态机制的一个例子,它的数值会一直保留在当前OpenGL环境当中。
    OpenGL有一个庞大的状态量列表。当创建一个新的OpenGL环境时,所有的状态量都会被初始化为默认值。因为OpenGL会保留所有更改的状态值,所以我们可以减少设置状态数值的次数。
    故而,在设置清除颜色为白色时,可以在display()函数中调用glClearColor(1, 1, 1, 1),也可以在init()函数中调用glClearColor(1, 1, 1, 1),后者效率更高,因为可以避免冗余的状态切换。

  • glBindVertexArray (VAOs[Triangles]),选择作为顶点数据使用的顶点数组。我们可以使用这个函数来切换程序中保存的多个顶点数据对象集合。

  • glDrawArrays (GL_TRIANGLES, 0, NumVertices),使用当前绑定的顶点数组元素来建立一系列的几何图元。实现顶点数据向OpenGL管线的传输。

    glDrawArrays: render primitives from array data
    void glDrawArrays(GLenum mode​, GLint first​, GLsizei count​);
    mode
    Specifies what kind of primitives to render. Symbolic constants GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY and GL_PATCHES are accepted.
    first
    Specifies the starting index in the enabled arrays.
    count
    Specifies the number of indices to be rendered.

  • glFlush (),强制所有进行中的OpenGL命令立即完成并传输到OpenGL服务端处理。

    glFlush: force execution of GL commands in finite time
    void glFlush(void​);

  • (未使用)glFinish(),会等待所有当前的OpenGL操作完成。而glFlush()则只是强制所有运行中的命令送入OpenGL服务端而已,不会等待所有的命令完成。因此当我们需要了解OpenGL是在是么时候完成操作的时候使用glFinish()。

    glFinish: block until all GL execution is complete
    void glFinish(void​);
    glFinish does not return until the effects of all previously called GL commands are complete. Such effects include all changes to GL state, all changes to connection state, and all changes to the frame buffer contents.

  • (未使用)glEnable(),glDisable(),启用或禁用OpenGL的操作模式。

    glEnable: enable or disable server-side GL capabilities
    void glEnable(GLenum cap​);
    void glDisable(GLenum cap​);
    cap
    Specifies a symbolic constant indicating a GL capability.

  • (未使用)glIsEnabled(),返回是否启用指定模式。

    glIsEnabled, glIsEnabledi: test whether a capability is enabled
    GLboolean glIsEnabled(GLenum cap​);
    GLboolean glIsEnabledi(GLenum cap​, GLuint index​);
    cap
    Specifies a symbolic constant indicating a GL capability.
    index
    Specifies the index of the capability.


相关链接:

转载于:https://www.cnblogs.com/ice-mj/p/5413629.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[OpenGL]第一章 OpenGL概述 的相关文章

  • Anaconda 安装 Python 库(MySQLdb)的方法-(转)

    安装python库的过程中 最重要的地方就是版本需要兼容 其中操作系统为64位 Python为2 X 64位 下载安装文件的时候也要注意版本匹配 其中文件名中包含的cp27表示CPython 2 7版本 cp34表示CPython 3 4
  • Linux下进程退出的几种形式

    进程退出 Linux 下进程的退出分为正常退出和异常退出两种 1 正常退出 a 在main 函数中执行return b 调用exit 函数 c 调用 exit 函数 2 异常退出 a 调用about函数 b 进程收到某个信号 而该信号使程序
  • 操作系统常见面试题

    1 什么是进程 Process 和线程 Thread 有何区别 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动 进程是系统进行资源分配和调度的一个独立单位 线程是进程的一个实体 是CPU调度和分派的基本单位 它是比进程更小的能
  • 【试题】排列组合

    在写一个远程的代码 如果本地有M个显示器 远程有N个显示器 M lt N 依据分辨率 显示器刷新频率等要求 需要对远程的N个显示器进行最佳分辨率修改 之后 需要从N个远程显示器中选择M个 跟本地显示器进行一对一的匹配 即从 A N M N
  • 【C/C++】 - Linux下查找函数头文件 以及 man命令拓展

    背景 比如现在需要找C语言 sleep函数的头文件 使用man来查找 可以先man sleep 可以发现出来的默认是sleep 1 是一个User Commands 明显不是我们需要的 这里提示了 看sleep 3 那我们查看下sleep
  • gdb attach 进程调试

    gdb调试正在运行的进程 GDB可以对正在执行的程序进行调度 它允许开发人员中断程序 并查看其状态 之后还能让这个程序正常地继续执行 gdb attach xxxxx xxxxx为利用ps命令获得的子进程process
  • 使用ShellJS提升你的开发效率(一)

    Shelljs Unix shell commands for Node js Shelljs是Node js下的脚本语言解析器 具有丰富且强大的底层操作 Windows Linux OS X 权限 Shelljs本质就是基于node的一层
  • 基数排序代码实现

    详情请看排序总结 传送门 https blog csdn net m0 52711790 article details 121914543 基数排序的知识点我就不贴出来 相信都能搜到对应概念解释 下面就直接上代码 代码解释其实也很清晰了
  • 《OSPF和IS-IS详解》一1.7 独立且平等

    本节书摘来自异步社区 OSPF和IS IS详解 一书中的第1章 第1 7节 作者 美 Jeff Doyle 更多章节内容可以访问云栖社区 异步社区 公众号查看 1 7 独立且平等 OSPF和IS IS详解与TCP IP相比 OSI协议对各国
  • 检查内存泄露

    自己编写的视频处理程序出现了一个问题 每帧的运行时间随着运行时间在不断增长 很大可能是出现了内存泄露 于是学习了一些查看内存泄露的方法 做了两种尝试 一是VS自带的DEBUG下的检测 view pl html view plain copy
  • 【C++】运算符重载

    加号运算符重载 include
  • 牛客剑指offer刷题其他算法篇

    文章目录 构建乘积数组 题目 思路 代码实现 第一个只出现一次的字符
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • 【数据结构】双链表的定义和操作

    目录 1 双链表的定义 2 双链表的创建和初始化 3 双链表的插入节点操作 4 双链表的删除节点操作 5 双链表的查找节点操作 6 双链表的更新节点操作 7 完整代码 嗨 我是 Filotimo 很高兴与大家相识 希望我的博客能对你有所帮助
  • C++常见STL容器基本用法

    1 vector include
  • C 语言运算符详解

    C 语言中的运算符 运算符用于对变量和值进行操作 在下面的示例中 我们使用 运算符将两个值相加 int myNum 100 50 虽然 运算符通常用于将两个值相加 就像上面的示例一样 它还可以用于将变量和值相加 或者将变量和另一个变量相加
  • C++ 中 const 和 constexpr 关键字解析:常量、函数和指针

    很多 C 的初学者看到 const 这个关键字的第一反应都是一头雾水 主要是因为 const 可 以出现在很多的位置 以及后面加入的 constexpr 更是常常感到困惑 今天就为大家一一解释出现它们的含义和以及作用 const 关键字 c
  • C++中的引用

    一 引用的概念 引用不是新定义一个变量 而是给已有变量取一个别名 编译器不会为引用变量开辟内存空间 而和它引用的变量共用一块内存空间 注意 由于C 兼容C 所以 既可以是引用符号 也可以是取地址 int a 0 int b a cout l
  • C++实现函数重载的原理

    一 函数重载的概念 C 中允许存在同名函数 但要求函数参数的类型 个数不同 这些同名函数就称为函数的重载 void func int a int b cout lt lt func int a int b lt lt endl void f
  • 在 Solaris 上,使用 gcc 编译的库与使用 cc 生成的库的使用方式是否相同?

    我目前正在尝试编译 libxml2在 Solaris 上 当我运行源代码提供的 configure 脚本时 会自动使用 gcc 和 g 编译器 但是 我想使用 cc 和 CC 编译器 所以我跑 configure CC cc CXX CC

随机推荐

  • springboot 连接redis

    安装文章https blog csdn net yeluo vinager article details 103680059 问题 F soft Redis x64 3 2 100 gt redis server exe service
  • muduo异步日志总结

    muduo中的日志是指诊断日志 即通常用于故障诊断和追踪的日志 便于服务器发生故障时的线索追踪 是网络库中很重要的一个部分 在总结异步日志之前 首先应该清楚什么是异步日志 与同步日志又有什么区别 同步日志与异步日志 同步日志 网络IO线程或
  • iPhone6可能取代公交卡和门禁卡

    10月28日 苹果公司正在积极寻求合作 以增加iPhone 6和iPhone 6 Plus内置的NFC芯片的用途 该芯片目前只能通过Apple Pay支付服务使用 因为苹果并没有向第三方开放API 应用编程接口 苹果正在与潜在合作伙伴展开沟
  • 流水线上的大专生,成功转行高薪IT岗,历程太心酸

    前言 我来自山东滨州 98年的 毕业于某职业学院 一名大专生 专业是机电一体化技术 对编程的认知度为0 和大多数人一样 一个月2500元 浑浑噩噩的工厂生活 大学时光 基本都是在睡觉 上网 逃课 早退中度过 偶尔会有一丝丝危机感 但是没一会
  • 华为OD机试真题-查找单入口空闲区域【2023.Q1】

    题目描述 给定一个 m xn 的矩阵 由若干字符 和0构成 X表示该处已被占据 0 表示该处空闲 请找到最大的单入口空闲区域 解释 空闲区域是由连通的O组成的区域 位于边界的0可以构成入口 单入口空闲区域即有目只有一个位于边界的0作为入口的
  • Linux系统中基于NGINX的代理缓存配置指南

    作为一名专业的爬虫程序员 你一定知道代理缓存在加速网站响应速度方面的重要性 而使用NGINX作为代理缓存服务器 能够极大地提高性能和效率 本文将为你分享Linux系统中基于NGINX的代理缓存配置指南 提供实用的解决方案 助你解决在爬虫过程
  • idea的自定义模板(文件代码模板和文件注释说明文档)

    1 idea自定义文件代码模板 1 步骤 File Settings Editor File and Code Templates 复制 起个名字 name 例如叫 HTML File View 把需要的代码放到合适位置 就做好了文件代码模
  • ES6必须知道的知识点--思维导图

    学习过程中每个人有每个人不同的习惯 我喜欢学完一个知识点再用脑图整理出知识点 这样回顾就有思路 看的顺序是从右上角开始顺时针 下面的图片是ES6要掌握的知识点 如果是要从事Vue React 这些都掌握了你就一只jio 进门了 希望对你有帮
  • 如何存matlab,[转载]如何在Matlab中保存文件及导入文件

    一 保存文件 1 保存整个工作区 File gt Save Workspace as 一个 mat文件 2 保存工作区的变量 在左工作区右击变量名 create M File 3 save命令 1 save 将工作区中的所有变量保存在当前工
  • C++ 从 HDF5 文件读取 Keras 神经网络模型和参数

    C 从 HDF5 文件读取 Keras 神经网络模型和参数 一 背景与应用 二 Keras 保存的 HDF5 参数 Weight 文件分析 二 遍历起点 1 工程需要包含的头文件和库文件 2 打开文件 3 打开 Root Group 并输出
  • uniapp图片上传h5与小程序的差别

    uni app的uni chooseImage图片上传的时候在h5跟小程序的一个差异 upload const token uni getStorageSync token uni chooseImage count 1 最多上传几张图片
  • 问题解决: 此文件来自其他计算机,可能被阻止以帮助保护该计算机/WORD在试图打开文件时遇到错误……...

    最近 在打开下载的office文档 包括word excel ppt等 时候 总是无法直接打开 错误提示如下 无论是邮件中的还是别的网站下载的 均提示该错误 后来搜索相关资料发现 修改其文件属性即可打开 属性 解除锁定
  • Web服务器如何确定哪个servlet处理请求

    Web服务器如何确定哪个Servlet处理请求 1 Servlet中的方法 1 init 方法 在Servlet的生命周期中 仅执行一次init 方法 它是在服务器装入Servlet时执行的 可以配置服务器 以在启动服务器或客户机首次访问S
  • g++11 ubuntu安装 2022

    编译一个C 工程 该工程要求g 版本大于等于11 在Windows上下载了Mingw 12版本 用里边内置的make时 编译出错 改用ubuntu安装g 和make 可以正常编译 记录一下安装过程备忘 安装gcc g 11 该条命令加入一个
  • DllNotFoundException: XRSDKOpenVR Unity.XR.OpenVR.OpenVRLoader.Initialize报错(unity2019.4.8f1)

    打开packageManager检查是否有OpenXR Plugin插件 Remove即可 其他配置 注意版本为Unity2019 4 8f1 使用设备为Htc vive focus 3串流PC Steam VR
  • 让资深猎头-GPT帮你修改简历,Get 心动的offer

    正文共 1391 字 阅读大约需要 4 分钟 求职者必备技巧 您将在4分钟后获得以下超能力 根据JD修改简历 Beezy评级 B级 经过简单的寻找 大部分人能立刻掌握 主要节省时间 推荐人 Kim 编辑者 Linda 图片来源 Lexica
  • Linux命令:lsof

    目录 一 理论 1 lsof 二 实验 1 无参数 2 p 参数 3 l 参数 4 u 参数 5 c 参数 6 d 参数 7 fileName 8 i 参数 一 理论 1 lsof 1 概念 命令 lsof list opened file
  • Apache详解(五)WEB相关工具

    成功不易 加倍努力 Apache详解总目录 5 Web相关工具 5 1 links 5 2 wget 5 3 curl 5 4 httpie 5 5 压力测试工具 5 6 httpd自带的工具程序 Apache详解总目录 Internet
  • springboot 整合 mybatis 报错: Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException

    Caused by org springframework beans factory NoSuchBeanDefinitionException No qualifying bean of type com mybatis springb
  • [OpenGL]第一章 OpenGL概述

    第一章 OpenGL概述 1 1 什么是OpenGL OpenGLwikipedia是一种应用程序编程接口 API 它是一种可以对图形硬件设备特性进行访问的软件库 一个用来渲染图像的OpenGL程序需要执行的主要操作如下 从OpenGL的几