LearnOpenGL-高级OpenGL-8.高级GLSL

本人初学者,文中定有代码、术语等错误,欢迎指正

文章目录

  • 高级GLSL
  • GLSL的内建变量
    • 在顶点着色器的内建变量
      • gl_PointSize
      • gl_VertexID
    • 在片段着色器的内建变量
      • gl_FragCoord
      • gl_FrontFacing
      • gl_FragDepth
  • 接口块
  • Uniform缓冲对象
    • Uniform块布局
    • 使用Uniform缓冲
      • 简介
      • 绑定点
      • 例子
    • Uniform缓冲对象比Uniform的优点

高级GLSL

我们将会讨论一些有趣的内建变量(Built-in Variable),管理着色器输入和输出的新方式以及一个叫做Uniform缓冲对象(Uniform Buffer Object)的有用工具。

GLSL的内建变量

  • 啥是内建变量

    在编写GLSL代码时,可以使用已经声明好了的变量就称为:内建变量,可供我们直接赋值使用。

  • 例子

    之前章节中遇到的:顶点着色器的输出向量gl_Position,和片段着色器的gl_FragCoord

在顶点着色器的内建变量

gl_PointSize

  • 简介

    • 每一个顶点都是一个图元,都会被渲染为一个点。

    • 可以通过OpenGL的glPointSize函数来设置渲染出来的点的大小,但我们也可以在顶点着色器中修改这个值。

    • GLSL定义了一个叫做gl_PointSize输出变量,它是一个float变量,你可以使用它来设置点的宽高(像素)。在顶点着色器中修改点的大小的话,你就能对每个顶点设置不同的值了。

  • 如何启用

    默认是禁用的,启用OpenGL的GL_PROGRAM_POINT_SIZE:

    glEnable(GL_PROGRAM_POINT_SIZE);
    
  • 使用例子

    将点的大小设置为裁剪空间位置的z值,也就是顶点距观察者的距离。的大小会随着观察者距顶点距离变远而增大

    void main()
    {
        gl_Position = projection * view * model * vec4(aPos, 1.0);    
        gl_PointSize = gl_Position.z;    
    }
    

    对每个顶点使用不同的点大小,会在粒子生成之类的技术中很有意思

gl_VertexID

  • 简介

    • 整型变量gl_VertexID储存了正在绘制顶点的当前ID

    • 只能对它进行读取

    • 当(使用glDrawElements)进行索引渲染的时候,这个变量会存储正在绘制顶点的当前索引

    • 当(使用glDrawArrays)不使用索引进行绘制的时候,这个变量会储存从渲染调用开始的已处理顶点数量

在片段着色器的内建变量

gl_FragCoord

  • 简介

    • gl_FragCoord是输入变量,能让我们读取当前片段的窗口空间坐标,并获取它的深度值

    • gl_FragCoord的z分量等于对应片段的深度值

    • gl_FragCoord的x和y分量是片段的窗口空间(Window-space)坐标,其原点为窗口的下角。

  • 例子

    通过利用片段着色器的gl_FragCoord,我们可以根据片段的窗口坐标,计算出不同的颜色。

    我们能够将屏幕分成两部分,在窗口的左侧渲染一种输出,在窗口的右侧渲染另一种输出。

    void main()
    {             
        if(gl_FragCoord.x < 400)
            FragColor = vec4(1.0, 0.0, 0.0, 1.0);// 红色
        else
            FragColor = vec4(0.0, 1.0, 0.0, 1.0);// 绿色  
    }
    

gl_FrontFacing

  • 简介

    • gl_FrontFacing是输入变量

    • 前置知识

      OpenGL能够根据顶点的环绕顺序来决定一个面是正向还是背向面

    • gl_FrontFacing作用

      如果我们不使用面剔除(不启用GL_FACE_CULL),那么gl_FrontFacing将会告诉我们当前片段是属于正向面的一部分还是背向面一部分

  • 例子

    我们可以这样子创建一个立方体,在内部和外部使用不同的纹理

    #version 330 core
    out vec4 FragColor;
    
    in vec2 TexCoords;
    
    uniform sampler2D frontTexture;
    uniform sampler2D backTexture;
    
    void main()
    {             
        if(gl_FrontFacing)
            FragColor = texture(frontTexture, TexCoords);// 正向
        else
            FragColor = texture(backTexture, TexCoords);// 背向
    }
    

    注意,如果你开启了面剔除,你就看不到箱子内部的面了,所以现在再使用gl_FrontFacing就没有意义了。

