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

news2024/11/15 11:46:31

目录

一、说明

二、几何着色器

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 core
    in vec2 pos;

    void main()
    {
        gl_Position = vec4(pos, 0.0, 1.0);
    }
)glsl";

// Fragment shader
const char* fragmentShaderSrc = R"glsl(
    #version 150 core
    out 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 core

layout(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 core

    layout(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 core

layout(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 core

in vec2 pos;
in vec3 color;

out vec3 vColor; // Output to geometry (or fragment) shader

void 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 point
     0.45f,  0.45f, 0.0f, 1.0f, 0.0f, // Green point
     0.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 core

layout(points) in;
layout(line_strip, max_vertices = 2) out;

in vec3 vColor[]; // Output from vertex shader for each vertex

out vec3 fColor; // Output to fragment shader

void main()
{
    ...

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

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

void main()
{
    fColor = vColor[0]; // Point has only one vertex

    gl_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 core

in vec3 fColor;

out vec4 outColor;

void main()
{
    outColor = vec4(fColor, 1.0);
}

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

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

三、动态生成几何体

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

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

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

#version 150 core

layout(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 radians
        float 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 core

in 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 radians
    float 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 core

    in 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 core

    layout(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 exactly
        for (int i = 0; i <= vSides[0]; i++) {
            // Angle between each side in radians
            float 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 core

    in 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 GLEW
    glewExperimental = GL_TRUE;
    glewInit();

    // Compile and activate shaders
    GLuint 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 coordinates
    GLuint 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 VAO
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Specify the layout of the vertex data
    GLint 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 black
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Render frame
        glDrawArrays(GL_POINTS, 0, 4);

        // Swap buffers
        window.display();
    }

    glDeleteProgram(shaderProgram);
    glDeleteShader(fragmentShader);
    glDeleteShader(geometryShader);
    glDeleteShader(vertexShader);

    glDeleteBuffers(1, &vbo);

    glDeleteVertexArrays(1, &vao);

    window.close();

    return 0;
}

练习

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

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

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

相关文章

探索 Rust 语言的精髓:深入 Rust 标准库

探索 Rust 语言的精髓&#xff1a;深入 Rust 标准库 Rust&#xff0c;这门现代编程语言以其内存安全、并发性和性能优势而闻名。它不仅在系统编程领域展现出强大的能力&#xff0c;也越来越多地被应用于WebAssembly、嵌入式系统、分布式服务等众多领域。Rust 的成功&#xff0…

databricks~Unity Catalog

Unity Catalog hierarchy 包含了用户授权管理信息和元数据信息 workspace with unity catalog hierarchy unity metastore Ref: https://www.youtube.com/playlist?listPLY-V_O-O7h4fwcHcXgkR_zTLvddvE_GfC

欢乐钓鱼大师攻略大全,游戏自动辅助,钓鱼大全!

欢迎来到《欢乐钓鱼大师》的攻略大全&#xff01;本文将为你详细介绍游戏中的各类玩法、技巧和注意事项&#xff0c;帮助你快速掌握游戏精髓&#xff0c;成为一名真正的钓鱼大师。攻略内容包括新手鱼竿选择、锦标赛攻略、实用技巧、藏宝图玩法、箱子开法等多个方面。让我们一起…

数字信号处理:matlab解差分方程

1. 验证全响应 %验证全响应零状态响应零输入响应 %y(n)4y(n-1)x(n),其中x(n)δ(n),y(-1)2.clc;%清屏 clear all;%清除所有变量的值 b[1]; a[1,-4]; ys[2]; xs[0];%没有初始值&#xff0c;就是0 xn[1, zeros(1,4)];%输入序列&#xff0c;假设长度是5&#xff0c;则输出长度也是…

人工智能+量子计算:飞跃现实边界还是科技幻想?

人工智能量子计算&#xff0c;这是一种可能改变世界的伙伴关系。 在科技的前沿&#xff0c;两大革命性技术——人工智能&#xff08;AI&#xff09;和量子计算——正站在合作的十字路口。人工智能&#xff0c;以其强大的数据分析能力和模式识别&#xff0c;正在改变着我们生活…

【机器学习与大模型】驱动下的电子商务应用

摘要&#xff1a; 随着信息技术的飞速发展&#xff0c;电子商务已经成为当今商业领域中最为活跃和重要的部分之一。而机器学习和大模型的出现&#xff0c;为电子商务带来了新的机遇和挑战。本文深入探讨了机器学习与大模型在电子商务中的应用&#xff0c;包括个性化推荐、精准营…

第一份工资

当我拿到我人生的第一份工资时&#xff0c;那是一种难以言表的激动。我记得那个下午&#xff0c;阳光透过窗户洒在了我的办公桌上&#xff0c;我看着那张支票&#xff0c;心中满是欣喜和自豪。那是我独立生活的开始&#xff0c;也是我对自己能力的一种肯定。 我记得我是如何支配…

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

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

5分钟在 VSCode 中使用 PlantUML 绘图

去年&#xff0c;写过一篇在 VSCode 中使用 PlantUML 的博客&#xff0c;那时候我嫌弃本地安装麻烦&#xff0c;所以采用的是在本地运行 docker 容器的方法部署的 PlantUML 服务端。不过&#xff0c;现在来看这样还必须依赖在本地手动启动 docker 容器&#xff08;如果有一个不…

【UnityShader入门精要学习笔记】第十四章 非真实感渲染

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 我的GitHub仓库 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 卡通风格渲…

2024年5月24日 十二生肖 今日运势

小运播报&#xff1a;2024年5月24日&#xff0c;星期五&#xff0c;农历四月十七 &#xff08;甲辰年己巳月戊子日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;龙、牛、猴 需要注意&#xff1a;兔、羊、马 喜神方位&#xff1a;东南方 财神方位&#xff1a;…

10个顶级的论文降重指令,让你的论文降重至1.9%

10个顶级的论文降重指令&#xff0c;本硕博写论文必备&#xff01; 在ChatGPT4o对话框中输入&#xff1a;写一个Spring BootVue实现的车位管理系统的论文大纲&#xff0c;并对其具体章节进行详细描述。 几小时即可完成一份1万字论文的编写 在GPTS中搜索论文降重&#xff0c;使…

[Redis]基本全局命令

Redis存储方式介绍 在 Redis 中数据是以键值对的凡事存储的&#xff0c;键&#xff08;Key&#xff09;和值&#xff08;Value&#xff09;是基本的数据存储单元。以下是对 Redis 键值对的详细讲解&#xff1a; 键&#xff08;Key&#xff09;&#xff1a; 类型&#xff1a;…

论文精读--InstructGPT

模型效果取决于数据效果&#xff0c;但在精细度上控制不够&#xff0c;只是大力出奇迹&#xff0c;这样有很大的问题&#xff1a; &#xff08;1&#xff09;数据量太多或者没有这方面的数据&#xff0c;模型学不会怎么办 &#xff08;2&#xff09;安全性问题&#xff0c;模…

c语言:利用随机函数产生20个[120, 834] 之间互不相等的随机数, 并利用选择排序法将其从小到大排序后输出(每行输出5个)

利用随机函数产生20个[120, 834] 之间互不相等的随机数&#xff0c; 并利用选择排序法将其从小到大排序后输出&#xff08;每行输出5个&#xff09; 代码如下&#xff1a; #include <stdio.h> #include <time.h> #include <stdlib.h> int shenchen(int a[…

信息系统项目管理师0126:输入(8项目整合管理—8.6管理项目知识—8.6.1输入)

点击查看专栏目录 文章目录 8.6 管理项目知识8.6.1 输入8.6 管理项目知识 管理项目知识是使用现有知识并生成新知识,以实现项目目标并且帮助组织学习的过程。管理项目过程的主要作用: 利用已有的组织知识来创造或改进项目成果;使当前项目创造的知识可用于支持组织运营和未来…

解决Vscode打开新文件会覆盖旧文件

现象&原因 现象&#xff1a;Vscode左侧点击新文件&#xff0c;右侧重用预览编辑器&#xff0c;新文件会替换旧文件原因&#xff1a; 默认单击是预览编辑器显示&#xff0c;双击是保持打开状态 解决方案 以下两种都可以 设置里搜索 Enable Preview 默认是勾选状态&#x…

京东科技市场与平台运营中心PMO负责人徐雪娇受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 京东集团京东科技市场与平台运营中心PMO负责人徐雪娇女士受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“AI数字人项目全过程管理实践分享”。大会将于6月29-30日在北京举办&#xff0c;敬请关注&#xff01; 议题简要&…

springboot vue 开源 会员收银系统 (4) 分类及商品模块开发

前言 完整版演示 前面我们对会员系统 门店模块开发的开发 完成了门店的基础管理 并与会员相关联 下面我们将开发门店的分类及商品管理 我们分析以下几个重点 分类可以随时禁用不用单独下架某个商品便于管理商品添加应该有图片上传商品设置会员价和散客价便于营销商品应该参与…

解决updateByExample时属性值异常的问题(部分属性值没有使用占位符?进行占位,而是变成了属性的名称)

目录 场景简介代码片断实体类 报错信息排查原因解决测试过程解决方案 场景简介 1、程序将mybatis框架升级为3.5.9版本后执行updateByExample方法时报错 代码片断 Condition condition new Condition(MbCcsSessionConfig.class); condition.createCriteria().andEqualTo(&quo…