【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) …

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

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

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

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

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

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

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

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

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

ARP基本原理

相关概念 ARP报文 ARP报文分为ARP请求报文和ARP应答报文&#xff0c;报文格式如图1所示。 图1 ARP报文格式 Ethernet Address of destination&#xff08;0–31&#xff09;和Ethernet Address of destination&#xff08;32–47&#xff09;分别表示Ethernet Address of dest…

【算法】前缀和——除自身以外数组的乘积

本节博客是用前缀和算法求解“除自身以外数组的乘积”&#xff0c;有需要借鉴即可。 目录 1.题目2.前缀和算法3.变量求解4.总结 1.题目 题目链接&#xff1a;LINK 2.前缀和算法 1.创建两个数组 第一个数组第i位置表示原数组[0,i-1]之积第二个数组第i位置表示原数组[i1,n-1]…

Hadoop 客户端 FileSystem加载过程

如何使用hadoop客户端 public class testCreate {public static void main(String[] args) throws IOException {System.setProperty("HADOOP_USER_NAME", "hdfs");String pathStr "/home/hdp/shanshajia";Path path new Path(pathStr);Confi…

在DAYU200上实现OpenHarmony跳转拨号界面

一、简介 日常生活中&#xff0c;打电话是最常见的交流方式之一&#xff0c;那么如何在OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;中进行电话服务相关的开发呢&#xff1f;今天我们可以一起来了解一下如何通过电话服务系统支持的API实现拨打电话的功能…

C#-根据日志等级进行日志的过滤输出

文章速览 概要具体实施创建Log系统动态修改日志等级 坚持记录实属不易&#xff0c;希望友善多金的码友能够随手点一个赞。 共同创建氛围更加良好的开发者社区&#xff01; 谢谢~ 概要 方便后期对软件进行维护&#xff0c;需要在一些关键处添加log日志输出&#xff0c;但时间长…

【408精华知识】指令周期的数据流

文章目录 一、取指周期二、间址周期三、执行周期&#xff08;一&#xff09;数据传送类指令(mov/load/store)&#xff08;二&#xff09;运算类指令(加/减/乘/除/移位/与/或)&#xff08;三&#xff09;转移类指令(jmp/jxxx) 四、中断周期 CPU每取出并且执行一条指令所需要的全…

二叉数之插入操作

首先是题目 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 &#xff0c;新值和原始二叉搜索树中的任意节点值都不同。 注意&#xff0c;可能存在多种有效…

AcWing 217:绿豆蛙的归宿 ← 搜索算法

【题目来源】https://www.acwing.com/problem/content/219/【题目描述】 给出一个有向无环的连通图&#xff0c;起点为 1&#xff0c;终点为 N&#xff0c;每条边都有一个长度。 数据保证从起点出发能够到达图中所有的点&#xff0c;图中所有的点也都能够到达终点。 绿豆蛙从起…

Kreon: An Efficient Memory-Mapped Key-Value Store for Flash Storage——论文泛读

TOS 2021 Paper 论文阅读笔记整理 问题 持久的键值存储已经成为现代数据处理系统的数据访问路径中的一个主要组件。然而&#xff0c;它们表现出较高的CPU和I/O开销。 基于LSM Tree的键值存储中两个重要的CPU和I/O开销来源是&#xff1a; 在LSM Tree中使用压缩&#xff0c;不…