gl_FragDepth

  • 简介

    • 前面介绍的:gl_FragCoord

      是输入变量,能让我们读取当前片段的窗口空间坐标,并获取它的深度值,但是它是一个只读(Read-only)变量。

      我们不能修改片段的窗口空间坐标,所以修改片段的深度值需要用到目前介绍的gl_FragDepth。

    • gl_FragDepth

      是输出变量,我们可以使用它来在着色器内设置片段的深度值

  • 例子

    gl_FragDepth = 0.0; // 这个片段现在的深度值为 0.0
    

    如果片段着色器没有写入值到gl_FragDepth,它会自动取用gl_FragCoord.z的值。

  • 缺陷

    • 只要我们在片段着色器中对gl_FragDepth进行写入,OpenGL就会(像深度测试小节中讨论的那样)禁用所有的提前深度测试(Early Depth Testing)。

      提前深度测试是:

      • 硬件属性
      • 提前深度测试允许深度测试在片段着色器之前运行
      • 即:在运行片段着色器时会根据深度测试, 是舍弃当前片段还是运行片段着色器程序渲染这个片段
    • 它被禁用的原因是

      OpenGL无法在片段着色器运行之前得知片段将拥有的深度值,因为片段着色器可能会完全修改这个深度值。

  • 解决缺陷

    从OpenGL 4.2起,我们仍可以对两者(写入gl_FragDepth 与 提前深度测试)进行一定的调和。

    方法:在片段着色器的顶部使用深度条件(Depth Condition)重新声明gl_FragDepth变量:

    layout (depth_<condition>) out float gl_FragDepth;
    

    condition可以为下面的值:

    条件描述
    any默认值。提前深度测试是禁用的,你会损失很多性能
    greater你只能让深度值比gl_FragCoord.z更大
    less你只能让深度值比gl_FragCoord.z更小
    unchanged如果你要写入gl_FragDepth,你将只能写入gl_FragCoord.z的值

    通过将深度条件设置为greater或者less,OpenGL就能假设你只会写入比当前片段深度值更大或者更小的值了。这样子的话,当深度值比片段的深度值要小的时候,OpenGL仍是能够进行提前深度测试的。

    • 个人理解(可能有误)

      • 声明写入gl_FragDepth的值只能更大

        写入gl_FragDepth后

        当前渲染的片段深度值铁定大于深度缓冲中的深度值,不管放到多大,当前片段一定被丢弃,依旧进行提前深度测试

      • 声明写入gl_FragDepth的值只能更小

        写入gl_FragDepth后:

        当前渲染的片段深度值铁定小于深度缓冲中的深度值,不管放到多小,当前片段一定不会被丢弃,依旧进行提前深度测试

  • 解决缺陷例子

    #version 420 core // 注意GLSL的版本!
    out vec4 FragColor;
    layout (depth_greater) out float gl_FragDepth;// 只会更大
    
    void main()
    {             
        FragColor = vec4(1.0);
        // 当前渲染的片段深度值铁定**大于**深度缓冲中的深度值,所以能提前深度测试
        gl_FragDepth = gl_FragCoord.z + 0.1;
    }  
    

接口块

  • 简介

    作用:方便我们组合顶点着色器传入到片段着色器的这些输入/输出变量。(顶点位置、法线等顶点属性)

  • 例子说明什么是接口块

    • 输出

      #version 330 core
      layout (location = 0) in vec3 aPos;
      layout (location = 1) in vec2 aTexCoords;
      
      uniform mat4 model;
      uniform mat4 view;
      uniform mat4 projection;
      // 注意这里,out说明是输出块
      out VS_OUT// VS_OUT(大写)是块名
      {
          vec2 TexCoords;
      } vs_out;// vs_out(小写)是实例名
      
      void main()
      {
          gl_Position = projection * view * model * vec4(aPos, 1.0);    
          vs_out.TexCoords = aTexCoords;
      }  
      
    • 输入

      #version 330 core
      out vec4 FragColor;
      // 注意这里,in说明是输入块
      in VS_OUT// VS_OUT(大写)是块名
      {
          vec2 TexCoords;
      } fs_in;// fs_in(小写)是实例名
      
      uniform sampler2D texture;
      
      void main()
      {             
          FragColor = texture(texture, fs_in.TexCoords);   
      }
      
      • 块名:VS_OUT

        顶点着色器与片段着色器的块名一致

      • 实例名:

        顶点着色器:vs_out

        片段着色器:fs_in

      只要两个接口块的名字一样,它们对应的输入和输出将会匹配起来。

