当前位置: 首页 > 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文件配…...

SpringBoot 动态操作定时任务(启动、停止、修改执行周期)增强版

前段时间编写了一篇博客SpringBoot 动态操作定时任务&#xff08;启动、停止、修改执行周期&#xff0c;该篇博客还是帮助了很多同学。 但是该篇博客中的方法有些不足的地方&#xff1a; 只能通过前端控制器controller手动注册任务。【具体的应该是我们提前配置好我们的任务&am…...

快排函数 -- qsort函数(Quick Sort)

文章目录&#x1f50e;1.qsort函数简介&#x1f4a1;1.1.函数原型&#x1f4a1;1.2.参数含义&#x1f50e;2.比较函数介绍&#x1f50e;3.比较函数使用案例&#x1f4a1;3.1.整型数组&#x1f4a1;3.2.浮点型数组&#x1f4a1;3.3.结构体类型 - 字符串&#x1f50e;4.利用冒泡排…...

条形码和二维码

前言&#xff1a;需要的包的相关文档 1. Barcode&#xff1a;https://pypi.org/project/python-barcode/0.8.1/ 2. Qrcode&#xff1a;https://pypi.org/project/qrcode/ 3. Zbar: https://pypi.org/project/pyzbar/ 4. Opencv: https://docs.opencv.org/3.4.11/ 5. OpenC…...

大数据-学习实践-5企业级解决方案

大数据-学习实践-5企业级解决方案 (大数据系列) 文章目录大数据-学习实践-5企业级解决方案1知识点2具体内容2.1小文件问题2.1.1 SequenceFile2.1.2 MapFile2.1.3 小文件存储计算2.2数据倾斜2.3 YARN2.3.1 YARN架构2.3.2 YARN调度器2.3.2 YARN多资源队列配置和使用2.4Hadoop官方…...

破解吲哚花菁素IR-808 N3,IR-808 azide,IR-808叠氮,酯溶性染料修饰叠氮基团,相关知识

基础产品数据&#xff08;Basic Product Data&#xff09;&#xff1a;CAS号&#xff1a;N/A中文名&#xff1a;IR-808叠氮英文名&#xff1a;IR-808 N3&#xff0c;IR-808 azideIR-808结构式&#xff08;Structural&#xff09;&#xff1a;详细产品数据&#xff08;Detailed …...

面试官:MQ的好处到底有哪些?

&#x1f497;推荐阅读文章&#x1f497; &#x1f338;JavaSE系列&#x1f338;&#x1f449;1️⃣《JavaSE系列教程》&#x1f33a;MySQL系列&#x1f33a;&#x1f449;2️⃣《MySQL系列教程》&#x1f340;JavaWeb系列&#x1f340;&#x1f449;3️⃣《JavaWeb系列教程》…...

事务机制:Redis能实现ACID属性吗?

ACID特性无需多言。我们知道关系数据库比如mysql可以实现事务的ACID特性&#xff0c;begin,commit,回滚实现。 那么redis可以实现ACID吗&#xff0c;结论是不能完全保证。 首先要知道redis通过MULTI关键字开启事务&#xff0c;中间一系列操作&#xff0c;加到操作队列中并不执…...

如何在 Apinto 实现 HTTP 与 gRPC 的协议转换(上)

什么是 gRPC 像 gRPC 是由 google 开发的一个高性能、通用的开源 RPC 框架&#xff0c;主要面向移动应用开发且基于 HTTP/2 协议标准而设计&#xff0c;同时支持大多数流行的编程语言。 gRPC 基于 HTTP/2 协议传输&#xff0c;而 HTTP/2 相比 HTTP1.x &#xff0c;有以下优势:…...

3分钟看完-丄-Python自动化测试【项目实战解析】经验分享

目录&#xff1a;导读 引言 自动化测试 背景 测试团队 测试体系发展 测试平台 自动化测试现状 现状一&#xff1a; 现状二&#xff1a; 现状三&#xff1a; 现状四&#xff1a; 现状五&#xff1a; 现状六&#xff1a; 失败的背景 失败的经历 失败总结 引言 内…...

Web漏洞-命令执行和代码执行漏洞

命令执行原理就是指用户通过浏览器或其他辅助程序提交执行命令&#xff0c;由于服务器端没有针对执行函数做过滤&#xff0c;导致在没有指定绝对路径的情况下就执行命令。漏洞成因它所执行的命令会继承WebServer的权限&#xff0c;也就是说可以任意读取、修改、执行Web目录下的…...

国外做化学申报的网站/百度里面的站长工具怎么取消

转载自http://m.blog.csdn.net/csdn15698845876/article/details/73278120 h5py简单介绍 h5py文件是存放两类对象的容器&#xff0c;数据集(dataset)和组(group)&#xff0c;dataset类似数组类的数据集合&#xff0c;和numpy的数组差不多。group是像文件夹一样的容器&#xff0…...

网站编程培训学校招生/搜索引擎优化文献

提交一个 服务器请求&#xff08;support request&#xff09; 然后在你的服务请求中同时提供下面的信息。 Confluence 服务器 登录 Confluence 然后访问管理员控制台。 将 系统信息&#xff08;System Information&#xff09;页面的中内容进行截图&#xff0c;或者保存页面为…...

简易广州网站建设/外贸建站seo

第四章 进程 1、windows支持两种应用程序&#xff1a;GUI程序和CUI程序&#xff0c;即图形用户界面程序和控制台应用程序。 在Visual Studio中&#xff0c;可以使用项目属性的连接器开关设置选择哪种程序&#xff0c;/SUBSYSTEM:CONSOLE和/SUBSYSTEM:WINDOWS 当运行应用程序时操…...

wordpress隐私提示/企业推广宣传方式

在使用MyBatis插入数据进入数据库的时候会用到sequence序列来生成自增的id 这时可以使用selectKey就可以得到sequence的值&#xff0c;同时也会将值返回。不过对于不同的数据库有不同的操作方式。 oracle&#xff1a; < insert id“insertTeacher” parameterClass“map”&g…...

dreamweaver绿色版下载/seo搜索引擎优化推荐

本文刚刚发在51CTO.com网站&#xff0c;文章链接&#xff1a;[url]http://soft.51cto.com/art/200611/34788.htm[/url]11月中旬&#xff0c;CA EXPO 2006分别在上海和北京召开。作为一直与CA保持联系的记者&#xff0c;51CTO老杨受邀参与北京站的会议。我是2000年开始接触和了解…...

织梦新闻门户网站模板/网络推广外包公司

1&#xff0c;空指针和索引越界 ArrayIndexOutOfBoundsException:数组索引越界异常 原因&#xff1a;你访问了不存在的索引。 b:NullPointerException:空指针异常 原因&#xff1a;数组已经不在指向堆内存了。而你还用数组名去访问元素。 【1】ArrayIndexOutOfBoundsExcepti…...