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

LearnOpenGL-高级OpenGL-6.天空盒

本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正

我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject

文章目录

  • 天空盒
    • 介绍
    • 如何采样
    • OpenGL纹理目标
    • 例子0:天空盒效果
  • 环境映射
    • 反射
      • 例子1:Cube反射
      • 例子2:模型反射
    • 折射
      • 例子1:Cube折射
      • 例子2:模型折射
  • 测试-先渲染天空盒再渲染物体,默认深度LESS比较方式

天空盒

介绍

立方体贴图就是一个包含了6个2D纹理的纹理,每个2D纹理都组成了立方体的一个面:一个有纹理的立方体

如何采样

  • 方向向量的大小并不重要,只要提供了方向,OpenGL就会获取方向向量(最终)所击中的纹素,并返回对应的采样纹理值。
  • 只要立方体的中心位于原点,我们就能使用立方体的实际位置向量来对立方体贴图进行采样了。
  • 我们可以将所有顶点的纹理坐标当做是立方体的顶点位置。最终得到的结果就是可以访问立方体贴图上正确面(Face)纹理的一个纹理坐标。

立方体有36个顶点位置,在顶点着色器后每个片段都有自己的顶点位置,采样天空盒时用这个顶点位置当做纹理坐标即可。

OpenGL纹理目标

纹理目标方位
GL_TEXTURE_CUBE_MAP_POSITIVE_X
GL_TEXTURE_CUBE_MAP_NEGATIVE_X
GL_TEXTURE_CUBE_MAP_POSITIVE_Y
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
GL_TEXTURE_CUBE_MAP_POSITIVE_Z
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z