Uniform缓冲对象

  • 之前使用Uniform缺陷

    当使用多于一个的着色器时,尽管大部分的uniform变量都是相同的,我们还是需要不断地设置它们。

    • 具体说明

      比如一个场景有正方体、原体,他们两个用了个着色器分别渲染,这两个着色器都有一个uniform mat4 project属性,代表都需要一个摄像机的投影矩阵,这样渲染前两个着色器分别需要设置上传一次这个project uniform,共次。

  • 使用Uniform缓冲对象

    允许我们定义一系列在多个着色器中相同的全局Uniform变量。

    当使用Uniform缓冲对象的时候,我们只需要设置相关的uniform一次

    tips:可以类别为编程语言中类中的普通变量static变量

  • 例子

    glsl

    #version 330 core
    layout (location = 0) in vec3 aPos;
    
    // Uniform缓冲对象
    layout (std140) uniform Matrices
    {
        mat4 projection;
        mat4 view;
    };
    
    uniform mat4 model;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(aPos, 1.0);
    }
    

Uniform块布局

  • 引出:什么是Uniform块布局

    • Uniform块的内容是储存在一个缓冲对象中的,它实际上只是一块预留内存

      如上一节的

      layout (std140) uniform Matrices
      {
          mat4 projection;
          mat4 view;
      };
      

      这是一个Uniform块声明,但是不具有内容

      • mat4 projection;

        预留了一个4x4float数组大小的内存

      • mat4 view;

        预留了一个4x4float数组大小的内存

    • 需要指定内容

      因为这块内存并不会保存它具体保存的是什么类型的数据,我们还需要告诉OpenGL在内存的哪一部分对应着着色器中的哪一个uniform变量(即哪块内存数据是给projection、哪块内存数据是给view)。

      如何告诉,这就是Uniform块布局

      (可以类比之前:glVertexAttribPointer,来指定内存数组的顶点输入数据的哪一个部分对应顶点着色器哪一个顶点属性

  • 假设着色器中有以下的这个Uniform块:

    layout (std140) uniform ExampleBlock
    {
        float value;
        vec3  vector;
        mat4  matrix;
        float values[3];
        bool  boolean;
        int   integer;
    };
    

    我们需要知道的是每个变量的大小(字节)和(从块起始位置的)偏移量,来让我们能够按顺序将它们放进缓冲中。

    • 每个元素的大小都是在OpenGL中有清楚地声明的,而且直接对应C++数据类型,其中向量和矩阵都是float数组。
    • OpenGL没有声明的是这些变量间的间距(Spacing)
  • 前置了解:硬件自动偏移量与共享布局

    • 硬件自动定义了偏移量,GLSL会使用一个叫做共享(Shared)布局的Uniform内存布局

    • 使用共享布局时,GLSL是可以为了优化而对uniform变量的位置进行变动的,只要变量的相对顺序保持不变。

    • 能够使用像是glGetUniformIndices这样的函数来查询每个uniform变量的偏移量,从而计算获取这个uniform的位置进行上传数据。

      小结:glsl会改变uniform的位置,则需要使用glGetUniformIndices函数查询uniform的偏移量,这会产生非常多的工作量。

  • std140布局

    克服:硬件自动偏移量与共享布局的缺陷

    • 简介

      • std140布局声明了每个变量的偏移量都是由一系列规则所决定的,这显式地声明了每个变量类型的内存布局。由于这是显式提及的,我们可以手动计算出每个变量的偏移量。
      • 基准对齐量,它等于一个变量在Uniform块中所占据的空间(包括填充量(Padding)),这个基准对齐量是使用std140布局的规则计算出来的。(类型的大小,float:4、)
      • 对齐偏移量,它是一个变量从块起始位置的字节偏移量。
      • 一个变量的对齐字节偏移量必须等于基准对齐量的倍数。
    • 布局规则

      GLSL中的每个变量,比如说int、float和bool,都被定义为4字节量。每4个字节将会用一个N来表示。

      类型布局规则
      标量,比如int和bool每个标量的基准对齐量为N。
      向量2N或者4N。这意味着vec3的基准对齐量为4N。
      标量或向量的数组每个元素的基准对齐量与vec4的相同。
      矩阵储存为列向量的数组,每个向量的基准对齐量与vec4的相同。
      结构体等于所有元素根据规则计算后的大小,但会填充到vec4大小的倍数。
    • 例子

      layout (std140) uniform ExampleBlock
      {
                           // 基准对齐量       // 对齐偏移量
          float value;     // 4               // 0 
          vec3 vector;     // 16              // 16  (必须是16的倍数,所以 4->16)
          mat4 matrix;     // 16              // 32  (列 0)
                           // 16              // 48  (列 1)
                           // 16              // 64  (列 2)
                           // 16              // 80  (列 3)
          float values[3]; // 16              // 96  (values[0])
                           // 16              // 112 (values[1])
                           // 16              // 128 (values[2])
          bool boolean;    // 4               // 144
          int integer;     // 4               // 148
      }; 
      
      • 如vec3 vector;

        由于:一个变量的对齐字节偏移量必须等于基准对齐量的倍数

        本来:它的对齐偏移量是4的,但是它的基准对齐量是16,所以4需要向上增长到16为基准对齐量(16)的一倍

      通过在Uniform块定义之前添加layout (std140)语句,我们告诉OpenGL这个Uniform块使用的是std140布局。

使用Uniform缓冲

简介

我们已经讨论了如何在着色器中定义Uniform块,并设定它们的内存布局了,但我们还没有讨论该如何使用它们。

绑定点

在OpenGL上下文中,定义了一些绑定点(Binding Point),我们可以将一个Uniform缓冲(图中的右边)链接至它。

在创建Uniform缓冲之后,我们将它绑定到其中一个绑定点上,并将着色器中的Uniform块(图中的左边)绑定到相同的绑定点,把它们连接到一起。

  • Uniform块绑定到一个特定的绑定点中

    // 将shaderA中的Lights Uniform块的索引点链接为绑定点的2号索引上
    unsigned int lights_index = glGetUniformBlockIndex(shaderA.ID, "Lights");   
    glUniformBlockBinding(shaderA.ID, lights_index, 2);
    
    • glGetUniformBlockIndex

      用来获取Uniform块索引(Uniform Block Index),是着色器中已定义Uniform块的位置值索引

      接受一个着色器程序对象Uniform块的名称

    • glGetUniformBlockIndex

      • 第一个参数是一个着色器程序对象

      • 第二个参数是一个Uniform块索引和链接到的绑定点

    /*从OpenGL 4.2版本起,你也可以添加一个布局标识符,显式地将Uniform块的绑定点储存在着色器中,这样就不用再调用glGetUniformBlockIndex和glUniformBlockBinding了。下面的代码显式地设置了Lights Uniform块的绑定点。*/
    layout(std140, binding = 2) uniform Lights { ... };
    
  • 绑定Uniform缓冲对象到相同的绑定点上

    // 将uboExampleBlock缓冲链接为绑定点的2号索引上
    glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboExampleBlock); 
    // 或
    glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
    
    • glBindbufferBase

      一个绑定点索引和一个Uniform缓冲对象作为它的参数

    • glBindBufferRange

      • 除了绑定点索引与Uniform缓冲对象,还需要一个附加的偏移量和大小参数
      • 这样子你可以绑定Uniform缓冲的特定一部分到绑定点中。
      • 可以让多个不同的Uniform块绑定到同一个Uniform缓冲对象上
  • 向Uniform缓冲中添加数据

    glBufferSubData函数,用一个字节数组添加所有的数据,或者更新缓冲的一部分。

    glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
    int b = true; // GLSL中的bool是4字节的,所以我们将它存为一个integer
    // 将缓冲的144字节开始的4个字节填充为b 
    glBufferSubData(GL_UNIFORM_BUFFER, 144, 4, &b);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    

    对应的Uniform块,缓冲的144是boolean的对齐偏移量,4是boolean的基准对齐量

    layout (std140) uniform ExampleBlock
    {
                         // 基准对齐量       // 对齐偏移量
    	.....
        float values[3]; // 16              // 96  (values[0])
                         // 16              // 112 (values[1])
                         // 16              // 128 (values[2])
        bool boolean;    // 4               // 144
        .....
    }; 
    

