【OpenGL实践10】关于几何着色器

目录

一、说明

二、几何着色器

2.1 设置

2.2 基本几何着色器

2.2.1 输入类型

2.2.2 输出类型

2.2.3 顶点输入

2.2.4 顶点输出

2.3 创建几何着色器

2.4 几何着色器和顶点属性

三、动态生成几何体

四、结论

练习


一、说明

        几何着色器的应用比较高级,关于几何着色器使用究竟需要什么样的步骤,几何着色器能解决什么样的问题。需要示范案例,本文将演示这个过程。

二、几何着色器

        到目前为止,我们已经使用顶点和片段着色器将输入顶点转换为屏幕上的像素。从 OpenGL 3.2 开始,顶点和片段着色器之间还有第三种可选着色器,称为几何着色 。此着色器具有独特的能力,可以使用顶点着色器的输出作为输入,动态创建新的几何体。

        由于我们忽视前几章中的小猫太久了,它跑到了新家。这给了我们一个重新开始的好机会。在本章的最后,我们将有以下演示:

        这看起来并不那么令人兴奋......直到您认为上面的结果是通过一次绘制调用生成的:

glDrawArrays(GL_POINTS, 0, 4);

        请注意,几何着色器可以做的所有事情都可以通过其他方式完成,但它们从少量输入数据生成几何体的能力允许您减少 CPU -> GPU 带宽使用。

2.1 设置

        让我们首先编写一些简单的代码,仅在屏幕上绘制 4 个红点。

// Vertex shader
const char* vertexShaderSrc = R"glsl(#version 150 corein vec2 pos;void main(){gl_Position = vec4(pos, 0.0, 1.0);}
)glsl";// Fragment shader
const char* fragmentShaderSrc = R"glsl(#version 150 coreout vec4 outColor;void main(){outColor = vec4(1.0, 0.0, 0.0, 1.0);}
)glsl";

        我们首先在文件顶部声明两个非常简单的顶点和片段着色器。顶点着色器只是转发每个点的位置属性,而片段着色器始终输出红色。那里没什么特别的。

        我们还添加一个辅助函数来创建和编译着色器:

GLuint createShader(GLenum type, const GLchar* src) {GLuint shader = glCreateShader(type);glShaderSource(shader, 1, &src, nullptr);glCompileShader(shader);return shader;
}

        在该main函数中,使用选择的库创建一个窗口和 OpenGL 上下文并初始化 GLEW。着色器并编译和激活:

GLuint vertexShader = createShader(GL_VERTEX_SHADER, vertexShaderSrc);
GLuint fragmentShader = createShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);

        之后,创建一个保存点坐标的缓冲区:

GLuint vbo;
glGenBuffers(1, &vbo);float points[] = {-0.45f,  0.45f,0.45f,  0.45f,0.45f, -0.45f,-0.45f, -0.45f,
};glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

        我们这里有 4 个点,每个点都有 x 和 y 设备坐标。请记住,设备坐标从左到右、从下到上的屏幕坐标范围为 -1 到 1,因此每个角都有一个点。

        然后创建一个VAO并设置顶点格式规范:

// Create VAO
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);// Specify layout of point data
GLint posAttrib = glGetAttribLocation(shaderProgram, "pos");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);

        最后是渲染循环:

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);glDrawArrays(GL_POINTS, 0, 4);

        使用此代码,您现在应该在黑色背景上看到 4 个红点,如下所示:

如果您遇到问题,请查看参考源代码。

2.2 基本几何着色器

        要了解几何着色器的工作原理,让我们看一个示例:

#version 150 corelayout(points) in;
layout(line_strip, max_vertices = 2) out;void main()
{gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0);EmitVertex();gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);EmitVertex();EndPrimitive();
}

2.2.1 输入类型

        顶点着色器处理顶点,片段着色器处理片段,而几何着色器处理整个图元。第一行描述了我们的着色器应该处理什么样的基元。

layout(points) in;

        下面列出了可用的类型及其等效的绘图命令类型:

  • - GL_POINTS(1 个顶点)
  • 线- GL_LINES、GL_LINE_STRIP、GL_LINE_LIST(2 个顶点)
  • lines_adjacency - GL_LINES_ADJACENCY、GL_LINE_STRIP_ADJACENCY(4 个顶点)
  • 三角形- GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN(3 个顶点)
  • triangles_adjacency - GL_TRIANGLES_ADJACENCY、GL_TRIANGLE_STRIP_ADJACENCY(6 个顶点)

        由于我们正在绘图GL_POINTS,因此points类型是合适的。