例子0:天空盒效果

  • 加载天空盒

    // 加载纹理// -------------
    unsigned int cubeTexture = loadTexture(FileSystem::getPath("assest/textures/container.jpg").c_str());
    // 加载天空盒
    vector<std::string> faces{FileSystem::getPath("assest/textures/skybox/right.jpg"),FileSystem::getPath("assest/textures/skybox/left.jpg"),FileSystem::getPath("assest/textures/skybox/top.jpg"),FileSystem::getPath("assest/textures/skybox/bottom.jpg"),FileSystem::getPath("assest/textures/skybox/front.jpg"),FileSystem::getPath("assest/textures/skybox/back.jpg")
    };
    unsigned int cubemapTexture = loadCubemap(faces);
    // 加载天空盒
    // 加载顺序
    // order:
    // +X (right)
    // -X (left)
    // +Y (top)
    // -Y (bottom)
    // +Z (front) 
    // -Z (back)
    unsigned int loadCubemap(vector<std::string> faces) {unsigned int textureID;glGenTextures(1, &textureID);glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);int width, height, nrChannels;for (unsigned int i = 0; i < faces.size(); i++) {unsigned char* data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);if (data) {glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);stbi_image_free(data);}else {std::cout << "Cubemap texture failed to load at path:" << faces[i] << std::endl;stbi_image_free(data);}}glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);;glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);;glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);;glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);;glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);;return textureID;
    }
    
  • 为天空盒创建立方体的六个面的顶点数据以及VAO VBO

    // skybox VAO
    unsigned int skyboxVAO, skyboxVBO;
    glGenVertexArrays(1, &skyboxVAO);
    glGenBuffers(1, &skyboxVBO);
    glBindVertexArray(skyboxVAO);
    glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glBindVertexArray(0);
    
  • 渲染

    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 view = camera.GetViewMatrix();
    glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);// 渲染立方体
    shader.use();
    view = camera.GetViewMatrix();
    shader.setMat4("model", model);// 不变,在中心
    shader.setMat4("view", view);
    shader.setMat4("projection", projection);
    glBindVertexArray(cubeVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, cubeTexture);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);// 渲染天空盒
    // 重点代码:小于等于。由于深度缓冲区的默认值为1,而到顶点着色器里设置了天空盒的深度值为1,所以要为小于等于,1=1,测试才通过才到片段着色器采样颜色
    glDepthFunc(GL_LEQUAL);
    skyboxShader.use();
    //view = camera.GetViewMatrix();
    // 重点代码:取4x4矩阵左上角的3x3矩阵来移除变换矩阵的位移部分,再变回4x4矩阵。///
    // 防止摄像机移动,天空盒会受到视图矩阵的影响而改变位置,即摄像机向z后退,天空盒和cube向z前进
    view = glm::mat4(glm::mat3(camera.GetViewMatrix()));
    skyboxShader.setMat4("view", view);
    skyboxShader.setMat4("projection", projection);
    glBindVertexArray(skyboxVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);// 第一个参数从GL_TEXTURE_2D 变为GL_TEXTURE_CUBE_MAP
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    glDepthFunc(GL_LESS);
    
  • glsl和采样

    #version 330 core
    layout (location = 0) in vec3 aPos;// 纹理坐标是3维的
    out vec3 TexCoords;
    // 不用model转换到世界矩阵
    uniform mat4 projection;
    uniform mat4 view;
    void main()
    {// 纹理坐标等于位置坐标/TexCoords = aPos;vec4 pos = projection * view * vec4(aPos, 1.0);// z为w,透视除法除后z=(z=w/w)=1,深度为最远///gl_Position = pos.xyww;
    }
    
    #version 330 core
    out vec4 FragColor;// 纹理坐标是3维的
    in vec3 TexCoords;// 纹理坐标// 天空盒纹理采样
    uniform samplerCube skybox;void main(){ FragColor = texture(skybox, TexCoords);
    }
    
  • 关键地方

    • 天空盒不会跟随摄像机移动

      // 重点代码:取4x4矩阵左上角的3x3矩阵来移除变换矩阵的位移部分,再变回4x4矩阵。
      // 防止摄像机移动,天空盒会受到视图矩阵的影响而改变位置,即摄像机向z后退,天空盒和cube向z前进
      view = glm::mat4(glm::mat3(camera.GetViewMatrix()));
      
    • 天空盒后渲染,也不会覆盖先前绘制的物体

      • 先绘制其它物体

      • 设置深度测试为小于等于

      • 绘制天空盒

        在天空盒的顶点着色器运行后,会执行透视除法,将gl_Position的xyz坐标除以w分量,将gl_Position的xyz坐标除以w分量(透视除法所做)。

        所以我们设置天空盒的z为w,z=(z=w/w)=1

        gl_Position = pos.xyww;// z为w,透视除法除后z=(z=w/w)=1,深度为最远
        
      • 由于深度测试为小于等于(结合下面图示)

        • 在其他物体占据片段的深度缓冲值<=1

          天空盒的深度值1小于等于这些片段的缓冲值,所以不会通过深度测试,从而保持原有的物体片段颜色。

        • 其他物体占据片段深度缓冲的默认值为1

          天空盒的深度值1小于等于深度缓冲的值1,所以会通过深度测试,从而输出天空盒片段。

      • 错误做法,将深度测试为默认的小于

        • 其他物体占据片段深度缓冲的默认值为1

          天空盒的深度值1不小于深度缓冲区的默认值1不会通过深度测试,从而具有天空盒的颜色的片段不会输出到屏幕上。

  • 效果

环境映射

  • 什么是环境映射

    通过使用环境的立方体贴图,我们可以给物体反射折射的属性。

    这样使用环境立方体贴图的技术叫做环境映射(Environment Mapping),其中最流行的两个是反射(Reflection)和折射(Refraction)。

反射

  • 原理图

