计算机图形学实验练习(实验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个不同的命令,可以用于设置所需的对象、图像和操…...

JWT实现单点登录
文章目录 JWT实现单点登录JWT 简介存在问题及解决方案登录流程后端程序实现前端保存Tokenstore存放信息的缺点及解决 校验流程:为gateway增加登录校验拦截器 另一种单点登录方法:Token+Redis实现单点登录 JWT实现单点登录 登录流程ÿ…...
云计算的概念与特点:开启数字化时代的新篇章
在当今数字化时代,云计算(Cloud Computing)已经成为推动技术创新和业务转型的核心力量。无论是大型企业、中小型企业,还是个人用户,云计算都为其提供了高效、灵活和经济的解决方案。本文将深入探讨云计算的概念及其核心特点,帮助读者全面了解这一革命性技术。 © ivw…...
salesforce中如何获取一个profile的18位id
在 Salesforce 中,要获取一个 Profile 的 18 位 ID,可以通过以下几种方式实现: 方法 1:通过 Developer Console 登录 Salesforce。 点击右上角的 头像 或 设置齿轮,选择 “开发者控制台”(Developer Conso…...
Vue 3 中的标签 ref 与 defineExpose:模板引用与组件暴露
在 Vue 3 中,ref 不仅可以用于创建响应式数据,还可以用于获取 DOM 节点或组件实例。通过 ref,我们可以直接访问模板中的元素或组件,并在需要时操作它们。此外,defineExpose 用于在 <script setup> 语法中显式暴露…...

FLTK - FLTK1.4.1 - demo - adjuster.exe
文章目录 FLTK - FLTK1.4.1 - demo - adjuster.exe概述笔记根据代码,用fluid重建一个adjuster.fl 备注 - fluid生成的代码作为参考代码好了修改后可用的代码END FLTK - FLTK1.4.1 - demo - adjuster.exe 概述 想过一遍 FLTK1.4.1的demo和测试工程,工程…...

单路由及双路由端口映射指南
远程登录总会遇到登陆不上的情况,可能是访问的大门没有打开哦,下面我们来看看具体是怎么回事? 当软件远程访问时,主机需要两个条件,一是有一个唯一的公网IP地址(运营商提供),二是开…...
专为课堂打造:宏碁推出三款全新耐用型 Chromebook
IT之家 1 月 25 日消息,宏碁(Acer)昨日(1 月 24 日)发布公告,针对教育市场,推出 Chromebook Spin 512 (R857T)、Chromebook Spin 511 (R757T) 和 Chromebook 511 (C737) 三款产品,兼…...

云计算架构学习之LNMP架构部署、架构拆分、负载均衡-会话保持
一.LNMP架构部署 1.1. LNMP服务搭建 1.磁盘信息 2.内存 3.负载信息 4.Nginx你们公司都用来干嘛 5.文件句柄(文件描述符 打开文件最大数量) 6.你处理过系统中的漏洞吗 SSH漏洞 7.你写过什么shell脚本 8.监控通过什么告警 zabbix 具体监控哪些内容 9.mysql redis查询 你好H…...

Python案例--暂停与时间格式化
在编程中,时间的处理是一个常见的需求。无论是日志记录、任务调度还是数据时间戳的生成,正确地获取和格式化时间都至关重要。Python 提供了强大的时间处理模块,其中 time 模块是基础且广泛使用的工具之一。本文将通过一个简单的示例ÿ…...

【javaweb项目idea版】蛋糕商城(可复用成其他商城项目)
该项目虽然是蛋糕商城项目,但是可以复用成其他商城项目或者购物车项目 想要源码的uu可点赞后私聊 技术栈 主要为:javawebservletmvcc3p0idea运行 功能模块 主要分为用户模块和后台管理员模块 具有商城购物的完整功能 基础模块 登录注册个人信息编辑…...

git gui 笔记
这里写目录标题 1. [下载安装git](https://blog.csdn.net/jiesunliu3215/article/details/111559125)2. [下载Git Gui](https://git-scm.com/downloads)3. 上传下载代码4. 创建版本5. 版本切换-checkout参考狂神说 git教程 -讲的是真的好gitee的git帮助 其他 1. 下载安装git 2…...
使用 Docker 运行 Oracle Database 23ai Free 容器镜像并配置密码与数据持久化
使用 Docker 运行 Oracle Database 23ai Free 容器镜像并配置密码与数据持久化 前言环境准备运行 Oracle Database 23ai Free 容器基本命令参数说明示例 注意事项高级配置参数说明 总结 前言 Oracle Database 23ai Free 是 Oracle 提供的免费版数据库,基于 Oracle …...

PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(下.代码部分)
医疗 MLLM 框架编程实现 本医疗 MLLM 框架结合 Python 与 PyQt6 构建,旨在实现多模态医疗数据融合分析并提供可视化界面。下面从数据预处理、模型构建与训练、可视化界面开发、模型 - 界面通信与部署这几个关键部分详细介绍编程实现。 6.1 数据预处理 在医疗 MLLM 框架中,多…...
salesforce公式字段 ISBLANK 函数和 <> NULL的区别
在 Salesforce 公式字段中,ISBLANK 函数和 <> NULL 的作用都可以用来检查字段是否有值,但它们的行为有一些显著的区别。以下是它们的详细对比和适用场景: 1. 基本区别 功能ISBLANK<> NULL主要作用检查字段是否为空(适…...

微服务学习-服务调用组件 OpenFeign 实战
1. OpenFeign 接口方法编写规范 1.1. 在编写 OpenFeign 接口方法时,需要遵循以下规范 1.1.1.1. 接口中的方法必须使用 RequestMapping、GetMapping、PostMapping 等注解声明 HTTP 请求的类型。 1.1.1.2. 方法的参数可以使用 RequestParam、RequestHeader、PathVa…...

关于安卓greendao打包时报错问题修复
背景 项目在使用greendao的时候,debug安装没有问题,一到打包签名就报了。 环境 win10 jdk17 gradle8 项目依赖情况 博主的greendao是一个独立的module项目,项目目前只适配了java,不支持Kotlin。然后被外部集成。greendao版本…...

Ansible自动化运维实战--通过role远程部署nginx并配置(8/8)
文章目录 1、准备工作2、创建角色结构3、编写任务4、准备配置文件(金甲模板)5、编写变量6、编写处理程序7、编写剧本8、执行剧本Playbook9、验证-游览器访问每台主机的nginx页面 在 Ansible 中,使用角色(Role)来远程部…...

RGB 转HSV空间颜色寻找色块
文章目录 前言一、绿色确定二、红色确定总结 前言 提示:这里可以添加本文要记录的大概内容: 项目需要: 将RGB颜色空间转换为HSV颜色空间以寻找颜色,主要基于以下几个原因: 直观性: HSV颜色空间更符合人类…...

Spring Boot - 数据库集成04 - 集成Redis
Spring boot集成Redis 文章目录 Spring boot集成Redis一:redis基本集成1:RedisTemplate Jedis1.1:RedisTemplate1.2:实现案例1.2.1:依赖引入和属性配置1.2.2:redisConfig配置1.2.3:基础使用 2&…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...