2.2.2 输出类型

        下一行描述着色器的输出。几何着色器的有趣之处在于它们可以输出完全不同类型的几何形状,并且生成的图元数量甚至可以变化!

layout(line_strip, max_vertices = 2) out;

        第二行指定输出类型及其可以传递的最大顶点数。这是着色器调用的最大数量,而不是单个图元(line_strip在本例中)的最大数量。

可以使用以下输出类型:

  • 线带
  • 三角形带

        这些类型看起来有些受限,但如果你仔细想想,这些类型足以涵盖所有可能的图元类型。例如,只有 3 个顶点的三角形条带相当于一个正三角形。

2.2.3 顶点输入

  gl_Position可以使用几何着色器中的数组来访问在顶点着色器中设置 的gl_in。它是一个结构数组,如下所示:

in gl_PerVertex
{vec4 gl_Position;float gl_PointSize;float gl_ClipDistance[];
} gl_in[];

        请注意,诸如pos和 之类的顶点属性color不包括在内,我们稍后将考虑访问这些属性。

2.2.4 顶点输出

        几何着色器程序可以调用两个特殊函数来生成图元,EmitVertexEndPrimitive。每次程序调用 时 EmitVertex,都会将一个顶点添加到当前图元中。添加完所有顶点后,程序将调用EndPrimitive生成图元。

void main()
{gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0);EmitVertex();gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);EmitVertex();EndPrimitive();
}

        在调用之前EmitVertex,应将顶点的属性分配给诸如 之类的变量gl_Position,就像在顶点着色器中一样。稍后我们将讨论如何设置color片段着色器等属性。

        现在您知道了每条线的含义,您能解释一下这个几何着色器的作用吗?

它为传递给它的每个点坐标创建一条水平线。

2.3 创建几何着色器

        没有太多需要解释的,几何着色器的创建和激活方式与其他类型的着色器完全相同。让我们向 4 点示例添加一个尚未执行任何操作的几何着色器。

const char* geometryShaderSrc = R"glsl(#version 150 corelayout(points) in;layout(points, max_vertices = 1) out;void main(){gl_Position = gl_in[0].gl_Position;EmitVertex();EndPrimitive();}
)glsl";

        这个几何着色器应该相当简单。对于每个输入点,它生成一个等效的输出点。这是在屏幕上显示点所需的最少代码量。

        使用辅助函数,创建几何着色器很容易:

GLuint geometryShader = createShader(GL_GEOMETRY_SHADER, geometryShaderSrc);

        将其附加到着色器程序也没有什么特别的:

glAttachShader(shaderProgram, geometryShader);

        当您现在运行该程序时,它应该仍然像以前一样显示点。您可以通过从其函数中删除代码来验证几何着色器现在是否正在执行其工作main。您将看到不再绘制任何点,因为没有生成任何点!

        现在,尝试用上一节中的线带生成代码替换几何着色器代码:

#version 150 corelayout(points) in;
layout(line_strip, max_vertices = 2) out;void main()
{gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0);EmitVertex();gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);EmitVertex();EndPrimitive();
}

        即使我们没有对绘制调用进行任何更改,GPU 也会突然绘制细线而不是点!

        尝试做一些实验来感受一下。例如,尝试使用输出矩形triangle_strip

2.4 几何着色器和顶点属性

        让我们为正在绘制的线条添加一些变化,让每条线条都具有独特的颜色。通过向顶点着色器添加颜色输入变量,我们可以指定每个顶点的颜色,从而指定每个生成线的颜色。

#version 150 corein vec2 pos;
in vec3 color;out vec3 vColor; // Output to geometry (or fragment) shadervoid main()
{gl_Position = vec4(pos, 0.0, 1.0);vColor = color;
}

        更新程序代码中的顶点规范:

GLint posAttrib = glGetAttribLocation(shaderProgram, "pos");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE,5 * sizeof(float), (void*) (2 * sizeof(float)));

        并更新点数据以包含每个点的 RGB 颜色:

float points[] = {-0.45f,  0.45f, 1.0f, 0.0f, 0.0f, // Red point0.45f,  0.45f, 0.0f, 1.0f, 0.0f, // Green point0.45f, -0.45f, 0.0f, 0.0f, 1.0f, // Blue point-0.45f, -0.45f, 1.0f, 1.0f, 0.0f, // Yellow point
};

        因为顶点着色器现在后面不是片段着色器,而是几何着色器,所以我们必须将变量vColor作为输入处理。

