计算机图形学实验练习(实验1.2-4.1AND补充实验12)
实验1.2 OpenGL与着色器编程
1.理论知识
1.1 OpenGL的含义
OpenGL是一种应用程序编程接口(Application Programming Interface,API),它是一种可以对图形硬件设备特性进行访问的软件库。OpenGL最新的4.3版本包含了超过500个不同的命令,可以用于设置所需的对象、图像和操作,以便开发出交互式的三维计算机图形应用程序。
OpenGL被设计为一个现代化的、硬件无关的接口,因此可以在不考虑计算机操作系统或窗口系统的前提下,在多种不同的图形硬件系统上,或者完全通过软件的方式实现OpenGL的接口。OpenGL自身并不包括任何执行窗口任务或者处理用户输入的函数,OpenGL也没有提供任何用于表达三维物体模型,或者读取图像文件(例如JPEG文件)的操作。这时,需要通过一系列的几何图元(geometric primitive)(包括点、线、三角形)来创建三维空间的物体。
一个用来渲染图像的OpenGL需要执行的主要操作如下所示:
a) 从OpenGL的几何图元中设置数据,用于构建形状。
使用不同的着色器(shader)对输入的图元数据执行计算操作,判断它们的位置、颜色,以及其他渲染属性。
b) 将输入图元的数学描述转换为与屏幕位置对应的像素片元(fragment)。这一步也成为光栅化(rasterization)。
c) 最后针对光栅化过程产生的每个片元,执行片元着色器(fragment shader),从而决定这个片元的最终颜色和位置。
d) 如果有必要,还需要对每个片元执行一些额外的操作,例如判断片元对应的对象是否可见,或者将片元的颜色与当前屏幕位置的颜色进行融合。
OpenGL另一个最本质的概念叫做着色器,它是图形硬件设备所执行的一类特殊函数。理解着色器最好的方法是把它看作专为图形处理单元(通常称作GPU)编译的一种小型程序。OpenGL在其内部包含了所有的编译器工具,可以直接从着色器源代码创建GPU所需的编译代码并执行。在OpenGL中,会用到四种不同的着色阶段(shader stage)。其中最常用的包括顶点着色器(vertex shader)以及片元着色器(fragment shader),前者用于处理顶点数据,后者用于处理光栅化后的片元数据。所有的OpenGL程序都需要用到这两类着色器。
最终生成的图像包含了屏幕上绘制的所有像素点。像素(pixel)是显示器上最小显示单位。计算机系统将所有的像素保存到帧缓存(frame buffer)。
1.2 着色器与OpenGL
OpenGL 实现了通常所说的渲染流程(rendering pipeline),它是一系列数据处理过程,并且将应用程序的数据转换到最终渲染的图像。上图为 OpenGL 4.3 版本的管线。自从 OpenGL 诞生以来,它的渲染流程已经发生了非常大的变化。
OpenGL 首先接收用户提供的几何数据(顶点和几何图元),并且将它输入到一系列着色器阶段中进行处理,包括:顶点着色、细分着色(它本身包含两个着色器),以及最后的几何着色,然后它将被送入光栅化单元(rasterizer)。光栅化单元负责对所有剪切区域(clipping region)内的图元生成片元数据,然后对每个生成的片元都执行一个片元着色器。
对于 OpenGL 应用程序而言着色器扮演了一个最重要的角色。你可完全控制自己需要用到的着色器来实现自己所需的功能。实际上,不需要用到所有的着色阶段,只有顶点着色器和片元着色器是必需的。细分和几何着色器是可选的步骤。
1.3 着色器与OpenGL
现代 OpenGL 渲染流程严重依赖着色器来处理传入的数据。在OpenGL 3.0 版本及以前,或者如果你用到了兼容模式(compatibility profile)环境,OpenGL 还包含一个固定功能流程(fixed-function pipeline),它可以在不使用着色器的情况下处理几何与像素数据。从 3.1 版本开始,固定功能流程从核心模式中去除,因此必须使用着色器来完成工作。
对于 OpenGL 而言,会使用 GLSL去编写着色器,也就是 OpenGL Shading Language。虽然 GLSL 是一种专门为图形开发设计的编程语言,但它与C语言非常类似,当然还有一点 C++ 的影子。
1.4 着色器的编译
OpenGL 着色器程序的编写与 C 语言等基于编译器的语言非常类似,也就是使用编译器来解析程序,检查是否存在错误,然后将它翻译为目标代码。然后在链接过程中将一系列目标文件合并,并产生最终的可执行程序。下图给出了创建 GLSL 着色器对象并通过链接来生成可执行着色器程序的过程。
对于每个着色器程序,都需要在应用程序中通过下面的步骤进行设置:
a) 创建一个着色器对象。
b) 将着色器源代码编译为对象。
c) 验证着色器的编译是否成功。
然后需要将所有着色器对象链接为一个着色器程序,包括:
a) 创建一个着色器程序。
b) 将着色器对象关联到着色器程序。
c) 链接着色器程序。
d) 判断着色器的链接过程是否成功完成。
e) 使用着色器来处理顶点和片元。
通常,创建多个着色器对象是因为有可能在不同的程序中复用同一个函数,而 GLSL 程序也是同样的道理。
2.相关代码
2.1OpenGL项目结构
a) include 文件夹:
-
Angel.h 主要包含了 GLAD(OpenGL加载库) 和 GLFW(OpenGL窗口库) 的头文件和简单的宏定义(GLAD负责加载 OpenGL 扩展和函数指针,使得程序可以调用特定版本的 OpenGL 函数;GLFW负责创建和管理窗口、处理输入事件,以及管理 OpenGL 上下文。)
-
CheckError.h 定义了输出错误信息的函数。
c) shaders 文件夹:vshader 与 fshader 分别是用 GLSL 编写的顶点着色器和片元着色器,在程序中通过 InitShader() 函数加载,其中文件名中带有“mac”的文件为MacOS下使用的着色器文件。
d) Initshader.cpp:实现了 InitShader() 函数,是为着色器进入 GPU 的操作专门实现的函数。
e) main.cpp:项目中的主要逻辑实现文件,包含初始化、绘制、响应控制等功能实现。
f) CMakeLists是指导CMake生成项目的描述文件, 描述了项目的生成过程,包括基本配置、生成目标、链接库等等。
2.2main.cpp核心代码文件
一个OpenGL程序通常会在起始部分,包含必要的头文件,并声明一些全局变量和其他有用的程序结构。程序主体由init(),display(),main()这三个函数组成。
init()函数负责设置程序中需要用到的数据。在本实验中,它负责设置渲染图元时用到的顶点位置信息。然后指定了程序中使用的顶点和片元着色器。最后将应用程序的数据与着色器程序的变量关联起来。
display()函数真正执行了渲染的工作。它负责调用OpenGL函数并渲染需要的内容,几乎所有的display()函数都要完成清除窗口内容、调用OpenGL命令来渲染对象、将最终图像输出到屏幕这三个步骤。
main()函数执行了创建窗口、调用init()以及最终进入时间循环体系的一系列繁重工作。这里会使用到一些以gl开头的函数,这些会是来自第三方库GLAD和GLFW的函数,这些函数的作用是快速完成一些简单功能,并保证OpenGL程序可以运行在不同的操作系统上。
a) 深入main()主函数
int main(int argc,char **argv)
{glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);GLFWwindow* window =glfwCreateWindow(512,512,"Red Triangle",NULL,NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window,framebuffer_size_callback);if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}init();while(!glfwWindowShouldClose(window)){display();glfwSwapBuffers(window);glfwPollEvents();}return 0;
}
glfwInit()初始化GLFW库。glfwInit()必须是应用程序调用的第一个GLFW函数,它会负责设置其他GLFW例程所必需的数据结构。
glfwWindowHint ()用来配置GLFW,第一个参数代表选项的名称,我们可以从很多以GLFW_开头的枚举值中选择;第二个参数接受一个整型,用来设置这个选项的值。在本例中将主版本号(Major)和次版本号(Minor)都设为3。我们同样明确告诉GLFW我们使用的是核心模式(Core-profile)。明确告诉GLFW我们需要使用核心模式意味着我们只能使用OpenGL功能的一个子集。
glfwCreateWindow ()创建窗口。窗口的宽和高作为它的前两个参数,第三个参数表示这个窗口的名称(标题),第四个和第五个参数可以忽略。
glfwMakeContextCurrent()用来通知GLFW将窗口的上下文设置为当前线程的主上下文。
glfwSetFramebufferSizeCallback(),该函数会调用回调函数framebuffer_size_callback(),回调函数中GLFWwindow作为它的第一个参数,以及两个整数表示窗口的新维度。每当窗口改变大小,GLFW会调用这个函数并填充相应的参数供你处理。
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress),GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前需要初始化GLAD。给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数。GLFW给我们的是glfwGetProcAddress,它根据我们编译的系统定义了正确的函数。
glfwWindowShouldClose()函数在我们每次循环的开始前检查一次GLFW是否被要求退出,如果是的话该函数返回true然后渲染循环便结束,关闭应用程序。
glfwSwapBuffers()函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
glfwPollEvents()函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)。
b) OpenGL的初始化过程
下面将分析讨论init()函数:
(1) 本次实验想要绘制两个形状,一个是三角形,一个是正方形。于是函数开始先创建了两个顶点数组对象vao(vertex array object),这个变量将用于管理顶点缓存对象,一个vao可以管理多个顶点属性(坐标、颜色、法向量等)。然后定义了我们要绘制的三角形与正方形的顶点坐标数组以及对于的顶点颜色数组。其中generateTrianglePoints和generateSquarePoints是代码中生成这些顶点数据的函数。
// 生成三角形上的每个点
void generateTrianglePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex)
{// 三角形尺寸glm::vec2 scale(0.25, 0.25);// 三角形中心位置glm::vec2 center(0.0, 0.70);
// @TODO: 在此函数中修改三角形的顶点位置 for(int i=0;i<3;i++) { double currentAngle=getTriangleAngle(i); vertices[startVertexIndex+i]=glm::vec2(cos(currentAngle),sin(currentAngle))*scale+center; }
// 确定三个顶点的颜色colors[startVertexIndex] = RED;colors[startVertexIndex + 1] = BLUE;colors[startVertexIndex + 2] = GREEN;
}
// 生成正方形上的每个点
void generateSquarePoints(glm::vec2 vertices[], glm::vec3 colors[], int squareNum, int startVertexIndex)
{// 最大正方形尺寸glm::vec2 scale(0.90, 0.90);// 正方形中心位置glm::vec2 center(0.0, -0.25);
glm::vec3 currentColor = WHITE;int vertexIndex = startVertexIndex;
// @TODO: 在此函数中修改,生成多个嵌套正方形double scaleDecrease = 0.15;// 根据正方形及顶点对应角度,计算当前正方形四个顶点坐标 for(int i=0;i<squareNum;i++) { currentColor=(i%2)?Black:WHITE; for(int j=0;j<4;j++) { double currentAngle=getSquareAngle(j); vertices[vertexIndex+j]=glm::vec2(cos(currentAngle),sin(currentAngle))*scale+center; colors[vertexIndex]=currentColor; vertexIndex++; } scale-=scaleDecrese; }
}
init():// 全局变量,两个vao,一个绘制三角形,一个绘制正方形
GLuint vao[2],program;
void init()
{ // 定义三角形的三个点glm::vec2 triangle_vertices[TRIANGLE_NUM_POINTS];glm::vec3 triangle_colors[TRIANGLE_NUM_POINTS];// 定义矩形的点glm::vec2 square_vertices[SQUARE_NUM_POINTS];glm::vec3 square_colors[SQUARE_NUM_POINTS];
// 调用生成形状顶点位置的函数generateTrianglePoints(triangle_vertices, triangle_colors, 0);generateSquarePoints(square_vertices, square_colors, SQUARE_NUM, 0);
(2)vshader和fshader分别对应shaders文件夹内的顶点与片元着色器文件的路径,我们使用InitShader.cpp内定义好的InitShader函数绑定和编译这两个着色器。函数会返回一个“着色器对象”,我们接着调用glUseProgram函数使用该着色器对象。我们后面会通过缓存对象 buffer 传递数据到渲染管道,而调用glUseProgram之后,渲染管道中会使用到我们指定的这两个着色器进行处理。
// 读取着色器并使用std::string vshader, fshader;vshader = "shaders/vshader.glsl";fshader = "shaders/fshader.glsl";program = InitShader(vshader.c_str(), fshader.c_str());glUseProgram(program);
(3) 首先我们给三角形的数据进行初始化,使用glGenVertexArrays函数分配一个vao(vertex array object)对象,使用glBindVertexArray函数绑定vao[0],vao对象将用于管理顶点缓存对象vbo(vertex buffer object),一个vao可以管理多个顶点属性(坐标、颜色、法向量等)
/** 初始化三角形的数据*/// 创建顶点数组对象glGenVertexArrays(1, &vao[0]); // 分配1个顶点数组对象glBindVertexArray(vao[0]); // 绑定顶点数组对象
(4) 与顶点数组对象vao的创建类似,我们这里定义顶点缓存对象vbo(vertex buffer object),这个变量是用来真正处理和管理各种顶点数据的,通过vao我们将会向GPU传递数据。使用glGenBuffer函数分配vbo,使用glBindBuffer函数绑定vbo,然后使用glBufferData函数分配一个缓存空间,把我们定义好的 三角形顶点数据triangle_vertices 传输到缓存对象当中。在glBufferData()函数中,顶点属性数据应设置GL_ARRAY_BUFFER,sizeof(vertices)指定了内存分配的大小,由于运行时不做修改所以最后的usage参数为GL_STATIC_DRAW。
(5) 虽然我们传入了一个顶点坐标数组,但是GPU并不知道要如何使用这个数据,我们还需要告诉GPU如何读取和链接,这里开始会涉及到两个着色器文件的内容。下面先介绍C++代码中的数据操作,然后再介绍着色器文件内代码具体的含义。
我们希望将triangle_vertices数组作为顶点坐标传递到渲染管道内,在vshader.glsl中,我们有声明一个in的属性 vPosition ,表示顶点着色器接收的数据,在init函数中,我们使用glGetAttribLocation函数获取这个属性在着色器程序 program 中的位置。
由于顶点属性默认是禁用的,所以获取了这个属性的位置后,我们要使用glEnableVertexAttribArray函数启用该属性,使得着色器中它能够接收数据。之后我们需要手动定义我们传递给着色器的 vertices 数组是如何对应到顶点属性的,也就是和GPU解释这些数据该如何读取,使用的函数为glVertexAttribPointer(文档最后会有函数简介)。同理我们在顶点着色器文件vshader.glsl只也声明了一个 vColor 属性,用来接收顶点颜色数据。
// 创建顶点缓存对象,vbo[2]是因为我们将要使用两个缓存对象,// 一个是顶点坐标,一个是顶点颜色GLuint vbo[2];// 分配1个顶点缓存对象glGenBuffers(1, &vbo[0]);// 绑定顶点缓存对象glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);// 分配数据所需的存储空间,将数据拷贝到OpenGL服务端内存glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW);// 从顶点着色器中初始化顶点的位置GLuint location = glGetAttribLocation(program, "vPosition");// 启用顶点属性数组glEnableVertexAttribArray(location);// 关联到顶点属性数组 (index, size, type, normalized, stride, *pointer)glVertexAttribPointer(location,2,GL_FLOAT,GL_FALSE,sizeof(glm::vec2),BUFFER_OFFSET(0));// 给颜色glGenBuffers(1, &vbo[1]);glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_colors), triangle_colors, GL_STATIC_DRAW);GLuint cLocation = glGetAttribLocation(program, "vColor");glEnableVertexAttribArray(cLocation);glVertexAttribPointer(cLocation,3,GL_FLOAT,GL_FALSE,sizeof(glm::vec3),BUFFER_OFFSET(0));
(6) 到目前为止,代码都是在glBindVertexArray(vao[0])之后进行的数据初始化,所以这聚代码之后关于vbo的操作,都会指向vao[0]这个顶点数组对象管理,这些数据都是三角形的顶点数据。当我们想初始化正方形的顶点数据时,也需要重复上面三角形的操作,先从glBindVertexArray开始,我们将vao[1]作为正方形数据的顶点数组对象,这里不在赘述,结合代码观看。init函数最后的glClearColor()设置了当前所有使用的清除颜色值,可用来设置背景的颜色。
c) 使用OpenGL进行渲染
下面将分析讨论display()函数。
void display(void)
{// 清理窗口glClear(GL_COLOR_BUFFER_BIT);
// 激活着色器glUseProgram(program);// 绑定三角形的顶点数组对象glBindVertexArray(vao[0]);glDrawArrays(GL_TRIANGLES, 0, TRIANGLE_NUM_POINTS);// 绑定正方形的顶点数组对象glBindVertexArray(vao[1]);
// 注意这里使用的绘制模式为GL_TRIANGLE_FAN// 它会以顶点数据的一个点为中心顶点,绘制三角形
// 绘制多个正方形for (int i = 0; i < SQUARE_NUM; ++i) {glDrawArrays(GL_TRIANGLE_FAN, (i * 4), 4);}// 强制所有进行中的OpenGL命令完成glFlush();
}
(1) 在渲染前需要利用glClear()函数清除帧缓存的数据。
(2) 我们想绘制图像,那么就需要指定着色器,所以需要glUseProgram函数激活我们在init函数中定义的着色器对象program。
(3) 先绘制三角形,所以我们先glBindVertexArray绑定三角形数据对应的vao,接着使用glDrawArrays绘制三角形,这函数会使用当前绑定的顶点数组元素来建立一系列的几何图元,实现顶点数据向OpenGL管线的传输。之后重复类似操作绘制正方形。
2.3 编写顶点与片元着色器
着色器就是使用OpenGL着色语言(GLSL)编写的一个小型函数。程序可以以字符串的形式传输GLSL着色器到OpenGL,不过为了更容易地使用着色器去进行开发,所有实验都将着色器字符串的内容保存到文件中,并且使用Initshader()读取文件和创建OpenGL着色器程序。下面将深入了解本次实验项目中的顶点着色器与片元着色器。
a) 顶点着色器vshader.glsl
第一行#version 330 core指定了所用的OpenGL着色语言版本,330 core代表了使用OpenGL 3.3 对应的GLSL语言,core代表使用OpenGL核心模式。每个着色器的第一行都应该设置#version,否则系统会使用110版本(对应OpenGL2.0)。
下一步是分配着色器变量。对于in vec3 vPosition,in字段指定了数据进入着色器的流向,而vPosition变量是一个GLSL中三维浮点数向量。接下来的vColor与vPosition是相似的输入变量。对于out vec3 color,out的限定符代表在顶点着色器中,会把color对应的数值输出。
着色器的main()函数实现其主体部分,在OpenGL的所有着色器中,都会有一个main()函数。在这里实现的就是将输入的三维顶点位置转换为四维,最后一位用1.0补齐,并复制到顶点着色器的指定输出变量gl_Positition中。
#version 330 corein vec3 vColor;
in vec3 vPosition;out vec3 color;void main()
{gl_Position = vec4(vPosition, 1.0);color = vColor;
}
b) 片元着色器fshader.glsl
在OpenGL中,还需要一个片元着色器来配合顶点着色器的工作。下面就是片元着色器的内容。
虽然片元着色器与顶点着色器属于两个完全不同类型的着色器,但大部分的代码都很类似。这里的in vec3 color代表了将顶点着色器中输出的color作为该片元着色器输入数据,这样便把两个不同着色阶段的数据连接了起来。最终片元着色器把fColor对应的数值输出,在这里也就是片元所对应的颜色值。
在OpenGL中的颜色是通过RGBA空间表示,因此最后用1.0的完全不透明alpha值,将RGB颜色向量转换为四维RGBA向量。在片元着色器中重点的内容就是设定片元的颜色,而在这里便决定了图元的最终颜色。
#version 330 corein vec3 color;
out vec4 fColor;void main()
{fColor = vec4(color, 1.0);
}
实验2.2 OFF格式的模型显示
1.理论知识
1.1OFF格式文件
OFF,Object File Format,即物体文件格式,是一种三维模型文件格式。物体文件格式(.off)文件通过描述物体表面的多边形来表示一个模型的几何结构,这里的多边形可以有任意数量的顶点。本次实验提供了两个立方体的off文件,放在assets文件夹下。
Princeton Shape Benchmark中的 .off 文件遵循以下标准:
-
OFF文件全是以OFF关键字开始的ASCII文件。
-
第二行说明顶点的数量、面片的数量、边的数量。边的数量可能会省略。
-
第三行开始是顶点列表,顶点按每行一个列出x、y、z坐标。
-
在顶点列表后,面片按照每行一个列表,对于每个面片,顶点的数量是指定的,接下来是顶点索引列表。比如图中有一行是 3 1 6 2,它表示该面片有3个顶点,由第1、6、2个顶点构成。
1.2深度测试
在绘制时,如果屏幕上当前像素要绘制新的候选颜色,只有对应物体比之前的物体更靠近观察者,我们才能绘制它
相关文章:
计算机图形学实验练习(实验1.2-4.1AND补充实验12)
实验1.2 OpenGL与着色器编程 1.理论知识 1.1 OpenGL的含义 OpenGL是一种应用程序编程接口(Application Programming Interface,API),它是一种可以对图形硬件设备特性进行访问的软件库。OpenGL最新的4.3版本包含了超过500个不同的命令,可以用于设置所需的对象、图像和操…...
javascript-es6 (一)
作用域(scope) 规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问 局部作用域 函数作用域: 在函数内部声明的变量只能在函数内部被访问,外部无法直接访问 function getSum(){ //函数内部是函数作用…...
uni-app 程序打包 Android apk、安卓夜神模拟器调试运行
1、打包思路 云端打包方案(每天免费次数限制5,最简单,可以先打包尝试一下你的程序打包后是否能用): HBuilderX 发行App-Android云打包 选择Android、使用云端证书、快速安心打包本地打包: HBuilderX …...
yolov11 解读简记
1 文章详细介绍了YOLOv11的架构设计,包括以下几个关键组件: C3k2块:这是YOLOv11引入的一种新型卷积块,替代了之前版本中的C2f块。C3k2块通过使用两个较小的卷积核代替一个大的卷积核,提高了计算效率,同时保…...
CommonAPI学习笔记-1
CommonAPI学习笔记-1 一. 整体结构 CommonAPI分为两层:核心层和绑定层,使用了Franca来描述服务接口的定义和部署,而Franca是一个用于定义和转换接口的框架(https://franca.github.io/franca/)。 核心层和通信中间…...
从入门到精通:RabbitMQ的深度探索与实战应用
目录 一、RabbitMQ 初相识 二、基础概念速览 (一)消息队列是什么 (二)RabbitMQ 核心组件 三、RabbitMQ 基本使用 (一)安装与环境搭建 (二)简单示例 (三)…...
深入理解若依RuoYi-Vue数据字典设计与实现
深入理解若依数据字典设计与实现 一、Vue2版本主要文件目录 组件目录src/components:数据字典组件、字典标签组件 工具目录src/utils:字典工具类 store目录src/store:字典数据 main.js:字典数据初始化 页面使用字典例子…...
Cursor 帮你写一个小程序
Cursor注册地址 首先下载客户端 点击链接下载 1 打开微信开发者工具创建一个小程序项目 选择TS-基础模版 官方 2 然后使用Cursor打开小程序创建的项目 3 在CHAT聊天框输入自己的需求 比如 小程序功能描述:吃什么助手 项目名称: 吃什么小程序 功能目标…...
进程控制的学习
目录 1.进程创建 1.1 fork函数 1.2 fork函数返回值 1.3 写时拷贝 1.4 fork 常规用法 1.5 fork 调用失败的原因 2. 进程终止 2.1 进程退出场景 2.2 进程常见退出方法 2.2.1 从main 返回 2.2.2 echo $? 查看进程退出码 2.2.2.1 我们如何得到退出码代表的含…...
一文讲解Java中的接口和抽象类
抽象类和接口有什么区别? 一个类只能继承一个抽象类;但一个类可以实现多个接口。所以我们在新建线程类的时候,一般推荐使用Runnable接口的方式,这样线程类还可以继承其他类,而不单单是Thread类;抽象类符合…...
Vue 3 30天精进之旅:Day 05 - 事件处理
引言 在前几天的学习中,我们探讨了Vue实例、计算属性和侦听器。这些概念为我们搭建了Vue应用的基础。今天,我们将专注于事件处理,这是交互式Web应用的核心部分。通过学习如何在Vue中处理事件,你将能够更好地与用户进行交互&#…...
STM32完全学习——RT-thread在STM32F407上移植
一、写在前面 关于源码的下载,以及在KEIL工程里面添加操作系统的源代码,这里就不再赘述了。需要注意的是RT-thread默认里面是会使用串口的,因此需要额外的进行串口的初始化,有些人可能会问,为什么不直接使用CubMAX直接…...
Shodan Dorks安装指南,通过Shodan搜索漏洞
Shodan Dorks是一种基于Shodan的工具,不知道Shodan是什么的不必阅读下面的内容。简单的说就是,利用预定义的查询(dorks),通过Shodan轻松搜索漏洞和机密信息。 推荐渗透测试人员自行测试。 安装方法: 1.确…...
poi在word中打开本地文件
poi版本 5.2.0 方法1:使用XWPFFieldRun(推荐) 比如打开当前相对路径的aaaaa.docx XWPFFieldRun run paragraph.createFieldRun();CTRPr ctrPr run.getCTR().addNewRPr();CTFonts font ctrPr.addNewRFonts();// 设置字体font.setAscii(&quo…...
Linux查看服务器的内外网地址
目录: 1、内网地址2、外网地址3、ping时显示地址与真实不一致 1、内网地址 ifconfig2、外网地址 curl ifconfig.me3、ping时显示地址与真实不一致 原因是dns缓存导致的,ping这种方法也是不准确的,有弊端不建议使用,只适用于测试…...
OAuth1和OAuth2授权协议
OAuth 1 授权协议 1. 概述 OAuth1 是 OAuth 标准的第一个正式版本,它通过 签名和令牌 的方式,实现用户授权第三方访问其资源的功能。在 OAuth1 中,安全性依赖于签名机制,无需传递用户密码。 2. 核心特性 使用 签名(…...
DeepSeek学术题目选择效果怎么样?
论文选题 一篇出色的论文背后,必定有一个“智慧的选题”在撑腰。选题足够好文章就能顺利登上高水平期刊;选题不行再精彩的写作也只能“当花瓶”。然而许多宝子们常常忽视这个环节,把大量时间花在写作上,选题时却像抓阄一样随便挑一…...
数据结构(一)顺序表和链表
目录 1. 时间复杂度和空间复杂度 2. 顺序表 3. 链表 1. 时间复杂度和空间复杂度 如何估算一个算法的效率高低一般就是使用到时间复杂度和空间复杂度; 时间复杂度是评价一个算法运行快慢的, 而空间复杂度是算法额外需要空间大小. 1.1 时间复杂度的计算: 准确来说时间复杂度是…...
单相可控整流电路——单相桥式全控整流电路
以下是关于单相桥式整流电路的介绍: 电路构成(带阻性负载的工作情况) - 二极管:是电路0的核心元件,通常采用四个同型号或根据需求选择不同型号的二极管,如1N4001、1N4007等,如图Vt1和Vt4是一对…...
DeepSeek-R1:性能对标 OpenAI,开源助力 AI 生态发展
DeepSeek-R1:性能对标 OpenAI,开源助力 AI 生态发展 在人工智能领域,大模型的竞争一直备受关注。最近,DeepSeek 团队发布了 DeepSeek-R1 模型,并开源了模型权重,这一举动无疑为 AI 领域带来了新的活力。今…...
【Maui】提示消息的扩展
文章目录 前言一、问题描述二、解决方案三、软件开发(源码)3.1 消息扩展库3.2 消息提示框使用3.3 错误消息提示使用3.4 问题选择框使用 四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移…...
001 mybatis入门
文章目录 mybatis是什么ORM是什么ORM框架和MyBatis的区别#{}和${}的区别编码流程UserDaoImpl.javaUserDao.javaUser.javadb.propertiesSqlMapConfig.xmlUserMapper.xmlMybatisTest.javapom.xmluser.sql 表现层 SpringMVC 业务层 Spring 持久层 Mybatis https://mybatis.org/myb…...
tomcat的accept-count、max-connections、max-threads三个参数的含义
tomcat的accept-count、max-connections、max-threads三个参数的含义 tomcat的accept-count、max-connections、max-threads三个参数的含义 max-connections:最大连接数 最大连接数是指,同一时刻,能够连接的最大请求数 需要注意的是&#x…...
8.2 从看图识字到智能解读:GPT-4 with Vision 开启多模态 AI 新纪元
从看图识字到智能解读:GPT-4 with Vision 开启多模态 AI 新纪元 引言:AI 的多模态跃迁 随着人工智能技术的快速发展,我们正迈入一个新的智能交互时代。传统的 AI 模型主要聚焦于文本处理,而多模态 AI 模型如 GPT-4 with Vision(GPT-4V) 则能够同时处理图像和文本。GPT-4…...
.strip()用法
.strip("") 是 Python 字符串方法 strip() 的一个用法,它会去除字符串两端指定字符集中的字符。 基本语法: string.strip([chars])string: 这是你要操作的字符串。chars: 可选参数,表示你想要去除的字符集(默认为空格…...
蓝桥杯例题三
无论前方困难如何重重,我们都要坚定信念,勇往直前。面对挑战和困境,不要退缩,不要放弃,要坚持走下去。当我们感到疲惫时,要告诉自己:“我可以,我一定行!”相信自己的实力…...
关于pygame窗口输入法状态异常切换现象的分析报告
一、问题描述 1.1 需求说明 我们准备使用Pygame开发一个键盘输入测试程序,需要确保输入时窗口始终处于英文输入模式,也就是禁止中文输入; 1.2 现象描述 控制台种显示,程序在初始化时,会有两次IMM状态切换操作&…...
【JavaEE进阶】应用分层
目录 🎋序言 🍃什么是应用分层 🎍为什么需要应用分层 🍀如何分层(三层架构) 🎄MVC和三层架构的区别和联系 🌳什么是高内聚低耦合 🎋序言 通过上⾯的练习,我们学习了SpringMVC简单功能的开…...
两数相加:链表操作的基础与扩展
两数相加:链表操作的基础与扩展 引言 链表(Linked List)是一种灵活且高效的数据结构,特别适用于动态增删操作。无论是初学者还是资深程序员,链表的基本操作都是算法学习中的重要一环。而 “两数相加” 问题则是链表操…...
ChatGPT从数据分析到内容写作建议相关的46个提示词分享!
在当今快节奏的学术环境中,研究人员面临着海量的信息和复杂的研究任务。幸运的是,随着人工智能技术的发展,像ChatGPT这样的先进工具为科研人员提供了强大的支持。今天就让我们一起探索如何利用ChatGPT提升研究效率进一步优化研究流程。 ChatG…...
解析“in the wild”——编程和生活中的俚语妙用
解析“in the wild”——编程和生活中的俚语妙用 看下面的技术文章中遇到 in the wild这个词,想要研究一下,遂产生此文。 Are there ever pointers to pointers to pointers? There is an old programming joke which says you can rate C programmers…...
rocketmq原理源码分析之控制器模式- dledger
简介 RocketMQ 4.5 版本之前,RocketMQ 的broker是 Master/Slave部署架构,一组 broker 有一个 Master ,有0到若干Slave,Slave复制Master消息存储,随时替代下线的Master。Master/Slave部署架构提供一定的高可用性&#x…...
Hello Moto
“Hello Moto” 是摩托罗拉(Motorola)的一句经典广告口号,用于推广其品牌和产品,特别是在手机领域。以下是它的含义和背景: 1. 品牌宣传的标志性语句 直白含义:简单地向摩托罗拉打招呼(“Hell…...
存储基础 -- SCSI命令格式与使用场景
SCSI命令格式与使用场景 1. SCSI命令描述符块(CDB) 1.1 CDB基本概念 SCSI命令通过**命令描述符块(CDB, Command Descriptor Block)**表示。 CDB长度:SCSI命令根据使用场景有不同长度的CDB,常见的有6字节…...
ceph基本概念,架构,部署(一)
一、分布式存储概述 1.存储分类 存储分为封闭系统的存储和开放系统的存储,而对于开放系统的存储又被分为内置存储和外挂存储。 外挂存储又被细分为直连式存储(DAS)和网络存储(FAS),而网络存储又被细分网络接入存储(NAS)和存储区域网络(SAN)等。 DAS(D…...
CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)
CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据) 目录 CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)预测效果基本介绍CNN-GRU卷积门控循环单元时间序列预测一、引言1.1、研究背景与意义1.2、研究现状1…...
Ubuntu 顶部状态栏 配置,gnu扩展程序
顶部状态栏 默认没有配置、隐藏的地方 安装使用Hide Top Bar 或Just Perfection等进行配置 1 安装 sudo apt install gnome-shell-extension-manager2 打开 安装的“扩展管理器” 3. 对顶部状态栏进行配置 使用Hide Top Bar 智能隐藏,或者使用Just Perfection 直…...
React应用深度优化与调试实战指南
一、渲染性能优化进阶 1.1 精细化渲染控制 typescript 复制 // components/HeavyComponent.tsx import React, { memo, useMemo } from react;interface Item {id: string;complexData: {// 复杂嵌套结构}; }const HeavyComponent memo(({ items }: { items: Item[] }) &g…...
Spring中的事件和事件监听器是如何工作的?
目录 一、事件(Event) 二、事件发布器(Event Publisher) 三、事件监听器(Event Listener) 四、使用场景 五、总结 以下是关于Spring中的事件和事件监听器的介绍与使用说明,结合了使用场景&…...
Vue.js组件开发-实现多个文件附件压缩下载
在 Vue 项目中实现多个附件压缩下载,可以借助 jszip 库来创建压缩文件,以及 file-saver 库来保存生成的压缩文件。 步骤 1:安装依赖 首先,在 Vue 项目中安装 jszip 和 file-saver: npm install jszip file-saver步骤…...
基于dlib/face recognition人脸识别推拉流实现
目录 一.环境搭建 二.推拉流代码 三.人脸检测推拉流 一.环境搭建 1.下载RTSP服务器MediaMTX与FFmpeg FFmpeg是一款功能强大的开源多媒体处理工具,而MediaMTX则是一个轻量级的流媒体服务器。两者结合,可以实现将本地视频或者实时摄像头画面推送到RTSP流,从而实现视频…...
qt QNetworkRequest详解
1、概述 QNetworkRequest是Qt网络模块中的一个核心类,专门用于处理网络请求。它封装了网络请求的所有关键信息,包括请求的URL、HTTP头部信息等,使得开发者能够方便地在Qt应用程序中执行网络操作,如文件下载、网页内容获取等。QNe…...
uvm timeout的哪些事
如下图所示,设置timeout并未生效,原因多了一个空格,坑 进一步分析,默认是overidable的 是否加括号呢,如下所示,这两个造型都可以,中间有空格也行 那么,我加上单位可以吗,…...
JavaScript赋能智能网页设计
构建AI驱动的实时风格迁移系统 案例概述 本案例将实现一个基于深度学习的实时图像风格迁移系统,通过浏览器端神经网络推理实现以下高级特性: WebAssembly加速的ONNX模型推理 WebGL Shader实现的风格混合算法 WebRTC实时视频流处理 基于Web Workers的…...
全面了解 Web3 AIGC 和 AI Agent 的创新先锋 MelodAI
不管是在传统领域还是 Crypto,AI 都是公认的最有前景的赛道。随着数字内容需求的爆炸式增长和技术的快速迭代,Web3 AIGC(AI生成内容)和 AI Agent(人工智能代理)正成为两大关键赛道。 AIGC 通过 AI 技术生成…...
leetcode_链表 234.回文链表
234.回文链表 给你一个单链表的头节点head,请你判断该链表是否为回文链表。如果是, 返回 true ; 否则, 返回false。思路: 找到中间节点(快慢指针法)反转后半部分的链表比较前半部分和后半部分链表 # Definition for singly-linked list. # class List…...
cloc下载和使用
cloc(Count Lines of Code)是一个跨平台的命令行工具,用于计算代码行数。以下是下载和使用 cloc 的步骤: 下载 cloc 对于 Windows 用户: 访问 cloc 的 GitHub 仓库:https://github.com/AlDanial/cloc在 …...
在 Windows 系统上,将 Ubuntu 从 C 盘 迁移到 D 盘
在 Windows 系统上,如果你使用的是 WSL(Windows Subsystem for Linux)并安装了 Ubuntu,你可以将 Ubuntu 从 C 盘 迁移到 D 盘。迁移过程涉及导出当前的 Ubuntu 发行版,然后将其导入到 D 盘的目标目录。以下是详细的步骤…...
【Redis】Redis入门以及什么是分布式系统{Redis引入+分布式系统介绍}
文章目录 介绍redis的引入 分布式系统单机架构应用服务和数据库服务分离【负载均衡】引入更多的应用服务器节点 单机架构 分布式是什么 数据库分离和负载均衡 理解负载均衡 数据库读写分离 引入缓存 数据库分库分表 引入微服务 介绍 The open source, in-memory data store us…...
wow-agent---task4 MetaGPT初体验
先说坑: 1.使用git clone模式安装metagpt 2.模型尽量使用在线模型或本地高参数模型。 这里使用python3.10.11调试成功 一,安装 安装 | MetaGPT,参考这里的以开发模型进行安装 git clone https://github.com/geekan/MetaGPT.git cd /you…...