当前位置: 首页 > news >正文

LearnOpenGL - Android OpenGL ES 3.0 使用 FBO 进行离屏渲染

系列文章目录

  • LearnOpenGL 笔记 - 入门 01 OpenGL
  • LearnOpenGL 笔记 - 入门 02 创建窗口
  • LearnOpenGL 笔记 - 入门 03 你好,窗口
  • LearnOpenGL 笔记 - 入门 04 你好,三角形
  • OpenGL - 如何理解 VAO 与 VBO 之间的关系
  • LearnOpenGL - Android OpenGL ES 3.0 绘制三角形
  • LearnOpenGL - Android OpenGL ES 3.0 绘制纹理
  • LearnOpenGL - Android OpenGL ES 3.0 YUV 渲染

一、前言

利用 FBO(Framebuffer Object),我们可以实现离屏渲染。在前面的章节中,当我们调用 glDrawElements 后,手机屏幕上就会显示出绘制的图像。这意味着 OpenGL 将数据直接渲染到了手机屏幕上。通过使用 FBO,我们可以将数据渲染到纹理上,而不是直接渲染到屏幕,这个过程称为离屏渲染。

通过离屏渲染,我们可以在最终显示之前对图像进行复杂的处理。这种方法非常有用,比如在后期处理效果(如模糊、HDR、阴影等)中,或者在渲染多个场景以进行纹理贴图、环境映射等操作时。

假设你在开发一款图片处理软件,包含美颜、滤镜等功能。用户可以同时应用多种滤镜,如瘦脸、美白、长腿等,每种滤镜都通过 OpenGL Shader 进行处理和渲染。为实现这种功能,你可以设计一个图片渲染链。

一种直观的方法是为每种滤镜创建一个独立的模块,通过组合不同的模块实现多种滤镜的处理链。在处理链完成之前,我们无法将结果渲染到屏幕上。模块与模块之间的处理结果应该通过某种介质进行传递,这里使用的介质就是纹理。这也解释了我们为什么需要使用 FBO。

通过 FBO,我们可以在离屏状态下将渲染结果存储到纹理中,然后将该纹理作为输入传递给下一个滤镜模块。这样,整个处理链就可以逐步处理图像,直到应用所有滤镜后,将最终结果渲染到屏幕上。

在这里插入图片描述
本文所有代码在 FBODrawer.kt

二、FBO 简介

在这里插入图片描述
上图显示了帧缓冲区对象的结构,它提供了颜色缓冲区和深度缓冲区的替代品。如你所见,绘制操作并不是直接发生在帧缓冲区中的,而是发生在帧缓冲区所关联的对象(attachment)上。一个帧缓冲区有多个关联对象:颜色关联对象(color attachment)、深度关联对象(depth attachment)和模板关联对象(stencil attachment),分别用来替代颜色缓冲区、深度缓冲区和模板缓冲区。经过一些设置,OpenGL 就可以向帧缓冲区的关联对象中写入数据,就像写入颜色缓冲区或深度缓冲区一样。我们目前只关注颜色关联对象即可

每个关联对象又可以是两种类型的:纹理对象或渲染缓冲区对象(renderbuffer object)。当我们把纹理对象作为颜色关联对象关联到帧缓冲区对象后,OpenGL 就可以在纹理对象中绘图。渲染缓冲区对象表示一种更加通用的绘图区域,可以向其中写入多种类型的数据。

2.1 渲染缓冲对象

渲染缓冲区对象(Renderbuffer Object)是 OpenGL 和 OpenGL ES 中的一种缓冲区类型,用于离屏渲染。它提供了一种高效的方式来存储图像数据,特别适用于深度缓冲区和模板缓冲区。

渲染缓冲区对象的特点:

  1. 高效存储

    • 渲染缓冲区对象在实现上通常比纹理对象更高效,特别是用于深度和模板数据的存储。
    • 它不需要纹理过滤、MIP 贴图等特性,因此在某些场景下可以提供更好的性能。
  2. 不可直接采样

    • 与纹理对象不同,渲染缓冲区对象不能直接被着色器采样。
    • 这意味着你不能在着色器中直接访问渲染缓冲区对象中的数据,只能用于渲染过程。
  3. 用途广泛

    • 渲染缓冲区对象可以用作颜色、深度或模板缓冲区。
    • 在使用 FBO 进行离屏渲染时,渲染缓冲区对象可以作为这些附件类型附加到 FBO 上。

