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

LearnOpenGL-入门-你好,三角形

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

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

LearnOpenGL中文官网:https://learnopengl-cn.github.io/

文章目录

  • 图形渲染管线
    • 基本介绍
    • 着色器阶段
  • 顶点输入
  • 着色器代码流程
  • 链接顶点属性
  • 顶点数组对象VAO
  • 绘制三角形
  • 元素(索引)缓冲对象EBO
  • 小结
    • 草稿图
    • 重复重要的流程
      • 着色器流程
      • 绘制流程

图形渲染管线

基本介绍

  • 功能

    将3D坐标变为2D坐标

    将2D坐标转换为实际的有颜色的像素

  • 图形渲染管线与着色器

    图形渲染管线分为多个阶段,多个阶段对应多个自己特定的函数(小程序),在各自特定的函数可并行执行调用显卡的成千上万的核心,这些小程序被称为着色器

着色器阶段

  • 顶点数据

    数组的形式传递3个3D坐标作为图形渲染管线的输入,用来表示一个三角形,这个数组叫做顶点数据(Vertex Data)

  • 顶点着色器

    • 它把一个单独的顶点作为输入
    • 主要的目的是把3D坐标转为另一种3D坐标
  • 形状(图元)装配

    将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并所有的点装配成指定图元的形状

  • 几何着色器

    • 把图元形式的一系列顶点的集合作为输入
    • 它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状
  • 光栅化

    • 把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)
    • 在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。
  • 片段着色器

    片段着色器的主要目的是计算一个像素的最终颜色

  • Alpha测试和混合

    • 检测片段的对应的深度(和模板(Stencil))值(后面会讲),用它们来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃

    • 检查alpha值(alpha值定义了一个物体的透明度)并对物体进行混合(Blend),可以认为改变片段的颜色

在现代OpenGL中,我们必须定义至少一个顶点着色器和一个片段着色器(因为GPU中没有默认的顶点/片段着色器)。

顶点输入

  • 标准化设备坐标

    • 在顶点着色器中处理过,它们就应该是标准化设备坐标,x、y和z值在-1.0到1.0的一小段空间

    • 图示

  • 顶点数据

    float vertices[] = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f,  0.5f, 0.0f
    };
    

    一个在CPU内存的数组

  • 顶点缓冲对象VBO

    由于CPU内存的顶点数据需要传入GPU内存中,就需要在GPU内存中存储同样大小的顶点数据,而顶点缓冲对象管理这个在GPU上的内存(有点模糊这个概念)

    unsigned int VBO;
    // 1.在GPU上生成一个缓冲,返回ID
    glGenBuffers(1, &VBO);
    // 2.绑定缓冲
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    // 3.CPU内存的顶点数据复制到GPU内存中
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    

着色器代码流程

  • 创建一个着色器对象

    用glCreateShader创建这个着色器

    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    
  • 着色器源码附加到着色器对象

    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    
  • 编译着色器

    glCompileShader(vertexShader);
    

    编译完顶点着色器后,片段着色器同样这样编译

  • 两个着色器对象链接到一个用来渲染的着色器程序

    • 创建一个着色器程序对象

      unsigned int shaderProgram;
      shaderProgram = glCreateProgram();
      
    • 编译的着色器附加着色器程序对象

      glAttachShader(shaderProgram, vertexShader);
      glAttachShader(shaderProgram, fragmentShader);
      
    • glLinkProgram链接着色器程序对象

      glLinkProgram(shaderProgram);
      
  • 使用着色器程序

    glUseProgram(shaderProgram);
    
  • 着色器对象链接到着色器程序对象以后,删除着色器对象

    glDeleteShader(vertexShader); 
    glDeleteShader(fragmentShader);
    
  • 另外

    在编译着色器对象和链接时可以看是否成功

    int  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;
    }
    