#version 150 corelayout(points) in;
layout(line_strip, max_vertices = 2) out;in vec3 vColor[]; // Output from vertex shader for each vertexout vec3 fColor; // Output to fragment shadervoid main()
{...

        您可以看到它与片段着色器中处理输入的方式非常相似。唯一的区别是输入现在必须是数组,因为几何着色器可以接收具有多个顶点的图元作为输入,每个顶点都有自己的属性值。

        由于颜色需要进一步向下传递到片段着色器,因此我们将其添加为几何着色器的输出。我们现在可以为其赋值,就像我们之前对gl_Position.

void main()
{fColor = vColor[0]; // Point has only one vertexgl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.1, 0.0, 0.0);EmitVertex();gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.1, 0.0, 0.0);EmitVertex();EndPrimitive();
}

        每当EmitVertex调用 now 时,都会发出一个fColor带有颜色属性当前值的顶点。我们现在可以在片段着色器中访问该属性:

#version 150 corein vec3 fColor;out vec4 outColor;void main()
{outColor = vec4(fColor, 1.0);
}

        因此,当您为顶点指定属性时,它首先会作为输入传递给顶点着色器。然后顶点着色器可以选择将其输出到几何着色器。然后几何着色器可以选择进一步输出到片段着色器。

        然而,这个演示并不是很有趣。我们可以通过使用单行创建顶点缓冲区并发出几个使用统一变量设置的不同颜色和位置的绘制调用来轻松复制此行为。

三、动态生成几何体

        几何着色器的真正威力在于能够生成不同数量的图元,因此让我们创建一个正确滥用此功能的演示。

        假设您正在制作一款世界由圆圈组成的游戏。您可以绘制一个圆形模型并重复绘制它,但这种方法并不理想。如果距离太近,这些“圆圈”看起来会像丑陋的多边形,如果距离太远,显卡就会在渲染复杂性上浪费性能,而您甚至看不到。

        我们可以使用几何着色器做得更好!我们可以编写一个着色器,根据运行时条件生成适当的分辨率圆。我们首先修改几何着色器以在每个点绘制一个 10 边形多边形。如果你还记得你的三角函数,那么它应该是小菜一碟:

#version 150 corelayout(points) in;
layout(line_strip, max_vertices = 11) out;in vec3 vColor[];
out vec3 fColor;const float PI = 3.1415926;void main()
{fColor = vColor[0];for (int i = 0; i <= 10; i++) {// Angle between each side in radiansfloat ang = PI * 2.0 / 10.0 * i;// Offset from center of point (0.3 to accomodate for aspect ratio)vec4 offset = vec4(cos(ang) * 0.3, -sin(ang) * 0.4, 0.0, 0.0);gl_Position = gl_in[0].gl_Position + offset;EmitVertex();}EndPrimitive();
}

        重复第一个点以闭合线循环,这就是绘制 11 个顶点的原因。结果如预期:

        现在添加顶点属性来控制边数很简单。将新属性添加到数据和规范中:

float points[] = {
//  Coordinates  Color             Sides-0.45f,  0.45f, 1.0f, 0.0f, 0.0f,  4.0f,0.45f,  0.45f, 0.0f, 1.0f, 0.0f,  8.0f,0.45f, -0.45f, 0.0f, 0.0f, 1.0f, 16.0f,-0.45f, -0.45f, 1.0f, 1.0f, 0.0f, 32.0f
};...// Specify layout of point data
GLint posAttrib = glGetAttribLocation(shaderProgram, "pos");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE,6 * sizeof(float), 0);GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE,6 * sizeof(float), (void*) (2 * sizeof(float)));GLint sidesAttrib = glGetAttribLocation(shaderProgram, "sides");
glEnableVertexAttribArray(sidesAttrib);
glVertexAttribPointer(sidesAttrib, 1, GL_FLOAT, GL_FALSE,6 * sizeof(float), (void*) (5 * sizeof(float)));

        更改顶点着色器以将值传递给几何着色器:

#version 150 corein vec2 pos;
in vec3 color;
in float sides;out vec3 vColor;
out float vSides;void main()
{gl_Position = vec4(pos, 0.0, 1.0);vColor = color;vSides = sides;
}

        并使用几何着色器中的变量而不是幻数边数 10.0。还需要max_vertices为我们的输入设置适当的值,否则具有更多顶点的圆将被切断。