渲染缓冲区对象的使用步骤:

  1. 创建渲染缓冲区对象

    GLuint rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    
  2. 分配存储

    • 根据用途分配存储,比如深度缓冲区、颜色缓冲区等。
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
    // 或者为颜色缓冲区分配存储
    // glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
    
  3. 附加到 FBO

    • 将渲染缓冲区对象附加到 FBO 作为附件。
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
    // 如果是颜色缓冲区
    // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
    

纹理对象与渲染缓冲区对象的对比:

  • 纹理对象

    • 可以在着色器中采样,用于更灵活的图像处理。
    • 适用于需要在多个渲染步骤中反复使用和处理的图像数据。
  • 渲染缓冲区对象

    • 高效的存储和写入,但不能在着色器中采样。
    • 适用于深度缓冲区和模板缓冲区,或者不需要在着色器中采样的颜色缓冲区。

结合使用:

在实际应用中,常常将纹理对象和渲染缓冲区对象结合使用。比如:

  • 使用渲染缓冲区对象存储深度和模板数据,以获得更高的性能。
  • 使用纹理对象存储颜色数据,以便在后续渲染步骤中进行采样和处理。

例子:

假设我们在开发一个图片处理软件,通过 FBO 进行多重滤镜处理。每个滤镜模块会产生一个中间结果,这些中间结果通常存储在纹理对象中,因为它们需要被后续的滤镜模块采样和处理。然而,为了提高性能,我们可以使用渲染缓冲区对象来存储深度数据,因为这些数据通常不需要在滤镜处理中直接访问。

// 创建并绑定 FBO
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);// 创建并附加颜色附件(纹理对象)
GLuint colorTex;
glGenTextures(1, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);// 创建并附加深度附件(渲染缓冲区对象)
GLuint depthRbo;
glGenRenderbuffers(1, &depthRbo);
glBindRenderbuffer(GL_RENDERBUFFER, depthRbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRbo);// 检查 FBO 完整性
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {// 处理错误
}// 解绑 FBO 以恢复默认帧缓冲区
glBindFramebuffer(GL_FRAMEBUFFER, 0);

通过这种方式,我们可以高效地实现图像的离屏渲染和多重滤镜处理。

三、FBO 使用流程

GLES30.glGenTextures(1, fboTexIds)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0])
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR)
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE)// generate fbo id and config fbo
// 创建 FBO
GLES30.glGenFramebuffers(1, fbo);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0])
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0])
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, fboTexIds[0], 0)
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, imageWidth, imageHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_NONE)

这段代码用于在 OpenGL ES 3.0 中创建并配置一个帧缓冲区对象(FBO),并将一个纹理对象附加到这个帧缓冲区对象上作为颜色附件,以便进行离屏渲染。下面是对每行代码的详细解释:

创建和配置纹理对象

// 生成一个纹理对象,并将其ID存储在 fboTexIds 数组中
GLES30.glGenTextures(1, fboTexIds);// 绑定生成的纹理对象
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);// 设置纹理过滤参数,线性过滤
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);// 解除纹理绑定
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);
  1. 生成纹理对象

    • GLES30.glGenTextures(1, fboTexIds);:生成一个纹理对象,并将其ID存储在 fboTexIds 数组中。
  2. 绑定纹理对象

    • GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);:将生成的纹理对象绑定到目标 GL_TEXTURE_2D
  3. 设置纹理参数

    • GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);:设置纹理的缩小过滤为线性过滤。
    • GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);:设置纹理的放大过滤为线性过滤。
  4. 解除纹理绑定

    • GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);:解除当前绑定的纹理对象。

创建和配置帧缓冲区对象