例子

  • glsl

    #version 330 core
    layout (location = 0) in vec3 aPos;
    
    layout (std140) uniform Matrices
    {
        mat4 projection;
        mat4 view;
    };
    uniform mat4 model;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(aPos, 1.0);
    }
    
  • 首先,我们将四个顶点着色器的Uniform块设置为绑定点0

    这4个着色器程序对象都使用这个顶点着色器,都各自具有一个uniform块,都链接到绑定点0号

    unsigned int uniformBlockIndexRed    = glGetUniformBlockIndex(shaderRed.ID, "Matrices");
    unsigned int uniformBlockIndexGreen  = glGetUniformBlockIndex(shaderGreen.ID, "Matrices");
    unsigned int uniformBlockIndexBlue   = glGetUniformBlockIndex(shaderBlue.ID, "Matrices");
    unsigned int uniformBlockIndexYellow = glGetUniformBlockIndex(shaderYellow.ID, "Matrices");  
    
    glUniformBlockBinding(shaderRed.ID,    uniformBlockIndexRed, 0);
    glUniformBlockBinding(shaderGreen.ID,  uniformBlockIndexGreen, 0);
    glUniformBlockBinding(shaderBlue.ID,   uniformBlockIndexBlue, 0);
    glUniformBlockBinding(shaderYellow.ID, uniformBlockIndexYellow, 0);
    
  • 我们创建Uniform缓冲对象本身

    unsigned int uboMatrices
    glGenBuffers(1, &uboMatrices);
    
    glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
    glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    
    glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 * sizeof(glm::mat4));
    

    首先我们为缓冲分配了足够的内存,它等于glm::mat4大小的两倍。GLM矩阵类型的大小直接对应于GLSL中的mat4。接下来,我们将缓冲中的特定范围(在这里是整个缓冲)链接到绑定点0

    个Uniform对应个Uniform缓冲

  • 填充这个缓冲

    glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);
    glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
    // 向Uniform缓冲中添加数据,0位置开始,1个mat4大小,代表前个部分
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection));
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    

    这里我们将投影矩阵储存在Uniform缓冲的前半部分。

    我们会将观察矩阵更新到缓冲的后半部分:

    glm::mat4 view = camera.GetViewMatrix();           
    glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
    // 向Uniform缓冲中添加数据,1个mat4大小起始位置,1个mat4大小,代表后半部分
    glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    

    只需要设置一次

  • 现在要用4个不同的着色器绘制4个立方体,它们的投影和观察矩阵都会是一样的。

    glBindVertexArray(cubeVAO);
    shaderRed.use();
    glm::mat4 model;
    model = glm::translate(model, glm::vec3(-0.75f, 0.75f, 0.0f));  // 移动到左上角
    shaderRed.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 36);        
    // ... 绘制绿色立方体
    // ... 绘制蓝色立方体
    // ... 绘制黄色立方体 
    

    唯一需要设置的uniform只剩model uniform了。在像这样的场景中使用Uniform缓冲对象会让我们在每个着色器中都剩下一些uniform调用。最终的结果会是这样的:

  • 效果

    请添加图片描述