layout(line_strip, max_vertices = 64) out;...in float vSides[];...// Safe, floats can represent small integers exactly
for (int i = 0; i <= vSides[0]; i++) {// Angle between each side in radiansfloat ang = PI * 2.0 / vSides[0] * i;...

        现在,您只需添加更多点即可创建具有任意边数的圆!

        如果没有几何着色器,每当这些圆中的任何一个需要更改时,我们就必须重建整个顶点缓冲区,现在我们可以简单地更改顶点属性的值。在游戏设置中,该属性可以根据玩家距离而改变,如上所述。您可以在此处找到完整的代码。

四、结论

        诚然,几何着色器可能没有像帧缓冲区和纹理等那样多的现实世界用例,但它们绝对可以帮助在 GPU 上创建内容,如此处所示。

        如果您需要多次重复单个网格(例如体素游戏中的立方体),您可以创建一个几何着色器,以类似的方式从点生成立方体。然而,对于每个生成的网格完全相同的情况,有更有效的方法,例如实例化代码(实例化代码)。

        最后,关于可移植性,最新的 WebGL 和 OpenGL ES 标准尚不支持几何着色器,因此如果您正在考虑开发移动或 Web 应用程序,请记住这一点。

实例化代码:

// Link statically with GLEW
#define GLEW_STATIC// Headers
#include <GL/glew.h>
#include <SFML/Window.hpp>// Vertex shader
const GLchar* vertexShaderSrc = R"glsl(#version 150 corein vec2 pos;in vec3 color;in float sides;out vec3 vColor;out float vSides;void main(){gl_Position = vec4(pos, 0.0, 1.0);vColor = color;vSides = sides;}
)glsl";// Geometry shader
const GLchar* geometryShaderSrc = R"glsl(#version 150 corelayout(points) in;layout(line_strip, max_vertices = 64) out;in vec3 vColor[];in float vSides[];out vec3 fColor;const float PI = 3.1415926;void main(){fColor = vColor[0];// Safe, GLfloats can represent small integers exactlyfor (int i = 0; i <= vSides[0]; i++) {// Angle between each side in radiansfloat ang = PI * 2.0 / vSides[0] * i;// Offset from center of point (0.3 to accomodate for aspect ratio)vec4 offset = vec4(cos(ang) * 0.3, -sin(ang) * 0.4, 0.0, 0.0);gl_Position = gl_in[0].gl_Position + offset;EmitVertex();}EndPrimitive();}
)glsl";// Fragment shader
const GLchar* fragmentShaderSrc = R"glsl(#version 150 corein vec3 fColor;out vec4 outColor;void main(){outColor = vec4(fColor, 1.0);}
)glsl";// Shader creation helper
GLuint createShader(GLenum type, const GLchar* src) {GLuint shader = glCreateShader(type);glShaderSource(shader, 1, &src, nullptr);glCompileShader(shader);return shader;
}int main()
{sf::ContextSettings settings;settings.depthBits = 24;settings.stencilBits = 8;settings.majorVersion = 3;settings.minorVersion = 2;sf::Window window(sf::VideoMode(800, 600, 32), "Circles", sf::Style::Titlebar | sf::Style::Close, settings);// Initialize GLEWglewExperimental = GL_TRUE;glewInit();// Compile and activate shadersGLuint vertexShader = createShader(GL_VERTEX_SHADER, vertexShaderSrc);GLuint geometryShader = createShader(GL_GEOMETRY_SHADER, geometryShaderSrc);GLuint fragmentShader = createShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);GLuint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, geometryShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);glUseProgram(shaderProgram);// Create VBO with point coordinatesGLuint vbo;glGenBuffers(1, &vbo);GLfloat points[] = {//  Coordinates     Color             Sides-0.45f,  0.45f, 1.0f, 0.0f, 0.0f,  4.0f,0.45f,  0.45f, 0.0f, 1.0f, 0.0f,  8.0f,0.45f, -0.45f, 0.0f, 0.0f, 1.0f, 16.0f,-0.45f, -0.45f, 1.0f, 1.0f, 0.0f, 32.0f};glBindBuffer(GL_ARRAY_BUFFER, vbo);glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);// Create VAOGLuint vao;glGenVertexArrays(1, &vao);glBindVertexArray(vao);// Specify the layout of the vertex dataGLint posAttrib = glGetAttribLocation(shaderProgram, "pos");glEnableVertexAttribArray(posAttrib);glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);GLint colAttrib = glGetAttribLocation(shaderProgram, "color");glEnableVertexAttribArray(colAttrib);glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*) (2 * sizeof(GLfloat)));GLint sidesAttrib = glGetAttribLocation(shaderProgram, "sides");glEnableVertexAttribArray(sidesAttrib);glVertexAttribPointer(sidesAttrib, 1, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*) (5 * sizeof(GLfloat)));bool running = true;while (running){sf::Event windowEvent;while (window.pollEvent(windowEvent)){switch (windowEvent.type){case sf::Event::Closed:running = false;break;}}// Clear the screen to blackglClearColor(0.0f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// Render frameglDrawArrays(GL_POINTS, 0, 4);// Swap bufferswindow.display();}glDeleteProgram(shaderProgram);glDeleteShader(fragmentShader);glDeleteShader(geometryShader);glDeleteShader(vertexShader);glDeleteBuffers(1, &vbo);glDeleteVertexArrays(1, &vao);window.close();return 0;
}