例子1:Cube反射

  • 代码

    立方体的shader,天空盒的shader不变(还是和上面例子:天空盒效果的一样)

    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aNormal;out vec3 Normal;
    out vec3 Position;uniform mat4 projection;
    uniform mat4 model;
    uniform mat4 view;
    void main()
    {// 法线矩阵Normal = mat3(transpose(inverse(model))) * aNormal;// 到世界空间Position = vec3(model * vec4(aPos, 1.0));// 这里不再是gl_Position = pos.xyww;因为这是中间立方体的,不是天空盒的shadergl_Position = projection * view * vec4(aPos, 1.0); 
    }
    
    #version 330 core
    out vec4 FragColor;in vec3 Normal;
    in vec3 Position; // 片段的坐标-世界空间uniform vec3 cameraPos;// 天空盒纹理采样
    uniform samplerCube skybox;void main(){ // 从眼睛位置指向片段位置vec3 I = normalize(Position - cameraPos);vec3 R = reflect(I, normalize(Normal));// 采样天空盒的uv坐标是3维的FragColor = vec4(texture(skybox, R).rgb, 1.0);// FragColor = texture(skybox, R); 这个效果一样
    }
    

    cpp

    Shader shader("assest/shader/4高级OpenGL/6.2.1.cube-反射天空盒.vs", "assest/shader/4高级OpenGL/6.2.1.cube-反射天空盒.fs");
    Shader skyboxShader("assest/shader/4高级OpenGL/6.1.1.天空盒-普通效果.vs", "assest/shader/4高级OpenGL/6.1.1.天空盒-普通效果.fs");
    .....
    // shader configuration
    // --------------------
    shader.use();
    shader.setInt("skybox", 0);skyboxShader.use();
    skyboxShader.setInt("skybox", 0);glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);// 第一个参数从GL_TEXTURE_2D 变为GL_TEXTURE_CUBE_MAP// render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {// 渲染立方体shader.use();view = camera.GetViewMatrix();shader.setMat4("model", model);// 不变,在中心shader.setMat4("view", view);shader.setMat4("projection", projection);// 为了反射传入shader.setVec3("cameraPos", camera.Position);glBindVertexArray(cubeVAO);glDrawArrays(GL_TRIANGLES, 0, 36);glBindVertexArray(0);// 其它和天空盒的代码一样
    
  • 效果

    请添加图片描述

    箱子上的贴图是后面的天空盒贴图

例子2:模型反射

  • 代码

    立方体的shader,天空盒的shader不变(还是和上面例子:天空盒效果的一样)

    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aNormal;
    layout (location = 2) in vec2 aTexCoords;out vec3 Normal;
    out vec3 Position; // 片段的坐标-世界空间
    out vec2 TexCoords;// 纹理坐标uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;void main()
    {gl_Position = projection * view * model * vec4(aPos, 1.0);TexCoords = aTexCoords;// 到世界空间Position = vec3(model * vec4(aPos, 1.0));// 这里不再是gl_Position = pos.xyww;因为这是中间立方体的,不是天空盒的shaderNormal = mat3(transpose(inverse(model))) * aNormal;
    }
    
    #version 330 core
    out vec4 FragColor;in vec3 Normal;
    in vec3 Position; // 片段的坐标-世界空间
    in vec2 TexCoords;// 纹理坐标uniform vec3 cameraPos;
    uniform sampler2D texture_diffuse1;
    uniform sampler2D texture_specular1;
    uniform sampler2D texture_height1;// 天空盒纹理采样
    uniform samplerCube skybox;void main(){ vec3 I = normalize(Position - cameraPos);vec3 R = reflect(I, normalize(Normal));// 采样镜面光贴图颜色(uv坐标是2维的)vec4 specular4 = texture(texture_specular1, TexCoords); // 采样出来的颜色是4维的vec3 specular3 = specular4.rgb;// 采样天空盒颜色(uv坐标是3维的)并乘以镜面光贴图颜色FragColor = vec4(texture(skybox, R).rgb * specular3, 1.0) ;// FragColor = vec4(texture(skybox, R).rgb, 1.0) ;// 未乘以镜面光贴图颜色
    }
    

    cpp

    // 加载模型
    Model ourModel(FileSystem::getPath("assest/model/nanosuit/nanosuit.obj"));// shader configuration
    // --------------------
    shader.use();
    shader.setInt("skybox", 4);skyboxShader.use();
    skyboxShader.setInt("skybox", 4);
    // 设置的天空盒的纹理单元位置,好像不会与普通的纹理冲突,但保险起见还是设为4
    glActiveTexture(GL_TEXTURE4);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);// 第一个参数从GL_TEXTURE_2D 变为GL_TEXTURE_CUBE_MAPwhile (!glfwWindowShouldClose(window))
    {// 渲染这个模型// 为了反射传入model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f));shader.use();shader.setVec3("cameraPos", camera.Position);shader.setMat4("model", model);shader.setMat4("view", view);shader.setMat4("projection", projection);ourModel.Draw(shader);
    }
    
  • 效果

    采样天空盒颜色,未乘以镜面光贴图颜色

    采样天空盒颜色,并乘以镜面光贴图颜色

    请添加图片描述