链接顶点属性

  • 我们必须手动指定顶点输入数据的哪一个部分对应顶点着色器哪一个顶点属性

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    // 若第一个参数为0,对应顶点着色器的layout(location = 0) in vec3 a_Position;
    // 若第一个参数为1,对应顶点着色器的layout(location = 1) in vec4 a_Color;
    glEnableVertexAttribArray(0);// 代表启用顶点着色器location=0的输入
    

    设置好OpenGL如何解释顶点数据,但是设置的顶点数据来源于上一次将顶点缓冲对象绑定的那个VBO。

    glVertexAttribPointer参数:

    • 1:要配置的顶点属性

      layout(location = 0)

    • 2:顶点属性的大小

    • 3:数据的类型

    • 4:是否希望数据被标准化

      GL_TRUE:所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间

    • 5:步长

    • 6:偏移量

  • 由此绘制的代码

    // 省略创建缓冲
    // 0. CPU内存的顶点数据复制到GPU内存中
    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 1. 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 2. 当我们渲染一个物体时要使用着色器程序
    glUseProgram(shaderProgram);
    // 3. 绘制物体
    someOpenGLFunctionThatDrawsOurTriangle();
    

    若有第二个不同的物体(不同的顶点数据)需要渲染

    又要写一遍这个代码
    // 0. CPU内存的顶点数据复制到GPU内存中
    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 1. 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 2. 当我们渲染一个物体时要使用着色器程序
    glUseProgram(shaderProgram);
    // 3. 绘制物体
    someOpenGLFunctionThatDrawsOurTriangle();
    
  • 缺点

    由上可看出,有多少个物体,就得重复写绑定的顶点缓冲区、顶点属性指针,属实麻烦,则应该使用顶点数组对象VAO

顶点数组对象VAO

  • 使用这个有什么用

    原话:

    • 当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。

    • 这使在不同顶点数据和属性配置之间切换变得非常简单,只需要绑定不同的VAO就行了。刚刚设置的所有状态都将存储在VAO中

    我认为:

    • 顶点数组对象VAO与顶点缓冲对象VBO一对多,一个VAO的顶点属性指针可以来源于多个不同的顶点缓冲对象,在初始化时VAO设置好顶点属性指针后,绘制的时候绑定对应的VAO就行,不需要写绑定顶点缓冲与设置顶点属性指针的代码了,可以在绘制时无关初始化设置状态的代码。
  • 代码

    // ..:: 初始化代码(只运行一次 (除非你的物体频繁改变)) :: ..
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    // 1. 绑定VAO
    glBindVertexArray(VAO);
    // 2. 把顶点数组复制到缓冲中供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);[...]// ..:: 绘制代码(渲染循环中) :: ..
    // 4. 绘制物体
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    someOpenGLFunctionThatDrawsOurTriangle();
    

    若有第二个物体要绘制,跟上一样,在初始化部分绑定相应顶点缓冲对象设置顶点属性后,在渲染绘制代码只要切换VAO就行

    // 4. 绘制物体
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    someOpenGLFunctionThatDrawsOurTriangle();glUseProgram(shaderProgram2);
    glBindVertexArray(VAO2);
    someOpenGLFunctionThatDrawsOurTriangle();
    
  • 图示

    如图:VAO与VBO一一对应,但实际上VAO的顶点属性指针可以来源于多个不同的顶点缓冲VBO,一般是一一对应

绘制三角形

  • 代码

    glsl

    version 330 core
    layout (location = 0) in vec3 aPos;
    void main()
    {gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    }
    
    #version 330 core
    out vec4 FragColor;
    void main()
    {FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    }
    

    cpp

    // 0.顶点数据
    float vertices[] = {-0.5f, -0.5f, 0.0f, // left  0.5f, -0.5f, 0.0f, // right 0.0f,  0.5f, 0.0f  // top   
    };
    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    // 1. 绑定顶点数组对象
    glBindVertexArray(VAO);
    // 2. 把我们的CPU的顶点数据复制到GPU顶点缓冲中,供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. 设定顶点属性指针,来解释顶点缓冲中的顶点属性布局
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    while (!glfwWindowShouldClose(window))
    {.....// 4.使用着色器程序对象glUseProgram(shaderProgram);// 5.绑定顶点数组对象,并绘制glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 3);// 这里.....
    }
    
  • 效果