练习

  • 尝试在 3D 场景中使用几何着色器来创建更复杂的网格,例如基于点的立方体。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/13973.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Epson推出的FC2012AN晶体专为小尺寸、低ESR应用设计

在可穿戴设备、loT产品、无线通信模块等领域&#xff0c;对于小型化、低功耗和高精度的时钟需求日益增长。Epson推出的FC2012AN系列晶体单元凭借其小尺寸、低ESR等特性使其成为这些应用的理想选择。 FC2012AN系列是一款32.768K频率的晶体单元&#xff0c;频率偏差为 20x10-6…

【云原生】kubernetes中的service原理、应用实战案例解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

DSPy - prompt 优化

文章目录 一、关于 DSPy与神经网络的类比常见问题解答**DSPy 优化器可以调整什么&#xff1f;****我应该如何使用 DSPy 完成我的任务&#xff1f;****如果我对提示或合成数据生成有更好的想法怎么办&#xff1f;**DSPy 代表什么&#xff1f; 二、安装三、文档A) 教程B) 指南C) …

Python列表推导式:简洁与高效的编程艺术

Python列表推导式&#xff1a;简洁与高效的编程艺术 在Python编程世界中&#xff0c;列表推导式&#xff08;List Comprehension&#xff09;无疑是一个强大而实用的工具。它允许我们以简洁、易读的方式快速生成列表&#xff0c;减少了编写循环和条件语句的需要。本文将详细介…

全球手游4月战报,《Monopoly GO!》荣耀再续!全球手游畅销榜冠军

易采游戏网5月22日消息&#xff0c;在刚刚过去的四月里&#xff0c;全球移动游戏市场的角逐愈发激烈。根据最新发布的数据&#xff0c;Scopely旗下的经典游戏《Monopoly GO!》再次蝉联全球手游畅销榜首冠军宝座&#xff0c;展现了无与伦比的市场魅力与玩家黏度。 4月Scopely《M…

中霖教育怎么样?二建继续教育几年一次?

中霖为大家介绍&#xff1a; 根据相关规定&#xff0c;二级建造师执业资格注册证书设定有效期限为三年。为确保持证人员的专业能力&#xff0c;在规定的期限内需要完成规定的继续教育课程并参加考核&#xff0c;以此来维护其职业资质的连续性。 在执业资格证书的有效期满前&a…

zabbix从6.0.x升级到6.0.x

一、升级原因 这两天安全方面暴露了zabbix的版本漏洞&#xff0c;具体漏洞信息如下&#xff1a; Zabbix Server Audit Log SQL 注入漏洞预警 近日&#xff0c;某机构获取到Zabbix Server组件中修复了一个SQL注入漏洞&#xff08;CVE-2024-22120&#xff09;&#xff0c…

redis小知识

AOF与RDB的区别 AOF (Append Only File) 和 RDB (Redis Database) 都是Redis中的持久化机制&#xff0c;但有以下几点不同之处&#xff1a; 内容格式&#xff1a;AOF 以日志的形式记录所有写操作命令&#xff0c;而 RDB 则是在指定的时间间隔内对数据库进行快照&#xff0c;将数…

WDW-100G 高温拉力试验机 技术方案书