Uniform缓冲对象比Uniform的优点

  • 一次设置很多uniform会比一个一个设置多个uniform要快很多。
  • 比起在多个着色器中修改同样的uniform,在Uniform缓冲中修改一次会更容易一些。
  • 你可以在着色器中使用更多的uniform。OpenGL限制了它能够处理的uniform数量,这可以通过GL_MAX_VERTEX_UNIFORM_COMPONENTS来查询。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于QT的智能家居中控系统的简明设计

文章目录 系统总体说明主板UI设计后续改进与完善 系统总体说明 系统采用 “主从式架构” &#xff0c;即一主多从式&#xff0c;该智能居家控制系统的主要功能包括登录功能、注册功能、音乐播放功能、时间显示、日历显示、温度湿度光照气压海拔数据等环境指标数据显示等。   …

Linux之理解文件系统——文件的管理

文章目录 前言一、磁盘1.磁盘的物理结构2.磁盘的存储结构3.磁盘的逻辑结构 二、文件系统与inode1.文件在磁盘中是如何存储的&#xff1f;2.对文件进行操作 三、软硬链接1.软链接创建软链接&#xff1a;inode删除软链接&#xff1a;软链接的作用&#xff1a; 2.硬链接创建硬链接…

堆(堆排序 模拟堆)