折射

  • 原理

  • 折射率表

    材质折射率
    空气1.00
    1.33
    1.309
    玻璃1.52
    钻石2.42

    例子中,光线/视线从空气(折射率1)进入玻璃(如果我们假设箱子是玻璃制的),所以比值为1.00/1.52=0.658

例子1:Cube折射

  • 代码

    和反射的代码差不多,就是中间立方体的glsl片段着色器代码不一样

    void main(){ float ratio = 1.00 / 1.52;vec3 I = normalize(Position - cameraPos);vec3 R = refract(I, normalize(Normal), ratio);// refract,第三个参数是折射率// 采样天空盒颜色(uv坐标是3维的)FragColor = vec4(texture(skybox, R).rgb, 1.0);// FragColor = texture(skybox, R); 这个效果一样
    }
    
  • 效果

    请添加图片描述

例子2:模型折射

  • 代码

    void main(){ float ratio = 1.00 / 1.52;vec3 I = normalize(Position - cameraPos);vec3 R = refract(I, normalize(Normal), ratio);// refract,第三个参数是折射率// 采样天空盒颜色(uv坐标是3维的)FragColor = vec4(texture(skybox, R).rgb, 1.0);// FragColor = texture(skybox, R); 这个效果一样
    }
    
  • 效果

    请添加图片描述

测试-先渲染天空盒再渲染物体,默认深度LESS比较方式

  • 代码

    // 将天空盒的盒子长宽为20
    float skyboxVertices[] = {// positions          -10.0f,  10.0f, -10.0f,-10.0f, -10.0f, -10.0f,.....
    };
    // 渲染天空盒
    //glDepthFunc(GL_LEQUAL); // 不用LEQUAL而是默认的LESS
    skyboxShader.use();
    // 重点代码:取4x4矩阵左上角的3x3矩阵来移除变换矩阵的位移部分,再变回4x4矩阵。
    // 防止摄像机移动,天空盒会受到视图矩阵的影响而改变位置,即摄像机向z后退,天空盒和cube向z前进
    view = glm::mat4(glm::mat3(camera.GetViewMatrix()));
    skyboxShader.setMat4("view", view);
    skyboxShader.setMat4("projection", projection);
    glBindVertexArray(skyboxVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);// 第一个参数从GL_TEXTURE_2D 变为GL_TEXTURE_CUBE_MAP
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    //glDepthFunc(GL_LESS);// 渲染立方体
    shader.use();
    view = camera.GetViewMatrix();
    shader.setMat4("model", model);// 不变,在中心
    shader.setMat4("view", view);
    shader.setMat4("projection", projection);
    glBindVertexArray(cubeVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, cubeTexture);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    

    天空盒的顶点位置z透视除法后不为1

    //gl_Position = pos.xyww;// z=w,透视除法除后还是1,深度为最远
    gl_Position= projection * view * vec4(aPos, 1.0);
    
  • 解释代码顺序

    • 天空盒的盒子长宽为20

    • 先绘制天空盒,再绘制箱子

    • 这代码天空盒将不会受摄像机的观察矩阵的位移部分影响

      所以虽然glsl天空盒的深度值z未设置w,但是视觉上依旧是无限远

      不过实际上现在代码造成的影响是,不论摄像机所在什么位置,以摄像机为原点,处在一个20*20大小的立方体盒子,在20*20范围内的物体被显示,20*20外的物体被天空盒颜色所覆盖。

      换句话说:注意摄像机在原点,所以20*20的盒子半径为10,于是原点为出发点距离摄像机长度小于10的物体会显示,大于10的物体会被天空盒颜色所覆盖。

  • 进一步解释(结合下方图)

    • 箱子离摄像机的距离 <10(第一幅图)

      箱子的深度值小于天空盒,所以天空盒同箱子所占的片段区域会被丢弃,显示箱子的片段颜色

    • 箱子离摄像机的距离 > 10(第二幅图)

      箱子的深度值大于天空盒,所以天空盒同箱子所占的片段区域会覆盖箱子,显示天空盒的片段颜色