// 生成一个帧缓冲区对象,并将其ID存储在 fbo 数组中
GLES30.glGenFramebuffers(1, fbo);// 绑定生成的帧缓冲区对象
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0]);// 重新绑定之前创建的纹理对象
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);// 将纹理对象附加到帧缓冲区对象的颜色附件上
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, fboTexIds[0], 0);// 为纹理对象分配存储空间
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, imageWidth, imageHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);// 解除纹理绑定
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);// 解除帧缓冲区对象的绑定
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_NONE);
  1. 生成帧缓冲区对象

    • GLES30.glGenFramebuffers(1, fbo);:生成一个帧缓冲区对象,并将其ID存储在 fbo 数组中。
  2. 绑定帧缓冲区对象

    • GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0]);:将生成的帧缓冲区对象绑定到目标 GL_FRAMEBUFFER
  3. 重新绑定纹理对象

    • GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);:将之前创建的纹理对象重新绑定到目标 GL_TEXTURE_2D
  4. 附加纹理对象到帧缓冲区对象

    • GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, fboTexIds[0], 0);:将纹理对象作为颜色附件附加到帧缓冲区对象上。
  5. 为纹理对象分配存储空间

    • GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, imageWidth, imageHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);:为纹理对象分配存储空间,并指定其格式和尺寸。
  6. 解除纹理绑定

    • GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);:解除当前绑定的纹理对象。
  7. 解除帧缓冲区对象的绑定

    • GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_NONE);:解除当前绑定的帧缓冲区对象。

四、FBO 离屏渲染

为了演示 FBO 离屏渲染,我在 FBODrawer.kt 构建了两个 shader,第一个 shader 将 RGB 图片转换为灰度图,第二个 shader 则将纹理渲染到屏幕上。

companion object {val vertexShaderSource ="""#version 300 eslayout(location = 0) in vec3 a_positlayout(location = 1) in vec2 a_texcoout vec2 v_texcoord;void main(){gl_Position = vec4(a_position, 1v_texcoord = a_texcoord;}""".trimIndent()val fragmentShaderSource ="""#version 300 esprecision mediump float;uniform sampler2D texture0;in vec2 v_texcoord;out vec4 fragColor;void main(void){fragColor = texture(texture0, v_}""".trimIndent()val fboFragmentShaderSource ="""#version 300 esprecision mediump float;uniform sampler2D texture0;in vec2 v_texcoord;out vec4 fragColor;void main(void)void main(void){vec4 tempColor = texture(texture0, v_texcoord);float gray = 0.299*tempColor.a + 0.587*tempColor.g + 0.114*tempColor.b;fragColor = vec4(vec3(gray), 1.0);}""".trimIndent()
}
private val shader = Shader(vertexShaderSource,fragmentShaderSource
)
private val fboShader = Shader(vertexShaderSource,fboFragmentShaderSource
)

因此我们需要调用两次 draw 方法:

  1. 第一次,我们的 shader 输入是 rgb 图片的纹理,输出是灰度图纹理
  2. 第二次,我们的 shader 输入是灰度图纹理,然后直接绘制到纹理上
override fun draw() {// first, fbo off screen renderingGLES30.glViewport(0, 0, imageWidth, imageHeight)GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0])fboShader.use()fboShader.setInt("texture0", 0)GLES30.glBindVertexArray(vaos[0])GLES30.glActiveTexture(GLES30.GL_TEXTURE0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexIds[0])GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)GLES30.glBindVertexArray(0)GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)// second, draw texture to screenGLES30.glViewport(0, 0, screenWidth, screenHeight)shader.use()shader.setInt("texture0", 0)GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)GLES30.glBindVertexArray(vaos[0])GLES30.glActiveTexture(GLES30.GL_TEXTURE0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]) // 用 fbo 渲染的结果作为纹理的输入GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0)GLES30.glBindVertexArray(0)
}

这段代码展示了如何使用帧缓冲区对象(FBO)进行离屏渲染,然后将离屏渲染的结果绘制到屏幕上。具体分为两个步骤:第一步是将场景渲染到 FBO,第二步是将 FBO 的内容作为纹理绘制到屏幕上。

第一步:离屏渲染到 FBO