目录 一、堆的数据结构二、堆的操作方法往下调整的示意图往上调整的示意图相关功能的实现思路1.插入一个数2.求最小值3.删除最小值4.删除任意一个元素5.修改任意一个元素 三、堆的实战运用堆排序模拟堆 一、堆的数据结构 堆是一个完全二叉树&#xff1a;除了最后一层结点以外&…

3ds MAX 基本体建模,长方体、圆柱体和球体

3ds MAX基本页面如下&#xff1a; 生成新的几何体在右侧&#xff1a; 选择生成的对象类型即可&#xff0c;以下为例子&#xff1a; 1、长方体建模 选择建立的对象类型为长方形 在 任意一个窗口绘制&#xff0c;鼠标滑动 这里选择左上角的俯视图 松开鼠标后&#xff0c;可以…

第18章 JQuery DataTables初始化渲染显示与排序

1 System.Linq.AsyncIEnumerableExtensions (Data\Extensions\AsyncIEnumerableExtensions.cs) namespace System.Linq { /// <summary> /// 【异步枚举数扩展--类】 /// <remarks> /// 摘要&#xff1a; /// 该类通过对System.Linq.Async中方法的自定义扩展…

C++进阶 —— set

目录 一&#xff0c;set介绍 二&#xff0c;set使用 一&#xff0c;set介绍 set是按照特定次序存储元素的关联式容器&#xff0c;元素不可重复&#xff1b;set中的元素不能在容器中修改(元素总是const)&#xff0c;但是可从容器中插入和删除它们&#xff1b;set中的元素总是按…

【测试报告】个人博客系统自动化测试报告

文章目录 项目背景项目功能测试计划功能测试测试用例执行测试的操作步骤 自动化测试设计的模块、自动化运行的结果、问题定位的结果自动化测试优点 项目背景 对于一个程序员来说&#xff0c;定期整理总结并写博客是不可或缺的步骤&#xff0c;不管是对近期新掌握的技术或者是遇…

代码随想录算法训练营第五十三天 | 力扣 1143.最长公共子序列, 1035.不相交的线, 53. 最大子序和

1143.最长公共子序列 题目 1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符…

SpringBoot——原理(自动配置+原理分析-源码跟踪)

源码跟踪 从Springboot的启动类进入&#xff0c;进行分析. 源码跟踪技巧 在以后接触各种框架的时候&#xff0c;如果需要查看源码&#xff0c;需要找到关键点和核心流程&#xff0c;先在宏观对整个原理和流程有一个认识&#xff0c;之后再去了解其中的细节。 按住Ctrl左键进…

怎么实现常用网络接口自动化测试框架应用?

一、RESTful&#xff08;resource representational state transfer)类型接口测试 (一&#xff09;GUI界面测试工具&#xff1a;jmeter 1、添加线程组 2、添加http请求 3、为线程组添加察看结果树 4、写入接口参数并运行 5、在查看结果树窗口查看结果 6、多组数据可增加CSVDat…

基于物理信息的神经网络(Physics-informed Neural Networks;PINNs)Part-1(简单介绍)

【摘要】 基于物理信息的神经网络&#xff08;Physics-informed Neural Networks&#xff0c;简称PINNs&#xff09;&#xff0c;是一类用于解决有监督学习任务的神经网络&#xff0c;它不仅能够像传统神经网络一样学习到训练数据样本的分布规律&#xff0c;而且能够学习到数学…

UFS 2 -UFS架构简介2

UFS 2 -UFS架构简介2 1 UFS架构简介1.1 System Boot and Enumeration1.2 UFS Interconnect (UIC) Layer1.2.1 UFS Physical Layer Signals1.2.2 MIPI UniPro1.2.3 MIPI UniPro Related Attributes 1.3 UFS Transport Protocol (UTP) Layer1.3.1 Architectural Model1.3.1.1 Cli…

图解max{X,Y}和min{X,Y}并求相关概率

图解max{X,Y}和min{X,Y}并求相关概率 对max{X,Y}或min{X,Y}进行分解再求解 P ( m a x { X , Y } ≥ c ) P [ ( X ≥ c ) ∪ ( Y ≥ c ) ] P ( m a x { X , Y } ≤ c ) P [ ( X ≤ c ) ∩ ( Y ≤ c ) ] P ( m i n { X , Y } ≥ c ) P [ ( X ≥ c ) ∩ ( Y ≥ c ) ] P ( m i…

k8s功能优势应用场景介绍(一)

一&#xff0c;K8S功能: 1、数据卷 pod中容器之间共享数据&#xff0c;可以使用数据卷 2、应用程序健康检查 容器内服务可能进程阻塞无法处理请求&#xff0c;可以设置监控检查策略保证应用健壮性 3、复制应用程序实例 控制器维护着pod副本数量&#xff0c;保证一个pod或一组同…

C++11 auto类型推导

1.类型推导 C11引入了auto 和 decltype 关键字实现类型推导&#xff0c;通过这两个关键字不仅能方便地获取复杂的类型&#xff0c;而且还能简化书写&#xff0c;提高编码效率。 auto 类型推导的语法和规则 在之前的 C 版本中&#xff0c;auto 关键字用来指明变量的存储类型…

Allure测试报告定制全攻略,优化你的Web自动化测试框架!

目录 前言&#xff1a; 1. Allure测试报告简介 2. Web自动化测试框架简介 3. 封装Web自动化框架 3.1 安装Selenium 3.2 封装Selenium 3.3 定制Allure测试报告 3.3.1 适配翻译插件 3.3.2 定制测试报告样式 4. 示例代码 5. 总结 前言&#xff1a; 随着现在Web应用的普…

SciencePub学术 | 计算机科学类重点SCIEI征稿中

SciencePub学术刊源推荐: 计算机科学类SCI&EI征稿中&#xff01;录用率高&#xff0c;自引率低&#xff0c;进展顺利。信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 【期刊简介】IF&#xff1a;4.0-4.5↑&#xff0c; JCR 2区&#xff0c;中科院3区…

SpringAOP简介及实现(包含切面、切点、连接点和通知)

目录 1.什么是AOP、SpringAOP&#xff1f; 2.AOP的组成 3.SpringAOP的实现 4.切点的表达式 1.什么是AOP、SpringAOP&#xff1f; 在学习SpringAOP之前&#xff0c;我们得先了解一下什么是AOP。AOP是一种面向切面编程的思想。那什么是切面呢&#xff1f;它其实是对某一类事情…

【HR专用】Vue+SpringBoot,实现人才招聘库的开发(后端部分)

人才招聘库是企业用于储存和管理潜在候选人信息的数据库。通常情况下&#xff0c;这些候选人可能已经应聘过公司的职位&#xff0c;也可能是通过其他途径获取的&#xff0c;例如社交网络、招聘网站等。 对于一个中小公司来说&#xff0c;人力资源部绝对是一个重要部门&#xff…

测试类型(单元、集成、系统或手动测试)

测试类型(单元、集成、系统或手动测试) 单元测试 单元是系统的单个组件&#xff0c;例如类或单个方法。孤立地测试单元称为单元测试。 优点&#xff1a;速度快/易控/易写 缺点&#xff1a;缺乏现实性/无法捕获所有错误&#xff08;例如与其他组件或服务的交互&#xff09; 单元…