相关文章:

LearnOpenGL-高级OpenGL-6.天空盒

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject 文章目录天空盒介绍如何采样OpenGL纹理目标例子0&#xff1a;天空盒效果环境映射反射例子1&#xff1a;Cube…...

Printk打印内核日志

一、背景 Linux 内核中提供了内核日志打印的工具printk。它的使用方式C语言中的printf是类似的。接下来我们介绍一下printk的使用方式。本文以打印Binder中的日志为例&#xff0c;进行演示。 printk的方法声明和日志级别binder驱动中增加 打印代码android系统中查看日志信息 …...

界面控件DevExpress WPF 202计划发布的新功能合集

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。本文将介绍今年DevExpr…...

Spring Cloud Alibaba 微服务2,注册中心演变 + Nacos注册中心与配置中心

目录专栏导读一、什么是Nacos&#xff1f;二、注册中心演变及其设计思想1、RestTemplate调用远程服务2、通过Nginx维护服务列表&#xff08;upStream&#xff09;3、通过Nacos实现注册中心4、心跳版Nacos三、Nacos Discovery四、Nacos核心功能1、服务注册2、服务心跳3、服务同步…...

Navicat 图形化界面工具

Navicat 介绍 Navicat是一套可创建多个连接的数据库管理工具&#xff0c;用以方便管理 MySQL、Oracle、SQL Server等不同类型的数据库 目录 Navicat 介绍 Navicat 下载 Navicat 安装 Navicat 使用 Navicat连接MySQL数据库 Navicat创建数据库和表 Navicat 下载 1、点击这…...

2023年网络安全比赛--attack(新)数据包分析中职组(超详细)

一、竞赛时间 180分钟 共计3小时 任务环境说明: 1 分析attack.pcapng数据包文件,通过分析数据包attack.pcapng找出恶意用户第一次访问HTTP服务的数据包是第几号,将该号数作为Flag值提交; 2.继续查看数据包文件attack.pcapng,分析出恶意用户扫描了哪些端口,将全部的端口号…...

C语言之extern(七十)

extern同一个文件&#xff1a;修饰变量声明#include <stdio.h>int add(){extern int x,y;return x y; }int main(){printf("%d\n", add()); }int x 10; int y 20;extern文件之间&#xff1a;修饰函数声明<1>.add.cint sum(){extern int x ;extern in…...

树的前中后序的Morris遍历

目录 一.Morris遍历 1.什么是Morris遍历 2.基本思想 3.Morris遍历的优点和缺点 4.知识回顾----二叉树的线索化 二.中序Morris遍历 1.中序Morris遍历的分析 2.中序Morris遍历的思路 3.具体的代码实现 三.前序Morris遍历 1.前序Morris遍历的思路 2.具体的代码实现 四…...

到底什么是线程?线程与进程有哪些区别?

上一篇文章我们讲述了什么是进程&#xff0c;进程的基本调度 http://t.csdn.cn/ybiwThttp://t.csdn.cn/ybiwT 那么本篇文章我们将了解一下什么是线程&#xff1f;线程与进程有哪些区别&#xff1f;线程应该怎么去编程&#xff1f; 目录 http://t.csdn.cn/ybiwThttp://t.csdn…...