// 设置视口为 FBO 的尺寸
GLES30.glViewport(0, 0, imageWidth, imageHeight);// 绑定 FBO
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0]);// 使用离屏渲染的着色器程序
fboShader.use();// 设置着色器程序中纹理单元的位置
fboShader.setInt("texture0", 0);// 绑定 VAO
GLES30.glBindVertexArray(vaos[0]);// 激活纹理单元并绑定需要渲染的纹理
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexIds[0]);// 绘制元素
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0);// 解除纹理绑定
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);// 解除 VAO 绑定
GLES30.glBindVertexArray(0);// 解除 FBO 绑定,恢复默认帧缓冲区
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
  1. 设置视口GLES30.glViewport(0, 0, imageWidth, imageHeight) 设置渲染区域为 FBO 的尺寸。
  2. 绑定 FBOGLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0]) 绑定帧缓冲区对象。
  3. 使用着色器程序fboShader.use() 使用用于离屏渲染的着色器程序。
  4. 设置纹理单元fboShader.setInt("texture0", 0) 设置着色器程序中的纹理单元。
  5. 绑定 VAOGLES30.glBindVertexArray(vaos[0]) 绑定顶点数组对象(VAO)。
  6. 激活并绑定纹理GLES30.glActiveTexture(GLES30.GL_TEXTURE0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexIds[0]) 激活并绑定需要渲染的纹理。
  7. 绘制元素GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0) 使用索引数组绘制三角形。
  8. 解除绑定:解除纹理和 VAO 的绑定,以及 FBO 的绑定,恢复默认帧缓冲区。

第二步:将 FBO 的内容绘制到屏幕上

// 设置视口为屏幕尺寸
GLES30.glViewport(0, 0, screenWidth, screenHeight);// 使用屏幕渲染的着色器程序
shader.use();// 设置着色器程序中纹理单元的位置
shader.setInt("texture0", 0);// 清除颜色缓冲区
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);// 绑定 VAO
GLES30.glBindVertexArray(vaos[0]);// 激活纹理单元并绑定 FBO 的纹理
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);// 绘制元素
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0);// 解除 VAO 绑定
GLES30.glBindVertexArray(0);
  1. 设置视口GLES30.glViewport(0, 0, screenWidth, screenHeight) 设置渲染区域为屏幕的尺寸。
  2. 使用着色器程序shader.use() 使用用于屏幕渲染的着色器程序。
  3. 设置纹理单元shader.setInt("texture0", 0) 设置着色器程序中的纹理单元。
  4. 清除颜色缓冲区GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT) 清除颜色缓冲区。
  5. 绑定 VAOGLES30.glBindVertexArray(vaos[0]) 绑定顶点数组对象(VAO)。
  6. 激活并绑定纹理GLES30.glActiveTexture(GLES30.GL_TEXTURE0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]) 激活并绑定 FBO 的纹理(即离屏渲染的结果)。
  7. 绘制元素GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0) 使用索引数组绘制三角形。
  8. 解除绑定:解除 VAO 的绑定。

总结

  • 第一步:在 FBO 中进行离屏渲染,将结果存储在一个纹理对象中。
  • 第二步:将 FBO 中的纹理对象作为输入,绘制到屏幕上。

这种方法在图形应用程序中非常常见,特别是在实现多重渲染效果(如后期处理、反射、阴影映射等)时。

参考

  • FBODrawer.kt
  • NDK OpenGLES3.0 开发(五):FBO 离屏渲染

相关文章:

LearnOpenGL - Android OpenGL ES 3.0 使用 FBO 进行离屏渲染

系列文章目录 LearnOpenGL 笔记 - 入门 01 OpenGLLearnOpenGL 笔记 - 入门 02 创建窗口LearnOpenGL 笔记 - 入门 03 你好,窗口LearnOpenGL 笔记 - 入门 04 你好,三角形OpenGL - 如何理解 VAO 与 VBO 之间的关系LearnOpenGL - Android OpenGL ES 3.0 绘制…...

人工智能虚拟仿真系统,解决算法难、编程难、应用场景难三大难题

近年来,人工智能技术迅猛发展,广泛渗透至各行业,市场份额持续扩大,预示着智能化转型的广阔前景。该行业本质上属于知识高度密集型,近年来的迅猛发展进一步加剧了对专业人才的迫切需求。 然而,我国目前在人工…...

CTE(公共表表达式)和视图在查询时的性能影响