一、整机外观图&#xff1a; 二、项目简介&#xff1a; 微机控制高温拉力试验机是电子技术与机械传动相结合的新型材料试验机&#xff0c;它具有宽广准确的加载速度和测力范围&#xff0c;对载荷、变形、位移的测量和控制有较高的精度和灵敏度&#xff0c;还可以进行等速加载、…

FFmpeg开发笔记(三十)解析H.264码流中的SPS帧和PPS帧

《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书的“2.1.1 音视频编码的发展历程”介绍了H.26x系列的视频编码标准&#xff0c;其中H.264至今仍在广泛使用&#xff0c;无论视频文件还是网络直播&#xff0c;H.264标准都占据着可观的市场份额。 之所以H.264取得了巨大…

CDLinux下载网站

CDlinux - Browse /CDlinux-ISO at SourceForge.net

9.2 字符串拼接

字符串拼接 使用运算符拼接字符串 使用加号""运算符&#xff0c;可将几个较小的字符串拼接成一个更大的字符串&#xff0c;其拼接的前后顺序严格遵循每个字符串在加法表达式中出现的顺序。 s : "北冥有鱼&#xff0c;其名为鲲。"s s 鲲之大&#xff0…

用神经网络预测三角形的面积

周末遛狗时&#xff0c;我想起一个老问题&#xff1a;神经网络能预测三角形的面积吗&#xff1f; 神经网络非常擅长分类&#xff0c;例如根据花瓣长度和宽度以及萼片长度和宽度预测鸢尾花的种类&#xff08;setosa、versicolor 或 virginica&#xff09;。神经网络还擅长一些回…

2024中青杯A题数学建模成品文章数据代码分享

人工智能视域下养老辅助系统的构建 摘要 随着全球人口老龄化的加剧&#xff0c;养老问题已经成为一个世界性的社会问题&#xff0c;对社会各个方面产生了深远影响&#xff0c;包括劳动力市场、医疗保健和养老金制度等。人口结构变化对养老服务的质量和覆盖面提出了更高要求。特…

Python 爬虫编写入门

一、爬虫概述 网络爬虫&#xff08;Web Crawler&#xff09;或称为网络蜘蛛&#xff08;Web Spider&#xff09;&#xff0c;是一种按照一定规则&#xff0c;自动抓取互联网信息的程序或者脚本。它们可以自动化地浏览网络中的信息&#xff0c;通过解析网页内容&#xff0c;提取…

3台机器快速安装ELK集群

安装和配置 Elasticsearch、Kibana 和 Logstash 以下是安装和配置 Elasticsearch、Kibana 和 Logstash 的详细步骤&#xff0c;并设置开机自启。 步骤 1&#xff1a;修改系统参数 编辑系统参数并使其生效&#xff1a; vim /etc/sysctl.conf添加以下行&#xff1a; vm.max_…

Xpath元素定位和三大等待,三大切换

在页面的操作过程当中&#xff0c;都需要适当的等待。特别是&#xff1a; 候【发生了页面切换的时候】。而我们接下来的操作都是在变化的内容上。 代码就要等等页面的加载&#xff0c;等等页面的渲染。代码是非常快的&#xff0c;页面加载跟不 上&#xff0c;就需要等待。 三大…

getaway基本配置

Getaway 是一款用于容器化应用的轻量级 API 网关。它提供了一种简单的方式来管理和路由 API 请求&#xff0c;通常用于微服务架构中。以下是 Getaway 的基本配置指南&#xff0c;包括安装、配置文件示例、以及一些常见的配置选项。 ### 1. 安装 Getaway 通常通过 Docker 容器…

用友开发平台调用审核提示U8授权失败可能原因

U8授权失败可能有多种原因&#xff0c;这里有几个可能的解决方案供您参考&#xff1a; 登录接口未调用&#xff1a;在调用审核接口&#xff08;如audit、abandon、verify、unverify&#xff09;之前&#xff0c;请确保已经调用了登录接口&#xff08;login&#xff09;。如果登…

红队攻防渗透技术实战流程:云安全之云原生安全:K8s安全

红队云攻防实战 1.云原生-K8s安全-名词架构&各攻击点1.1 云原生-K8s安全-概念1.2 云原生-K8s安全-K8S集群架构解释1.2.1 K8s安全-K8S集群架构-Master节点1.2.2 K8s安全-K8S集群架构-Node节点1.2.3 K8s安全-K8S集群架构-Pod容器1.3 云原生安全-K8s安全-K8S集群攻击点 `(重点…