元素(索引)缓冲对象EBO

  • 简介

    绘制矩形,有重复的顶点,正确使用索引顺序绘制图形可以重复利用顶点从而减少顶点数据。

  • 使用

    和VBO同样的生成使用方法,生成EBO缓冲区返回ID、绑定ID、设置索引数据、绑定在VAO上

    绘制不同:

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);代替glDrawArrays(GL_TRIANGLES, 0, 3);

  • 图示

    由图可见,VAO索引缓冲区的指针只有一个,且在最后

  • 代码

    glsl不变

    version 330 core
    layout (location = 0) in vec3 aPos;
    void main()
    {gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    }
    
    #version 330 core
    out vec4 FragColor;
    void main()
    {FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    }
    

    cpp

    // 0.1顶点数据
    float vertices[] = {0.5f,  0.5f, 0.0f,  // top right0.5f, -0.5f, 0.0f,  // bottom right-0.5f, -0.5f, 0.0f,  // bottom left-0.5f,  0.5f, 0.0f   // top left 
    };
    // 0.2索引数据
    unsigned int indices[] = {  // note that we start from 0!0, 1, 3,  // first Triangle1, 2, 3   // second Triangle
    };unsigned int VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    // 1. 绑定顶点数组对象
    glBindVertexArray(VAO);
    // 2. 把我们的CPU的顶点数据复制到GPU顶点缓冲中,供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. 复制我们的CPU的索引数组到GPU索引缓冲中,供OpenGL使用
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    // 4. 设定顶点属性指针,来解释顶点缓冲中的顶点属性布局
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    while (!glfwWindowShouldClose(window))
    {.....// 5.使用着色器程序对象glUseProgram(shaderProgram);// 6.绑定顶点数组对象,并绘制glBindVertexArray(VAO); //glDrawArrays(GL_TRIANGLES, 0, 3);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);// 这里不同// 由于只有一个顶点数组对象,不需要解绑.....
    }
    
  • 效果

小结

草稿图

请添加图片描述

重复重要的流程

着色器流程

  • 顶点着色器

    • 创建顶点着色器对象

    • 附加源码给顶点着色器对象

    • 编译顶点着色器对象

      可以打印是否编译成功

  • 片段着色器同上

  • 着色器程序

    • 创建着色器程序对象

    • 附加着色器对象给着色器程序对象

    • 链接着色器程序对象

      可以检查是否成功

    • 删除着色器对象