在SQL查询优化和数据库设计中,CTE(公共表表达式)和视图都是常用的工具。尽管它们在功能和使用场景上有很多相似之处,但在查询性能方面可能存在显著差异。本文将探讨CTE和视图在查询时的性能影响,帮助您在实际项目中做出…...

新能源行业必会基础知识-----电力市场概论笔记-----绪论

新能源行业知识体系-------主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/139946830 目录 1. 电力市场的定义2. 对传统电力系统理论的挑战 1. 电力市场的定义 1. 我国电力市场的进程 我国新一轮电力体制改革的5大亮点&…...

003 SpringBoot操作ElasticSearch7.x

文章目录 5.SpringBoot集成ElasticSearch7.x1.添加依赖2.yml配置3.创建文档对象4.继承ElasticsearchRepository5.注入ElasticsearchRestTemplate 6.SpringBoot操作ElasticSearch1.ElasticsearchRestTemplate索引操作2.ElasticsearchRepository文档操作3.ElasticsearchRestTempl…...

npm install报错Maximum call stack size exceeded

npm 报错 方案: npm cache clean --force npm install...

第1章 基础知识

第1章 基础知识 1.1 机器语言 机器语言就是机器指令的集合,机器指令展开来讲就是一台机器可以正确执行的命令 1.2 汇编语言的产生 汇编语言的主题是汇编指令。汇编指令和机器指令的差别在于指令的表示方法上,汇编指令是机器指令便于记忆的书写格式。…...

python脚本 限制 外部访问 linux服务器端口

注意:该脚本会清空linux防火墙的filter表的规则和用户自定义链路 脚本的效果是将端口限制为仅服务器内部访问 可以提供ip地址白名单 具体脚本: #!/usr/bin/python3 import argparse, subprocess, sys, redef popen(cmd):global resulttry:result su…...

Redis-哨兵模式-主机宕机-推选新主机的过程

文章目录 1、为哨兵模式准备配置文件2、启动哨兵3、主机6379宕机3.4、查看sentinel控制台日志3.5、查看6380主从信息 4、复活63794.1、再次查看sentinel控制台日志 1、为哨兵模式准备配置文件 [rootlocalhost redis]# ll 总用量 244 drwxr-xr-x. 2 root root 150 12月 6 2…...

游戏工厂:AI(AIGC/ChatGPT)与流程式游戏开发

游戏工厂:AI(AIGC/ChatGPT)与流程式游戏开发 码客 卢益贵 ygluu 关键词:AI(AIGC、ChatGPT、文心一言)、流程式管理、好莱坞电影流程、电影工厂、游戏工厂、游戏开发流程、游戏架构、模块化开发 一、前言…...

每日一练 - OSPF 组播地址

01 真题题目 判断以下陈述是否正确: 224.0.0.6 是 ALL DRouters 监听地址 224.0.0.5 是 ALL SPFRouters 监听地址 A.正确 B.错误 02 真题答案 A 03 答案解析 在OSPF (Open Shortest Path First) 路由协议中,为了实现高效的信息交换和发现邻居&#x…...

AMHS工程师的培养

一、岗位职责主要包括: 1. 负责生产现场设备运行维护及异常处理,确保设备安全操作与保养。 2. 制定并实施AMHS计划和措施,对过程问题进行追踪解决。 3. 监控生产过程中的不良品率,确保生产过程的稳定性。 4. 建立AMHS标准作业程序文件,并定期更新和维护。 5. 负责AMHS…...

如何在前端项目中制定代码注释规范

本文是前端代码规范系列文章,将涵盖前端领域各方面规范整理,其他完整文章可前往主页查阅~ 开始之前,介绍一下​最近很火的开源技术,低代码。 作为一种软件开发技术逐渐进入了人们的视角里,它利用自身独特的优势占领市…...

一位苹果手机硬件工程师繁忙的一天

早晨:迎接新的一天 7:00 AM - 起床 早晨七点准时起床。洗漱、吃早餐后,查看手机上的邮件和消息,以便提前了解今天的工作安排和优先事项。 7:30 AM - 前往公司 开车前往位于加州库比蒂诺的苹果总部。在车上习惯性地听一些与电子工程相关的播…...

Python | 使用均值编码(MeanEncoding)处理分类特征

