[OpenGL] Transform feedback 介绍以及使用示例

一、简介

本文介绍了 OpenGL 中 Transform Feedback 方法的基本概念和代码示例。

二、Transform Feedback 介绍

1. Transform Feedback 简介

根据 OpenGL-wiki,Transform Feedback 是捕获由顶点处理步骤(vertex shader 和 geometry shader)生成的图元(Primitives)的过程,将这些图元的数据记录到缓冲区对象(Buffer Objects)中。这样可以保留物体的变换后渲染状态,(在GPU中)多次重新提交这些数据。

简单来讲,使用 Transform Feedback 可以将 vertex shader 和 geometry shader 处理后的数据存储到指定的 Buffer Objects 中,而不继续进行后续的 Clipper、Rasterizaer 和 Test & Blending 阶段。

Transform Feedback Buffer 在渲染管线中所处的位置如下图所示:
TB in render pipline

2. 使用 Transform feedback 可实现的功能

  1. 实现粒子系统:
    在粒子系统中,Transform Feedback 可以用来捕获粒子的状态信息(如位置、速度、颜色等),然后将这些数据存储到缓冲区中。在每一帧中,系统可以通过 Transform Feedback 来更新粒子的状态,从而避免在CPU中重新计算整个粒子系统。这种方式能有效地避免 CPU 参与数据更新,提高系统的性能。
  2. 进行GPU并行运算:
    使用 Transform Feedback,可以在 vertex shader 中执行并行计算任务,将计算结果直接存储在 Transform Feedback 对应的 buffer 中 (GPU 内存中)。
    例如,可以在 vertex shader 中执行物理计算(如模拟重力或其他力学运动),并将计算结果(例如新的顶点位置)存储在 buffer 中,作为新渲染 shader program 的输入,或者直接作为结果传输到 CPU 上。而不需要每次都在 CPU 计算再传输到 GPU 中。

三、使用示例

1. 使用 Transform Feedback 与 vertex shader

在本例中,使用 Transform feedback 方法在 GPU (vertex shader) 中进行并行运算,将输入的数据开平方后存储到 Transform feedback 对应的 buffer 中再传到 CPU 中进行打印输出。

1.1. 步骤

  1. 初始化 glfw, glad, 窗口
  2. 构建,编译 vertex shader
  3. 指定 Transform feedback object 的接收变量
  4. 链接 shader program
  5. 准备输入数据, VAO 和 VBO
  6. 设置绑定到 Transform feedback object 上的 buffer,用于接收输出数据
  7. 运行 shader 程序
    7.1 use shader program
    7.2 disable rasterizer
    7.3 begin transform feedback
    7.4 bind VAO
    7.5 draw
    7.6 end transform feedback
  8. 将 Transform feedback buffer 中的数据传输到 CPU
  9. 释放资源

1.2. 代码