const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
unsigned int vertex, fragment;
// 1.1创建顶点着色器对象
vertex = glCreateShader(GL_VERTEX_SHADER);
// 1.2附加顶点着色器源码给顶点着色器对象
glShaderSource(vertex, 1, &vShaderCode, NULL);
// 1.3编译顶点着色器对象
glCompileShader(vertex);
// 1.4检测是否编译成功
checkCompileErrors(vertex, "VERTEX");
// 2.1创建片段着色器对象
fragment = glCreateShader(GL_FRAGMENT_SHADER);
// 2.2附加片段着色器源码给片段着色器对象
glShaderSource(fragment, 1, &fShaderCode, NULL);
// 2.3编译片段着色器对象
glCompileShader(fragment);
// 2.4检测是否编译成功
checkCompileErrors(fragment, "FRAGMENT");// 3.1创建着色器程序对象
ID = glCreateProgram();
// 3.2附加着色器对象给着色器程序对象
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
// 3.3链接着色器程序对象
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");// 可以检查是否成功
// 4.删除着色器对象
glDeleteShader(vertex);
glDeleteShader(fragment);void checkCompileErrors(unsigned int shader, std::string type)
{int success;char infoLog[1024];if (type != "PROGRAM"){glGetShaderiv(shader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}else{glGetProgramiv(shader, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}
}

绘制流程

  • 顶点数组对象
    • 创建顶点数组对象
    • 绑定顶点数组对象
  • 顶点缓冲对象
    • 创建顶点缓冲对象
    • 绑定顶点缓冲对象
    • 将顶点数据从CPU拷贝到GPU的顶点缓冲对象中
    • 设置顶点数组里的顶点属性指针,解释此顶点缓冲区的布局
  • 索引缓冲对象
    • 创建索引缓冲对象
    • 绑定索引缓冲对象,当前绑定顶点数组对象的索引缓冲对象指针会指向当前索引缓冲对象(自己的语言)
    • 将索引数据从CPU拷贝到GPU的索引缓冲对象中
  • 绘制代码
    • 使用着色器程序对象
    • 绑定顶点数组对象
    • 绘制元素
    • 解绑顶点数组对象
// ..:: 初始化代码 :: ..
// 1. 绑定顶点数组对象
glBindVertexArray(VAO);
// 2. 把我们的CPU的顶点数据复制到GPU顶点缓冲中,供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. 复制我们的CPU的索引数组到GPU索引缓冲中,供OpenGL使用
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 4. 设定顶点属性指针,来解释顶点缓冲中的顶点属性布局
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);[...]// ..:: 绘制代码(渲染循环中) :: ..
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

相关文章:

LearnOpenGL-入门-你好,三角形

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject LearnOpenGL中文官网&#xff1a;https://learnopengl-cn.github.io/ 文章目录图形渲染管线基本介绍着色器…...

SOEM 源码解析 ecx_init_redundant

/* Initialise lib in redundant NIC mode* 在冗余网卡模式下初始化lib库* param[in] context context struct* 上下文结构体* param[in] redport pointer to redport, redundant port data* 指向冗余端口的指针&#xff…...

网页唤起 APP中Activity的实现原理

疑问的开端大家有没有想过一个问题&#xff1a;在浏览器里打开某个网页&#xff0c;网页上有一个按钮点击可以唤起App。这样的效果是怎么实现的呢&#xff1f;浏览器是一个app&#xff1b;为什么一个app可以调起其他app的页面&#xff1f;说到跨app的页面调用&#xff0c;大家是…...

【操作系统】概述

基本特征 1. 并发 并发是指宏观上在一段时间内能同时运行多个程序&#xff0c;而并行则指同一时刻能运行多个指令。 并行需要硬件支持&#xff0c;如多流水线、多核处理器或者分布式计算系统。 操作系统通过引入进程和线程&#xff0c;使得程序能够并发运行 2. 共享 共享…...

Flume三种组件的选择对比

文章目录1.source2.channel3.sink1.source Source: 数据源:通过source组件可以指定让Flume读取哪里的数据&#xff0c;然后将数据传递给后面的 channel Flume内置支持读取很多种数据源&#xff0c;基于文件、基于目录、基于TCP\UDP端口、基于HTTP、Kafka的 等等、当然了&#x…...

响应性基础API

一.什么是proxy和懒代理&#xff1f;什么是proxy?proxy对象是用于定义基本操作的自定义行为(如&#xff1a;属性查找&#xff0c;赋值&#xff0c;枚举&#xff0c;函数调用等等)。什么是懒代理&#xff1f;懒代理&#xff1a;在初始化的时候不会进行全部代理&#xff0c;而是…...

剑指 Offer 25. 合并两个排序的链表

剑指 Offer 25. 合并两个排序的链表 难度&#xff1a;easy\color{Green}{easy}easy 题目描述 输入两个递增排序的链表&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1&#xff1a; 输入&#xff1a;1->2->4, 1->3->4 输出&#xff1a;1…...

顿悟日记(一)

目录2023年1月顿悟日记&#xff1a;2023年2月24日顿悟日记&#xff1a;2023年2月25日顿悟日记&#xff1a;2023年2月26日顿悟日记&#xff1a;顿悟的经历是如此的奇妙&#xff0c;且让人亢奋的事情。 2023年1月顿悟日记&#xff1a; 1.我是面向对象还是面向过程&#xff1f; …...

前端卷算法系列(二)

前端卷算法系列&#xff08;二&#xff09; 回文数 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样…...

网络应用之HTTP响应报文

HTTP响应报文学习目标能够知道HTTP响应报文的结构1. HTTP响应报文分析HTTP 响应报文效果图:响应报文说明:--- 响应行/状态行 --- HTTP/1.1 200 OK # HTTP协议版本 状态码 状态描述 --- 响应头 --- Server: Tengine # 服务器名称 Content-Type: text/html; charsetUTF-8 # 内容类…...

常见的CSS技巧

1.禁止长按图片弹出菜单 img {-webkit-touch-callout: none; // 主要用于禁止长按菜单。主针对webkit内核的浏览器&#xff1b; } /*或者 user-select , 是css3的新属性&#xff0c;用于设置用户是否能够选中文本*/ .img {-webkit-user-select: none;-khtml-user-select: none…...

算法进阶-动态规划

经典例题 大家肯定想用递归做 思路大概就是这样 递归到最后一行就是对应的D(i,j) 然后往上推 但是这样会超时&#xff0c;因为存在大量的重复计算 比如调用第一行MasSum(7)需要调用MaxSum(3)和MaxSum(8) 但是调用第二行MaxSum(3)还要调用3行的MaxSum(8)和3行的MaxSum(1) 第二行…...

python的读写操作

一、使用open函数&#xff0c;可以打开一个已经存在的文件&#xff0c;或着创建一个新文件 语法如下&#xff1a; open(name, mode, encoding) name: 要打开的目标文件的字符串(可以包含文件所在的具体路径) mode: 打开文件模式&#xff1a;只读(r)、写入(w)、追加(a)等 e…...

Mybatis中添加、查询、修改、删除

在Mybatis中添加数据的操作 编写相对应的SQL语句&#xff0c;并完成相关数据的对应关系 编写测试用例 需要提交事务 sqlSession commit() 这里需要注意的是mybatis是默认的是手动提交事务&#xff0c;如果不写的话会进行回滚&#xff0c;添加操作就不会被执行 或者在 如果…...

C++---线性dp---传纸条(每日一道算法2023.2.26)

注意事项&#xff1a; 本题dp思路与 “线性dp–方格取数” 一致&#xff0c;下方思路仅证明为什么使用方格取数的思路是正确的。 题目&#xff1a; 小渊和小轩是好朋友也是同班同学&#xff0c;他们在一起总有谈不完的话题。 一次素质拓展活动中&#xff0c;班上同学安排坐成…...

浅谈 C/C++ 的输入输出

更好的阅读体验\huge{\color{red}{更好的阅读体验}}更好的阅读体验 文章目录0. 叠甲&#xff0c;过1. 谈谈输入输出缓冲区1.1 基本概念输入输出流标准输入输出流文件输入输出流1.2 输入输出缓冲区什么是输入输出缓冲区&#xff1f;为什么要设置输入输出缓冲区&#xff1f;C/C 的…...

【计算机三级网络技术】 第二篇 中小型系统总体规划与设计

文章目录一、基于网络的信息系统基本结构二、划分网络系统组建工程阶段三、网络需求调研与系统设计原则四、网络用户调查与网络工程需求分析1.网络用户调查2.网络节点的地理位置分布3.应用概要分析4.网络需求详细分析五、网络总体设计基本方法1.网络工程建设总体目标与设计原则…...

Boosting Crowd Counting via Multifaceted Attention之人群密度估计实践

这周闲来无事&#xff0c;看到一篇前不久刚发表的文章&#xff0c;是做密集人群密度估计的&#xff0c;这块我之前虽然也做过&#xff0c;但是主要是基于检测的方式实现的&#xff0c;这里提出来的方法还是比较有意思的&#xff0c;就拿来实践一下。论文在这里&#xff0c;感兴…...

python之面向对象编程

1、面向对象介绍&#xff1a; 世界万物&#xff0c;皆可分类 世界万物&#xff0c;皆为对象 只要是对象&#xff0c;就肯定属于某种类 只要是对象&#xff0c;就肯定有属性 2、 面向对象的几个特性&#xff1a; class类&#xff1a; 一个类即对一类拥有相同属性的对象的…...

常见前端基础面试题(HTML,CSS,JS)(七)

同源策略 浏览器有一个重要的安全策略&#xff0c;称之为同源策略 其中&#xff0c;协议、端口号、域名必须一致&#xff0c;&#xff0c;称之为同源&#xff0c;两个源不同&#xff0c;称之为跨源或跨域 同源策略是指&#xff0c;若页面的源和页面运行过程中加载的源不一致…...

产业链金风控基本逻辑

产业链金风控基本逻辑 产业链金融平台作为一个助贷平台&#xff0c;很大程度上是为银行等金融机构进 行引流&#xff0c;贷款的审批本质上还是依赖金融机构的风控。那么&#xff0c;产业链金融 平台是否还有必要建设自己的风控模型呢?笔者给出的答案是肯定的。 一方面&#x…...

Java高级点的知识

Java 集合框架 该框架必须是高性能的。基本集合&#xff08;动态数组&#xff0c;链表&#xff0c;树&#xff0c;哈希表&#xff09;的实现也必须是高效的。 该框架允许不同类型的集合&#xff0c;以类似的方式工作&#xff0c;具有高度的互操作性。 对一个集合的扩展和适应…...

MyBatis - 05 - 封装SqlSessionUtil工具类(用于获取SqlSession对象)并测试功能

文章目录1.新建SqlSessionUtils工具类2.编写静态方法3.项目结构及代码项目结构数据库和表pom.xmlParameterMapper接口&#xff1a;User类&#xff1a;ParameterMapper.xmljdbc.propertieslog4j.xml:mybatis-config.xml:ParameterMapperTest测试类&#xff1a;测试结果1.新建Sql…...

Java中BIO、NIO和AIO的区别和应用场景

IO的方式通常分为几种&#xff0c;同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。 一、BIO 在JDK1.4出来之前&#xff0c;我们建立网络连接的时候采用BIO模式&#xff0c;需要先在服务端启动一个ServerSocket&#xff0c;然后在客户端启动Socket来对服务端进行通信&#…...

Python安装教程(附带安装包)

首先&#xff0c;打开python安装包的下载地址&#xff0c;https://www.python.org/downloads/&#xff0c;会有些慢 点击downloads中的windows 左侧是稳定的版本&#xff0c;我这边下的是3.8的&#xff0c;不想去官网下载的可以直接用我下载的这个3.8版本&#xff0c;https://…...

华为OD机试用Python实现 -【信号发射和接收】(2023-Q1 新题)

华为OD机试题 华为OD机试300题大纲信号发射和接收题目描述输入描述输出描述说明示例一输入输出说明示例二输入输出说明Python 代码实现代码运行结果代码编写思路华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为…...

Springboot整合 Thymeleaf增删改查一篇就够了

很早之前写过Thymeleaf的文章&#xff0c;所以重新温习一下&#xff0c;非前后端分离&#xff0c;仅仅只是学习 官网&#xff1a; https://www.thymeleaf.org/ SpringBoot可以快速生成Spring应用&#xff0c;简化配置&#xff0c;自动装配&#xff0c;开箱即用。 JavaConfigur…...

BigScience bloom模型

简介项目叫 BigScience,模型叫 BLOOM,BLOOM 的英文全名代表着大科学、大型、开放科学、开源的多语言语言模型。拥有 1760 亿个参数的模型.BLOOM 是去年由 1000 多名志愿研究人员,学者 在一个名为“大科学 BigScience”的项目中创建的.BLOOM 和今天其他可用大型语言模型存在的一…...

Squid服务的缓存概念

Squid缓存概念 squid是一个缓存服务器的守护进程 之前涉及的缓存服务&#xff1a;redis 2-8原则&#xff1a;80%的访问就是从20%的数据提供的&#xff1b;因此把20%的数据给到缓存–>完美解决等待时间&#xff1b; nginx是没有缓存的服务的&#xff1b;那么专业的事情就…...

Hadoop YARN

目录Hadoop YARN介绍Hadoop YARN架构、组件程序提交YARN交互流程YARN资源调度器Scheduler调度器策略FIFO SchedulerCapacity SchedulerFair SchedulerHadoop YARN介绍 YARN是一个通用资源管理系统和调度平台&#xff0c;可为上层应用提供统一的资源管理和调度 上图&#xff1…...

关于网站备案的44个问题/中国十大广告公司排行榜

伪元素:before 和 :after可以做的东西是相当惊人的。对于页面上的每一个元素&#xff0c;你拥有了两个更灵活的、而且可以完成其它HTML元素都能完成的东西的元素。它们让一大堆有趣的设计成为可能&#xff0c;而且不会对你的语义标签产生负面影响。这里有一大堆关于这些有趣的效…...

常德网站设计/免费有效的推广平台

Windows下安装配置免安装MySQL5.7服务器 1、下载、解压安装包 从MySQL官方网站上下载mysql-5.7.19-winx64.zip 下载完成后&#xff0c;把安装包解压到D:\DevSoftware\mysql57\目录下&#xff0c;会生成一个mysql-5.7.19-winx64目录。现在MySQL的目录就是D:\DevSoftware\mysql57…...

网站建设公司普遍存在劣势/指数搜索

上岸前辈告诉你&#xff0c;考研数学什么时候开始复习最好&#xff1f;摘要&#xff1a;数学基础不好&#xff0c;要不要早早开始复习啊&#xff1f;可战线过长&#xff0c;后期会不会影响复习效果&#xff1f;对于2021考研内心的困惑&#xff0c;帮帮为大家整理了过来人的经验…...

wordpress 网站锁/网站建网站建设网站

本文实例讲述了jQuery超简单遮罩层实现方法。共享给大家供大家参考&#xff0c;详细如下&#xff1a;在开发中&#xff0c;为了避免二次提交&#xff0c;遮罩层的运用越来越普遍看了很多代码&#xff0c;下面跟大家共享一下我认为最简单的遮罩层实现方式&#xff1a;1.风格如下…...

网站运营是做啥的/seo站长工具推广平台

如何从零开始&#xff0c;以最简单的方式搭建一个 Windows 云服务器。如果您之前没有搭建云服务器的经验&#xff0c;建议您按照以下视频及文档&#xff0c;购买和配置您的第一台云服务器。本文是搭建 Windows 云服务器入门教程。若想了解搭建 Linux 云服务器的入门教程&#x…...

做网站这个工作怎么样/seo是什么技术

需求描述 在表单中&#xff0c;可能部分表单项需封装成自定义组件&#xff0c;如何在表单提交时&#xff0c;能同步触发自定义组件的表单校验&#xff1f; 解决方案 将表单绑定的变量传入自定义组件中&#xff0c;在自定义组件中定义表单校验规则 完整代码范例 表单 内嵌自定义…...