在特征工程中,将分类特征转换为数字特征的任务称为编码。 有多种方法来处理分类特征,如OneHotEncoding和LabelEncoding,FrequencyEncoding或通过其计数替换分类特征。同样,我们可以使用均值编码(MeanEncoding)。 均值编码 均值…...

面试-java异常体系

1.java异常体系 error类是指与jvm相关的问题。如系统崩溃,虚拟机错误,内存空间不足。 非runtime异常不处理,程序就没有办法执行。 一旦遇到异常抛出,后面的异常就不会进行。 (1)常见的error以及exception 2.java异常要点分析…...

Clickhouse 的性能优化实践总结

文章目录 前言性能优化的原则数据结构优化内存优化磁盘优化网络优化CPU优化查询优化数据迁移优化 前言 ClickHouse是一个性能很强的OLAP数据库,性能强是建立在专业运维之上的,需要专业运维人员依据不同的业务需求对ClickHouse进行有针对性的优化。同一批…...

变工况下转子、轴承数据采集及测试

1.固定工况下的数据采集 1.wireshark抓包 通过使用 Wireshark 抓包和 Linux 端口重放技术,可以模拟实际机械设备的运行环境,从而减少实地验证软件和算法的复杂性和麻烦。 打开设备正常运转,当采集器通过网口将数据发送到电脑时&#xff0c…...

泰迪智能科技与成都文理学院人工智能与大数据学院开展校企合作交流

近日,在推动高等教育与产业深度融合的背景下,成都文理学院人工智能与大数据学院携手广东泰迪智能科技股份有限公司开展“专业建设交流会”。人工智能与大数据学院院长胡念青、院长助理陈坚、骨干教师刘超超、孙沛、赵杰、文运、胡斌、邹杰出席本次交流会…...

ubuntu22.04安装初始化

目录 1. 概述2. 修改参数3. 修改限制4. 修改源6. 虚拟机关闭swap分区7. 配置系统信息7.1 设置主机名7.2 设置时区7.3 安装常用工具包7.4 设置时间同步7.5 关闭 selinux 1. 概述 CentOS 7 马上就停止支持服务了,未雨绸缪,整理Ubuntu 22.04的 初始化脚本。…...

学习新语言方法总结(一)

随着工作时间越长,单一语言越来越难找工作了,需要不停地学习新语言来适应,总结一下自己学习新语言的方法,这次以GO为例,原来主语言是PHP ,自学GO 了解语言特性,知道他是干嘛的 go语言&#xff0…...

Mysql数据的备份与恢复

一.备份概述 备份的主要目的是灾难恢复,备份还可以测试应用、回滚数据修改、查询历史数据、审计等。 1.数据备份的重要性 在企业中数据的价值至关重要,数据保障了企业业务的正常运行。因此,数据的安全性及数据的可靠性是运维的重中之重&…...

规上!西安市支持培育商贸企业达限纳统应统尽统申报奖励补助要求政策

西安市支持培育商贸企业达限纳统应统尽统工作方案 为加快培育消费市场主体,支持商贸企业扩大经营、做大做强,指导企业达限纳统、应统尽统,不断扩大我市限额以上商贸企业数量规模,促进全市经济社会高质量发展,结合我市…...

Go语言测试第二弹——基准测试

在前一篇文章中,我们讲解了Go语言中最基础的单元测试,还没有看过的可以自行去查看,这篇文章我们详细了解Go语言里面的基准测试。 基准测试 基准测试,也就是BenchmarkTest,基准测试是用来测试代码性能的的一种方法&…...

关于“刘亦菲为什么无人敢娶”的问题❗❗❗

关于“刘亦菲为什么无人敢娶”的问题, 实际上涉及到多个方面的因素, 以下是对这些因素的详细分析:1.事业心重:刘亦菲作为华语影视圈的知名女星,她的演艺事业非常成功, 这也意味着她将大量的时间和精力投…...

LeetCode:经典题之141、142 题解及延伸

系列目录 88.合并两个有序数组 52.螺旋数组 567.字符串的排列 643.子数组最大平均数 150.逆波兰表达式 61.旋转链表 160.相交链表 83.删除排序链表中的重复元素 389.找不同 1491.去掉最低工资和最高工资后的工资平均值 896.单调序列 206.反转链表 92.反转链表II 141.环形链表 …...