#include <glad/glad.h>
#include <GLFW/glfw3.h>#include <iostream>
// 用于处理窗口大小改变的回调函数
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
// 用于处理用户输入的函数
void processInput(GLFWwindow *window);// 指定窗口默认width和height像素大小
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;/****** vertex shader 代码 ******/
const char *vertexShaderSource = R"(
#version 330 core
layout (location = 0) in float inputValue;
out float outputValue;
void main()
{outputValue = sqrt(inputValue);
}
)";
/************************************/int main()
{/****** 1.初始化glfw, glad, 窗口 *******/// glfw 初始化 + 配置 glfw 参数glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfw 生成窗口// (由于我们只使用 Transform feedback 进行并行运算,因此实际上不生成窗口也可以)GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){// 检查是否成功生成窗口,如果没有成功打印出错信息并且退出std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}// 设置窗口window的上下文glfwMakeContextCurrent(window);// 配置window变化时的回调函数glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 使用 glad 加载 OpenGL 中的各种函数if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}/************************************//****** 2.构建,编译 vertex shader ******/// vertex shaderunsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// 检查是否成功编译 vertex shaderint success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// 生成 shader 程序unsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);/****** 3. 指定 Transform feedback object 的接收变量  ******/// 该步骤必须在 glLinkProgram() 之前进行// 因为使用 Transform feedback 会改变 shader 程序的渲染流程,因此需要先指定 Transform feedback 的接收变量,告诉// OpenGL 应该如何链接、编译 shader 程序,再进行 glLinkProgram()const char *feedbackVaryings[] = {"outputValue"}; // 我们希望接收 vertex shader 的输出变量 out float outputValue// glTransformFeedbackVaryings() 函数的参数解释:// (1). 目标 shader program// (2). 目标接收变量的个数,即 feedbackVaryings 数组中 字符串的个数// (3). 目标接收的变量名字符串数组// (4). 接收变量的存储目标. GL_INTERLEAVED_ATTRIBS, 表示所有输出变量都输出到 一个 buffer 中,// GL_SEPARATE_ATTRIBS 表示 输出变量输出到不同的 buffer 中. 此处我们选择将输出存储到 一个 buffer 中glTransformFeedbackVaryings(shaderProgram, 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);/************************************//****** 4. 链接 shader program  ******/glLinkProgram(shaderProgram); // 链接 shader program// 检查是否成功链接 vertex shader 和 fragment shaderglGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);/************************************//****** 5.准备输入数据, VAO 和 VBO *******/float inputData[] = {0.0f, 0.5f, 1.0f};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO); // 生成一个VAO对象glGenBuffers(1, &VBO);      // 生成一个VBO对象glBindVertexArray(VAO); // 绑定VAOglBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定VBOglBufferData(GL_ARRAY_BUFFER, sizeof(inputData), inputData,GL_STATIC_DRAW); // 将vertices中的数据复制到刚刚绑定的VBO buffer中去,VBO buffer是GPU内存上的一块区域// glVertexAttribPointer() 用于指定顶点属性如何从绑定的 VBO 中读取数据,// 此时绑定的 buffer 是 VBO,因此location=0 处的顶点属性就从VBO中读数据 glVertexAttribPointer()// 需要6个参数,每个参数的含义如下:// (1). 指定要配置的顶点属性, 即 shader 中指定 数据 location 值,对于position部分,此处填入 0// (2). 指定顶点属性的大小,shader中我们将VBO中的数据传给了一个 float 类型的变量,// 每个顶点数据只有一个 float, 因此此处填 1// (3). 指定数据的类型,用于使用的是浮点型,因此此处填入 GL_FLOAT// (4). 指定是否自动对数据进行归一化,我们不需要自动诡异化,因此此处填入 GL_FALSE// (5). 指定VBO中顶点数据组之间的间隔,可以手动设置间隔,例如 sizeof(float),// 也可以填 0 让 Opengl 自动设置// (6). 指定读取VBO数据起始位置偏移,单位为字节,这里填入 (void *)(0*sizeof(float)) 即可glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0,(void *)(0 * sizeof(float))); // 设置如何读取VBO中数据glEnableVertexAttribArray(0);                       // 启用 location = 0 处的顶点属性glBindBuffer(GL_ARRAY_BUFFER, 0);                   // 解绑VBO/************************************//****** 6. 设置绑定到 Transform feedback object 上的 buffer,用于接收输出数据  ******/// 新建一个 buffer 用于作为 Transform feedback object 的 buffer,用来接收 计算后的输出结果GLuint tbo;glGenBuffers(1, &tbo);glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(inputData), nullptr, GL_STATIC_READ);// 将 tbo 绑定到 TFO 的 0号卡槽上, 此处不对卡槽机制进行过多的讲解glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);/************************************//****** 7. 运行 shader 程序  ******/// 7.1 use shader programglUseProgram(shaderProgram);// 关闭 光栅化阶段, 只使用 vertex shader 和 geometry shader (如果有的话) 阶段// 7.2 disable rasterizerglEnable(GL_RASTERIZER_DISCARD);// 开始绘制 Transform feedback// 此处只有 vertex shader,因此 glBeginTransformFeedback() 中指定的 图元 需要跟 glDrawArray() 中的相同// 7.3 begin transform feedbackglBeginTransformFeedback(GL_POINTS);// 7.4 bind VAOglBindVertexArray(VAO); // 绑定VAO,指定当前使用的VAO对象// 7.5 drawglDrawArrays(GL_POINTS, 0,3); // 输入数据数据只有三个 float,因此可以将每个数据分配给一个 point ,在 vertex shader 中进行计算处理// 7.6 end transform feedbackglEndTransformFeedback(); // 结束 Transform feedback// 开启 光栅化阶段glDisable(GL_RASTERIZER_DISCARD);glBindVertexArray(0); // 解绑 VAOglFlush(); // 刷新 gl 命令 buffer 保证前面的命令都运行完成/************************************//****** 8. 将 Transform feedback buffer 中的数据传输到 CPU   ******/// 接收 Transform feedback 对应的 buffer (tbo) 中的数据GLfloat feedback[3];glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(feedback), feedback);for (int i = 0; i < 3; i++){printf("%f\n", feedback[i]);}/************************************//****** 9.释放资源 ******/// 释放之前申请的 VBO, VAO 资源和 shader 程序glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);// glfw 释放 glfw使用的所有资源glfwTerminate();/************************************/return 0;
}// 用于处理用户输入的函数
void processInput(GLFWwindow *window)
{// 当按下 Esc 按键时调用 glfwSetWindowShouldClose() 函数,关闭窗口if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}// 在使用 OpenGL 和 GLFW 库时,处理窗口大小改变的回调函数
// 当窗口大小发生变化时,确保 OpenGL 渲染的内容能够适应新的窗口大小,避免图像被拉伸、压缩或出现其他比例失真的问题
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{glViewport(0, 0, width, height);
}

1.3. 运行结果

0.000000
0.707107
1.000000

2. 使用 Transform Feedback 与 vertex + geometry shader

在本例中,使用 Transform feedback 方法在 vertex shader 和 geometry shader 中进行并行运算,在 vertex shader 中将输入的数据开平方,然后在 geometry shader 中将一份数据分别加0, 加1和加2,变为三份数据。最后存储到 Transform feedback 对应的 buffer 中再传到 CPU 中进行打印输出。

2.1. 步骤

  1. 初始化 glfw, glad, 窗口
  2. 构建,编译 vertex shader , geometry shader
  3. 指定 Transform feedback object 的接收变量
  4. 链接 shader program
  5. 准备输入数据, VAO 和 VBO
  6. 设置绑定到 Transform feedback object 上的 buffer,用于接收输出数据
  7. 运行 shader 程序
    7.1 use shader program
    7.2 disable rasterizer
    7.3 begin transform feedback
    7.4 bind VAO
    7.5 draw
    7.6 end transform feedback
  8. 将 Transform feedback buffer 中的数据传输到 CPU
  9. 释放资源

2.2 代码

#include <glad/glad.h>
#include <GLFW/glfw3.h>#include <iostream>
// 用于处理窗口大小改变的回调函数
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
// 用于处理用户输入的函数
void processInput(GLFWwindow *window);// 指定窗口默认width和height像素大小
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;/****** vertex shader 代码 ******/
const char *vertexShaderSource = R"(
#version 330 core
layout (location = 0) in float inputValue;
out float geoValue;
void main()
{geoValue =  sqrt(inputValue);
}
)";/****** geometry shader 代码 ******/
const char *geometryShaderSource = R"(
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices=3) out;
in float[] geoValue;
out float outputValue;
void main()
{for(int i=0; i<3; i++){outputValue = geoValue[0] + i;EmitVertex();}EndPrimitive();
}
)";/************************************/int main()
{/****** 1.初始化glfw, glad, 窗口 *******/// glfw 初始化 + 配置 glfw 参数glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfw 生成窗口// (由于我们只使用 Transform feedback 进行并行运算,因此实际上不生成窗口也可以)GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){// 检查是否成功生成窗口,如果没有成功打印出错信息并且退出std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}// 设置窗口window的上下文glfwMakeContextCurrent(window);// 配置window变化时的回调函数glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 使用 glad 加载 OpenGL 中的各种函数if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}/************************************//****** 2.构建,编译 vertex shader, geometry shader ******/// vertex shaderunsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// 检查是否成功编译 vertex shaderint success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// geometry shaderunsigned int geometryShader = glCreateShader(GL_GEOMETRY_SHADER);glShaderSource(geometryShader, 1, &geometryShaderSource, NULL);glCompileShader(geometryShader);// 检查是否成功编译 geometry shaderglGetShaderiv(geometryShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(geometryShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::GEOMETRY::COMPILATION_FAILED\n" << infoLog << std::endl;}// 生成 shader 程序unsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, geometryShader);/****** 3. 指定 Transform feedback object 的接收变量  ******/// 该步骤必须在 glLinkProgram() 之前进行// 因为使用 Transform feedback 会改变 shader 程序的渲染流程,因此需要先指定 Transform feedback 的接收变量,告诉// OpenGL 应该如何链接、编译 shader 程序,再进行 glLinkProgram()const char *feedbackVaryings[] = {"outputValue"}; // 我们希望接收 vertex shader 的输出变量 out float outputValue// glTransformFeedbackVaryings() 函数的参数解释:// (1). 目标 shader program// (2). 目标接收变量的个数,即 feedbackVaryings 数组中 字符串的个数// (3). 目标接收的变量名字符串数组// (4). 接收变量的存储目标. GL_INTERLEAVED_ATTRIBS, 表示所有输出变量都输出到 一个 buffer 中,// GL_SEPARATE_ATTRIBS 表示 输出变量输出到不同的 buffer 中. 此处我们选择将输出存储到 一个 buffer 中glTransformFeedbackVaryings(shaderProgram, 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);/************************************//****** 4. 链接 shader program  ******/glLinkProgram(shaderProgram); // 链接 shader program// 检查是否成功链接 vertex shader 和 fragment shaderglGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(geometryShader);/************************************//****** 5.准备输入数据, VAO 和 VBO *******/float inputData[] = {0.0f, 0.5f, 1.0f};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO); // 生成一个VAO对象glGenBuffers(1, &VBO);      // 生成一个VBO对象glBindVertexArray(VAO); // 绑定VAOglBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定VBOglBufferData(GL_ARRAY_BUFFER, sizeof(inputData), inputData,GL_STATIC_DRAW); // 将vertices中的数据复制到刚刚绑定的VBO buffer中去,VBO buffer是GPU内存上的一块区域// glVertexAttribPointer() 用于指定顶点属性如何从绑定的 VBO 中读取数据,// 此时绑定的 buffer 是 VBO,因此location=0 处的顶点属性就从VBO中读数据 glVertexAttribPointer()// 需要6个参数,每个参数的含义如下:// (1). 指定要配置的顶点属性, 即 shader 中指定 数据 location 值,对于position部分,此处填入 0// (2). 指定顶点属性的大小,shader中我们将VBO中的数据传给了一个 float 类型的变量,// 每个顶点数据只有一个 float, 因此此处填 1// (3). 指定数据的类型,用于使用的是浮点型,因此此处填入 GL_FLOAT// (4). 指定是否自动对数据进行归一化,我们不需要自动诡异化,因此此处填入 GL_FALSE// (5). 指定VBO中顶点数据组之间的间隔,可以手动设置间隔,例如 sizeof(float),// 也可以填 0 让 Opengl 自动设置// (6). 指定读取VBO数据起始位置偏移,单位为字节,这里填入 (void *)(0*sizeof(float)) 即可glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0,(void *)(0 * sizeof(float))); // 设置如何读取VBO中数据glEnableVertexAttribArray(0);                       // 启用 location = 0 处的顶点属性glBindBuffer(GL_ARRAY_BUFFER, 0);                   // 解绑VBO/************************************//****** 6. 设置绑定到 Transform feedback object 上的 buffer,用于接收输出数据  ******/// 新建一个 buffer 用于作为 Transform feedback object 的 buffer,用来接收 计算后的输出结果GLuint tbo;glGenBuffers(1, &tbo);glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);// 注意!!! 由于我们使用 geometry shader 将一个输入变量(geoValue)变为三个输出(outputValue),// 因此 Transform feedback object 中用于接收数据的 buffer 大小应该为输入数据的 3 倍大glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(inputData) * 3, nullptr, GL_STATIC_READ);// 将 tbo 绑定到 TFO 的 0号卡槽上, 此处不对卡槽机制进行过多的讲解glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);/************************************//****** 7. 运行 shader 程序  ******/// 7.1 use shader programglUseProgram(shaderProgram);// 7.2 disable rasterizer// 关闭 光栅化阶段, 只使用 vertex shader 和 geometry shader (如果有的话) 阶段glEnable(GL_RASTERIZER_DISCARD);// 7.3 begin transform feedback// 开始绘制 Transform feedback// 注意!!! 由于此时使用了 geometry shader, glBeginTransformFeedback() 中的图元应该与 geometry shader 的输出一致,// 尽管 geometry shader 中的 out 图元为 triangle_strip,// 但是 transform feedback 依旧独立地存储每个 triangle 的顶点数据,// 而不是使用 strip 对数据进行压缩glBeginTransformFeedback(GL_TRIANGLES);// 7.4 bind VAOglBindVertexArray(VAO); // 绑定VAO,指定当前使用的VAO对象// 7.5 drawglDrawArrays(GL_POINTS, 0,3); // 输入数据数据只有三个 float,因此可以将每个数据分配给一个 point ,在 vertex shader 中进行计算处理// 7.6 end transform feedbackglEndTransformFeedback(); // 结束 Transform feedback// 开启 光栅化阶段glDisable(GL_RASTERIZER_DISCARD);glBindVertexArray(0); // 解绑 VAOglFlush();            // 刷新 gl 命令 buffer 保证前面的命令都运行完成/************************************//****** 8. 将 Transform feedback buffer 中的数据传输到 CPU   ******/// 接收 Transform feedback 对应的 buffer (tbo) 中的数据GLfloat feedback[9];glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(feedback), feedback);for (int i = 0; i < 9; i++){printf("%f\n", feedback[i]);}/************************************//****** 9.释放资源 ******/// 释放之前申请的 VBO, VAO 资源和 shader 程序glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);// glfw 释放 glfw使用的所有资源glfwTerminate();/************************************/return 0;
}// 用于处理用户输入的函数
void processInput(GLFWwindow *window)
{// 当按下 Esc 按键时调用 glfwSetWindowShouldClose() 函数,关闭窗口if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}// 在使用 OpenGL 和 GLFW 库时,处理窗口大小改变的回调函数
// 当窗口大小发生变化时,确保 OpenGL 渲染的内容能够适应新的窗口大小,避免图像被拉伸、压缩或出现其他比例失真的问题
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{glViewport(0, 0, width, height);
}

2.3 结果

0.000000
1.000000
2.000000
0.707107
1.707107
2.707107
1.000000
2.000000
3.000000

四、参考

[1.] OpenGL-Transform Feedback
[2.] OpenGL–Transform feedback示例解析
[3.] OpenGL-wiki-Transform Feedback

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

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

相关文章

如何使mysql数据库ID从0开始编号——以BiCorpus为例

BiCorpus是北京语言大学韩林涛老师研制一款在线语料库网站&#xff0c;可以通过上传tmx文件&#xff0c;实现在线检索功能&#xff0c;程序在github上开源免费&#xff0c;深受广大网友的喜欢。 在使用过程中&#xff0c;我发现我上传的语言资产经历修改后&#xff0c;mysql的…

C++---入门

C补充了上的不足&#xff0c;使用各方面更加便捷&#xff0c;在C的基础上面向对象进行编译&#xff0c;学过C之后&#xff0c;对学习C的一定的帮助。 命名空间&#xff1a; namesp的定义&#xff1a;定义命名空间&#xff0c;需要使⽤到namespace关键字&#xff0c;后⾯跟命…

[COLM 2024] V-STaR: Training Verifiers for Self-Taught Reasoners

本文是对 STaR 的改进方法&#xff0c;COLM 是 Conference On Language Models&#xff0c;大模型领域新出的会议&#xff0c;在国际上很知名&#xff0c;不过目前还没有被列入 ccf list&#xff08;新会议一般不会列入&#xff09;&#xff1b;作者来自高校、微软研究院和 Goo…

AOF和RDB【Redis持久化篇】

文章目录 1.什么是持久化&#xff1f;2.RDB3.AOF 1.什么是持久化&#xff1f; Redis是跑在内存里的&#xff0c;当程序重启或者服务器崩溃&#xff0c;数据就会丢失&#xff0c;如果业务场景希望重启之后数据还在&#xff0c;就需要持久化&#xff0c;即把数据保存到可永久保存…

浅谈大模型之Agent(下篇)

大模型在Agent中的应用 随着人工智能技术的不断进步&#xff0c;大模型Agent已经成为了推动智能应用发展的关键力量&#xff0c;这些Agent不仅能够理解人类的语言&#xff0c;还能自主地执行复杂任务&#xff0c;从简单的聊天机器人到能够做出战略决策的企业级助手&#xff0c…

Burp与小程序梦中情缘

前言 在日常渗透工作中&#xff0c;有时需要对微信小程序进行抓包渗透&#xff0c;通过抓包&#xff0c;我们可以捕获小程序与服务器之间的通信数据&#xff0c;分析这些数据可以帮助我们发现潜在的安全漏洞&#xff0c;本文通过讲述三个方法在PC端来对小程序抓包渗透 文章目…

RabbitMQ实现消息发送接收——实战篇(路由模式)

本篇博文将带领大家一起学习rabbitMQ如何进行消息发送接收&#xff0c;我也是在写项目的时候边学边写&#xff0c;有不足的地方希望在评论区留下你的建议&#xff0c;我们一起讨论学习呀~ 需求背景 先说一下我的项目需求背景&#xff0c;社区之间可以进行物资借用&#xff0c…

Python的3D可视化库【vedo】2-1 (plotter模块) 绘制器的使用

文章目录 1 相关用语及其关系2 Plotter类的基本使用3 Plotter类具体的初始化设置3.1 全部初始化参数3.2 使用不同的axes vedo是Python实现的一个用于辅助科学研究的3D可视化库。 vedo的plotter模块封装了绘制器类Plotter。 Plotter实例可以用于显示3D图形对象、控制渲染器行为、…

【开源大屏】玩转开源积木BI,从0到1设计一个大屏

积木 BI 重磅推出免费大屏设计器&#xff01;功能超强大&#xff0c;操作超流畅&#xff0c;体验超酷炫。快来体验一下吧。 让我们一起来看一下如何从0到1设计一个大屏。 一、积木BI大屏介绍 积木BI可视化数据大屏 是一站式数据可视化展示平台&#xff0c;旨在帮助用户快速通…

微信小程序--创建一个日历组件

微信小程序–创建一个日历组件 可以创建一个日历组件&#xff0c;来展示当前月份的日期&#xff0c;并支持切换月份的功能。 一、目录结构 /pages/calendarcalendar.wxmlcalendar.scsscalendar.jscalendar.json二、calendar.wxml <view class"calendar"><…

【Python网络爬虫笔记】11- Xpath精准定位元素

目录 一、Xpath 在 Python 网络爬虫中的作用&#xff08;一&#xff09;精准定位元素&#xff08;二&#xff09;应对动态网页&#xff08;三&#xff09;数据结构化提取 二、Xpath 的常用方法&#xff08;一&#xff09;节点选取&#xff08;二&#xff09;谓词筛选&#xff0…

现代密码学总结(上篇)

现代密码学总结 &#xff08;v.1.0.0版本&#xff09;之后会更新内容 基本说明&#xff1a; ∙ \bullet ∙如果 A A A是随机算法&#xff0c; y ← A ( x ) y\leftarrow A(x) y←A(x)表示输入为 x x x ,通过均匀选择 的随机带运行 A A A,并且将输出赋给 y y y。 ∙ \bullet …

深度学习训练参数之学习率介绍

学习率 1. 什么是学习率 学习率是训练神经网络的重要超参数之一&#xff0c;它代表在每一次迭代中梯度向损失函数最优解移动的步长&#xff0c;通常用 η \eta η 表示。它的大小决定网络学习速度的快慢。在网络训练过程中&#xff0c;模型通过样本数据给出预测值&#xff0…

lc46全排列——回溯

46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 法1&#xff1a;暴力枚举 总共n!种全排列&#xff0c;一一列举出来放入list就行&#xff0c;关键是怎么去枚举呢&#xff1f;那就每次随机取一个&#xff0c;然后删去这个&#xff0c;再从剩下的数组中继续去随机选一个&a…

Docker 安装 Seata2.0.0 (快速配置)

说明&#xff1a;已安装Docker、MySql等&#xff0c;案例使用Mysql数据库模式、Nacos配置信息 1、准备工作 1.1 拉取镜像 [rootTseng ~]# docker pull seataio/seata-server:2.0.0 2.0.0: Pulling from seataio/seata-server 001c52e26ad5: Already exists d9d4b9b6e964: P…

渗透测试-前端验签绕过之SHA256+RSA

本文是高级前端加解密与验签实战的第2篇文章&#xff0c;本系列文章实验靶场为Yakit里自带的Vulinbox靶场&#xff0c;本文讲述的是绕过SHA256RSA签名来爆破登录。 绕过 根据提示可以看出这次签名用了SHA2556和RSA两个技术进行加密。 查看源代码可以看到RSA公钥是通过请求服务…

【JavaEE】网络(2)

一、网络编程套接字 1.1 基础概念 【网络编程】指网络上的主机&#xff0c;通过不同的进程&#xff0c;以编程的方式实现网络通信&#xff1b;当然&#xff0c;我们只要满足进程不同就行&#xff0c;所以即便是同一个主机&#xff0c;只要是不同进程&#xff0c;基于网络来传…

《操作系统 - 清华大学》7 -1:全局页面置换算法:局部页替换算法的问题、工作集模型

文章目录 1. 局部页替换算法的问题2. 全局置换算法的工作原理3. 工作集模式3.1 工作集3.2 工作集的变化 4 常驻集 1. 局部页替换算法的问题 局部页面置换算法 OPT&#xff0c;FIFO&#xff0c;LRU&#xff0c;Clock 等等&#xff0c;这些算法都是针对一个正在运行的程序来讲的…

SpringCloud和Nacos的基础知识和使用

1.什么是SpringCloud ​   什么是微服务&#xff1f; ​   假如我们需要搭建一个网上购物系统&#xff0c;那么我们需要哪些功能呢&#xff1f;商品中心、订单中心和客户中心等。 ​   当业务功能较少时&#xff0c;我们可以把这些功能塞到一个SpringBoot项目中来进行…

LLMs之APE:基于Claude的Prompt Improver的简介、使用方法、案例应用之详细攻略

LLMs之APE&#xff1a;基于Claude的Prompt Improver的简介、使用方法、案例应用之详细攻略 目录 Prompt Improver的简介 0、背景痛点 1、优势 2、实现思路 Prompt优化 示例管理 提示词评估 Prompt Improver的使用方法 1、使用方法 Prompt Improver的案例应用 1、Kap…