你真的知道如何系统高效地学习数据结构与算法吗?

文章目录前言&#xff1a;什么是数据结构&#xff1f;什么是算法&#xff1f;学习这个算法需要什么基础&#xff1f;学习的重点在什么地方&#xff1f;一些可以让你事半功倍的学习技巧1.边学边练&#xff0c;适度刷题2.多问、多思考、多互动3.打怪升级学习法4.知识需要沉淀&…...

Linux操作系统基础的常用命令

1&#xff0c;Linux简介Linux是一种自由和开放源码的操作系统&#xff0c;存在着许多不同的Linux版本&#xff0c;但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中&#xff0c;比如手机、平板电脑、路由器、台式计算机。1.1Linux介绍Linux出现于1991年&#xff0c…...

Jasypt加密库基本使用方法

目录 1 Jasypt简介... 2 基础知识回顾... 3 Jasypt基本加密器... 4 JasyptPBE加密器... 5 Jasypt池化加密器... 6 Jasypt客户端工具... 7 JasyptSpringboot基本用法... 8 JasyptSpringboot自定义加密器... 9 JasyptSprin…...

C++并发编程之五 高级线程管理

文章目录5.1.1 线程池5.1.1 线程池 在前面我们引入了线程的通信和同步手段&#xff0c;那么为什么还要引入线程池呢&#xff1f; 线程池是一种管理多个线程的技术&#xff0c;它可以减少线程的创建和销毁的开销&#xff0c;提高并发性能。线程池中有一定数量的空闲线程&#x…...

单片机——IIC协议与24C02

1、基础知识 1.1、IIC串行总线的组成及工作原理 I2C总线只有两根双向信号线。一根是数据线SDA&#xff0c;另一根是时钟线SCL。 1.2、I2C总线的数据传输 I2C总线进行数据传送时&#xff0c;时钟信号为高电平期间&#xff0c;数据线上的数据必须保持稳定&#xff0c;只有在时钟…...

案例05-将不必要的逻辑放到前端(发送调查问卷)

目录一&#xff1a;背景介绍背景二&#xff1a;思路&方案重大问题&#xff1a;解决办法优点&#xff1a;三&#xff1a;总结一&#xff1a;背景介绍 本篇博客书写的意义是警示大家不必把不必要的逻辑放到前端。 明确前后端分离的意义。 背景 下面的主要逻辑是&#xff1…...

【每日一题】——矩阵相等判定

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e2; 读书笔记 &#x1f7e1; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…...

Linux防火墙的关闭

查看防火墙的状态打开终端输入如下命令systemctl status firewalld如图所示&#xff1a;running表示防火墙目前处于打开状态输入命令进行关闭防火墙&#xff1a;systemctl stop firewalld如图所示正常的用户是没有权限的&#xff0c;需要输入管理员的密码才能够进行关闭防火墙。…...

Request和Response的概述

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;输出优质文章⭐作者主页&#xff1a;︶ㄣ释然⭐如果觉得文章写的不错&#xff0c;欢迎点个关注&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601;Request和Respo…...

常见的Web安全漏洞:SYN攻击/CSRF/XSS

一、SYN攻击&#xff08;属于DOS攻击&#xff09; 什么情况下被动方出现SYN_RCVD状态?(flood攻击服务) 客户伪造 ip 端口&#xff0c; 向服务端发送SYN请求。完成2次握手&#xff0c;第三次服务端 等待客户端ACK确认&#xff0c;但由于客户不存在服务端一直未收到确认&#…...

【STC15单片机】 超声波模块的使用

目录 1 基于STC15F2K60S2的超声波测距代码 1.1 基本注意事项 1.1.1 跳线帽接法 1.1.2 晶振设置 1.2 板载超声波工作原理 1.2.1 原理总结 1.2.2 超声波代码思路 1.3 STC15单片机代码部分 1.3.1 定时器0&定时器1初始化 1.3.2 超声波ultrasonic.c ultrasonic.h文件配…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...