rk3568 OpenHarmony 串口uart与电脑通讯开发案例

一、需求描述: rk3568开发板运行OpenHarmony4.0,通过开发板上的uart串口与电脑进行通讯,相互收发字符串。 二、案例展示 1、开发环境: (1)rk3568开发板 (2)系统:OpenHar…...

canvas画布旋转问题

先说一下为什么要旋转的目的:因为在画布上签名,在不同的设备上我需要不同方向的签名图片,电脑是横屏,手机就是竖屏,所以需要把手机的签名旋转270,因此写了这个方法。 关于画布旋转的重点就是获取到你的画布…...

vue3 【提效】自动导入框架方法 unplugin-auto-import 实用教程

是否还在为每次都需要导入框架方法而烦恼呢? // 每次都需手动导入框架方法 import { ref } from vuelet num ref(0)用 unplugin-auto-import 来帮你吧,以后只需这样写就行啦! let num ref(0)官方示例如下图 使用流程 1. 安装 unplugin-au…...

clip系列改进Lseg、 group ViT、ViLD、Glip

Lseg 在clip后面加一个分割head,然后用分割数据集有监督训练。textencoder使用clip,frozen住。 group ViT 与Lseg不同,借鉴了clip做了真正的无监督学习。 具体的通过group block来做的。使用学习的N个group token(可以理解为聚类…...

Ubuntu下TensorRT与trtexec工具的安装

新版(这里测试的是10.1版)的onnx转tensorrt engine工具trtexec已经集成在TensorRT中,不需要额外单独安装。 教程来源于此网页:https://medium.com/moshiur.faisal01/install-tensorrt-with-command-line-wrapper-trtexec-on-unun…...

MySQL定时任务

事件调度器操作 查看事件调度器是否开启:ON 表示已开启。 show variables like %event_scheduler%; ------------------------ | Variable_name | Value | ------------------------ | event_scheduler | ON | ------------------------ 开启和关闭事件调度器…...

Pandas实用Excel数据汇总

Pandas 是一个开源的 Python 库,由 Wes McKinney 开发,专门用于高效地处理和分析数据,无论是小规模的数据实验还是大规模的数据处理任务。它构建在 NumPy 之上,这意味着它利用了 NumPy 的高性能数组计算能力。Pandas 的核心数据结…...

【计算机网络】[第4章 网络层][自用]

1 概述 (1)因特网使用的TCP/IP协议体系(四层)的网际层,提供的是无连接、不可靠的数据报服务; (2)ATM、帧中继、X.25的OSI体系(七层)中的网络层,提供的是面向连接的、可靠的虚电路服务。 (3)路由选择分两种: 一种是由用户or管理员人工进行配置(只适用于规…...

Unity3D Entity_CacheService实现详解

Unity3D是一款广泛使用的游戏开发引擎,它提供了丰富的功能和工具来帮助开发者创建高质量的游戏和互动体验。在Unity开发过程中,资源管理是一个重要的环节,特别是当项目规模逐渐增大,资源数量变多时。为了优化资源的加载和管理&…...

DLMS/COSEM协议—(Green-Book)Gateway protocol

DLMS/COSEM协议 — Gateway protocol 10.10 Gateway protocol (网关协议)10.10.1 概述10.10.2 网关协议 (The gateway protocol)10.10.3 HES在WAN/NN中作为发起者(拉取操作)10.10.4 LAN中的终端设备作为发起…...

Android高级面试_12_项目经验梳理

Android 高级面试-1:Handler 相关 问题:Handler 实现机制(很多细节需要关注:如线程如何建立和退出消息循环等等) 问题:关于 Handler,在任何地方 new Handler 都是什么线程下? 问题&#xff1a…...

【项目实训】解决前后端跨域问题

由于前端框架使用vue,后端使用flask,因此需要解决前后端通信问题 在vue.config.js中修改 module.exports defineConfig({transpileDependencies: true,lintOnSave:false, }) // 跨域配置 module.exports {devServer: { //记住&#x…...

Java反射API详解与应用场景

一、Java反射API简介: 一、什么是反射: 反射是一种强大的工具,它允许我们在运行时检查类、方法和字段的信息,甚至允许我们动态的调用特定类的方法或改变字段的值。编程语言中的反射机制通常用于从类、对象或方法中检索元数据,或者更特别的说,从代码本身中获取信息。这就…...

【例子】webpack 开发一个可以加载 markdown 文件的加载器 loader 案例

Loader 作为 Webpack 的核心机制,内部的工作原理却非常简单。接下来我们一起来开发一个自己的 Loader,通过这个开发过程再来深入了解 Loader 的工作原理。 这里我的需求是开发一个可以加载 markdown 文件的加载器,以便可以在代码中直接导入 m…...

揭秘!这款电路设计工具让学校师生都爱不释手——SmartEDA的魔力何在?

随着科技的飞速发展,电子设计已成为学校师生们不可或缺的技能之一。而在众多的电路设计工具中,有一款名为SmartEDA的工具,凭借其强大的功能和友好的用户体验,迅速赢得了广大师生的青睐。今天,就让我们一起探索SmartEDA…...

onlyoffice实现打开文档的功能

后端代码 import api from api import middlewareasync def doc_callback(request):data await api.req.get_json(request)print("callback ", data)# status 2 文档准备好被保存# status 6 文档编辑会话关闭return api.resp.success()app api.Api(routes[api.…...

基于 SpringBoot + Vue 的图书购物商城项目

本项目是一个基于 SpringBoot 和 Vue 的图书购物商城系统。系统主要实现了用户注册、登录,图书浏览、查询、加购,购物车管理,订单结算,会员折扣,下单,个人订单管理,书籍及分类管理,用…...

如何使用kimi智能助手:您的智能生活小助手

Kimi智能助手是一款功能强大的AI工具,旨在帮助用户提高工作效率和生活品质。下面小编将详细介绍如何使用Kimi智能助手,涵盖其主要功能以及一些实用技巧。 一、Kimi智能助手的主要功能 多语言对话能力:Kimi擅长中文和英文的对话,可…...

sql操作

1. 按条件将表A的数据更新到表B中: update B b set b.col1 (select col1 from A a where b. id a.code), b.col2 (select col2 from A a where b. id a.code), ………… 2. 将表A的全量数据插入到表B中 insert into B (col1, col2, col3, col4,……&am…...

开关电源调试记录-基于DK112(DK1203也一样)作为开关主控芯片的开关电源

调试了一款DK112(datasheet)开关电源控制芯片。 1、原理图如下: 2、测试波形 a.输出波形,图中标识“5V”的位置 b.芯片VCC引脚,图中标识“4”的位置 c.芯片FB引脚,图中标识“3”的位置 对于FB引脚&…...

【自然语言处理】GPT-5技术突破预测:引领自然语言处理革新的里程碑

摘要 随着科技的飞速发展,人工智能(AI)领域正迎来一场前所未有的革命。近日,OpenAI首席技术官米拉穆拉蒂在采访中透露,新一代大语言模型GPT-5将在一年半后发布,这一消息无疑在科技界掀起了巨大的波澜。GPT-…...

qt基本窗口类(QWidget,QDialog,QMainWindow)

1.三个基本窗口类 1.1QWidget 所有窗口的基类 可以内嵌到其他窗口的内部,无边框 也可以作为独立窗口显示,有边框 1.2QDialog 继承于QWidget 对话框窗口类 不可以内嵌到其他窗口 有模态和非模态两种显示方式 1.3QMainWind 继承于QWidget 主窗口类 不可以…...

最新收录历年地震数据,含时间、位置、类型、震级等信息

基本信息. 数据名称: 历年地震数据 数据格式: Shp 数据时间: 2023年 数据几何类型: 点 数据坐标系: WGS84坐标系 数据来源:网络公开数据 数据字段: 序号字段名称字段说明1dzlx地震类型2zj震级3zysd震源深度(米)4jtwz…...

C++ 串口读写

这段代码演示了如何使用 Windows API 中的串口通信功能进行简单的数据发送和接收。它使用了串口的基本操作和设置,并通过 sendSizeCategory 函数实现了一个简单的串口通信示例,发送一个十六进制数据,并读取串口返回的数据。 _CRT_SECURE_NO_WARNINGS:这是针对使用 strcpy …...