LearnOpenGL-入门-8.坐标系统

news2024/9/21 22:42:33

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

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

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

文章目录

  • 坐标系统
    • 概述
    • 局部空间
    • 世界空间
    • 观察空间
    • 裁剪空间
      • 正交投影
      • 透视投影
    • 把他们组合到一起
  • 进入3D
    • 例子1
    • 例子2:更加3D
    • 例子3:箱子派对

坐标系统

  • 标准化设备坐标介绍

    • 每个顶点的xyz坐标都在**-1.01.0**之间

    • OpenGL希望在每次顶点着色器运行后,我们可见的所有顶点都为标准化设备坐标

    • 我们通常会自己设定一个坐标的范围,之后再在顶点着色器中将这些坐标变换为标准化设备坐标

    • 将标准化设备坐标传入光栅器(Rasterizer),将它们变换为屏幕上的二维坐标或像素。

  • 多个坐标系统

    • 为什么存在

      坐标变换为标准化设备坐标,接着再转化为屏幕坐标的过程通常是分步进行的,所以物体的顶点在最终转化为屏幕坐标之前还会被变换到多个坐标系统

    • 多个坐标系统的优点优点

      在这些特定的坐标系统中,一些操作或运算更加方便和容易

概述

  1. 局部坐标是对象相对于局部原点的坐标,也是物体起始的坐标
  2. 局部坐标通过Model矩阵变换为世界空间坐标,这些坐标相对于世界的全局原点,它们会和其它物体一起相对于世界的原点进行摆放。
  3. 观察空间坐标,通过view矩阵将世界空间转换到观察空间,使得每个坐标都是从摄像机或者说观察者的角度进行观察的。
  4. 裁剪坐标,通过投影矩阵从观察空间到裁剪空间,裁剪坐标会被处理(透视除法)至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上。
  5. 视口变换将-1.0到1.0范围的裁剪坐标(标准化设备坐标)变换到由glViewport函数所定义的坐标范围内。

局部空间

  • 简介

    局部空间是指物体所在的坐标空间

世界空间

  • 简介

    是指顶点相对于(游戏)世界的坐标

  • 如何从局部到世界坐标

    该变换是由模型矩阵(Model Matrix)实现的。

观察空间

  • 简介

    摄像机的视角所观察到的空间,是由观察矩阵(Model Matrix)从世界到观察坐标。

  • view(观察)矩阵

    由一系列的位移和旋转的组合来完成,平移/旋转场景从而使得特定的对象被变换到摄像机的前方。

    这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里

裁剪空间

  • 简介

    • OpenGL自动执行
    • 范围内的保留,范围外的裁掉
    • 当裁剪后剩下的可见的片段就是裁剪空间
  • 如何进入裁剪空间

    投影矩阵将观察空间变换到裁剪空间

  • 投影矩阵分为

    • 正交投影
    • 透视投影
  • 透视除法

    • 什么时候执行

      一旦所有顶点被变换到裁剪空间,OpenGL自动会透视除法(在每一个顶点着色器运行的最后被自动执行)

    • 它如何做

      将位置向量的x,y,z分量分别除以向量的齐次w分量

    • 结果

      透视除法执行后才将裁剪坐标系变换到标准化设备坐标系

  • 小结工作流程(自己捋的,很大概率有误)

    设置-1000到1000范围,投影矩阵会将在这个范围内的坐标从观察空间变换到裁剪空间,然后OpenGL自动执行透视除法,转换为标准化设备坐标的范围(-1.0, 1.0)。

    所有的坐标先转换为(-1, 1)之间,然后不在-1.0到1.0的范围,会被裁剪掉(OpenGL自动执行裁剪)。

  • 在标准化设备坐标系之后

    执行第一张图所说的视口变换

    最终的坐标(标准化设备坐标系)将会被映射到屏幕空间中(使用glViewport中的设定),并被变换成片段。

    即:视口变换将标准化设备坐标系到屏幕坐标

正交投影

  • 图示

  • glm创建

    glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
    
    • 前两个参数指定了平截头体的左右坐标

    • 第三和第四参数指定了平截头体的底部和顶部

      通过这四个参数我们定义了近平面和远平面的大小

    • 第五和第六个参数则定义了近平面和远平面的距离

  • 缺点

    这个投影没有将透视(Perspective)考虑进去,所有的物体仿佛都保持原有大小。

    因为这个投影不改变每个向量的w分量,都保持1,透视除法是用x,y,z除以w分量,w=1,自然不会变。

透视投影

  • 图示

  • 简介

    近大远小

  • 透视投影矩阵如何工作

    • 这个投影矩阵将给定的平截头体范围映射到裁剪空间

    • 除此之外还修改了每个顶点坐标的w

      • 从而使得离观察者越远的顶点坐标w分量越大。

      • 透视除法所做

        将位置向量的x,y,z分量分别除以向量的齐次w分量,因为远的顶点坐标w分量大,所以距离观察者越远顶点坐标就会越小

    • 什么时候执行透视除法

      • 上面有讲:由projection投影矩阵变换到裁剪空间后
      • OpenGL要求所有可见的坐标都落在-1.0到1.0范围内,作为顶点着色器最后的输出。因此,一旦坐标在裁剪空间内之后,就会在裁剪空间坐标上执行透视除法,透视除法执行后便是标准化设备坐标(-1.0,1.0)范围。
  • glm创建

    glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);
    
    • 第一个参数定义了fov的值,它表示的是视野

    • 第二个参数设置了宽高比,由视口的宽除以高所得

    • 第三和第四个参数设置了平截头体的平面

      • 说明第三个参数

        near 值设置太大时(如10.0f),OpenGL会将靠近摄像机的坐标**(在0.0f和10.0f之间)**都裁剪掉

  • 透视投影与正交投影对比

把他们组合到一起

  • 注意顺序

    • 写代码顺序

      v = projection * view * model * local

    • 读顺序

      需从右往左阅读矩阵

  • 再重复了一次裁剪空间这点的内容

    OpenGL将会自动进行透视除法和裁剪操作

    重要的顺序

    • 顶点着色器的输出要求所有的顶点都在裁剪空间内,这正是我们刚才使用变换矩阵所做的。
    • OpenGL然后对裁剪坐标自动执行透视除法从而将它们变换到标准化设备坐标
    • 视口变换:OpenGL会使用glViewPort内部的参数来将标准化设备坐标映射到屏幕坐标

进入3D

  • 观察矩阵
    • 将摄像机向后移动,和将整个场景向前移动是一样的。
    • 这正是观察矩阵所做的,我们以相反于摄像机移动的方向移动整个场景
    • 因为我们想要往后移动,所以场景需要沿着z轴负方向平移来实现,它会给我们一种我们在往后移动的感觉。(opengl右手坐标系)

例子1

  • 代码

    glsl

    顶点着色器

    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec2 aTexCoord;
    out vec2 TexCoord;
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    void main()
    {
        // 注意乘法要从右向左读
        gl_Position = projection * view * model * vec4(aPos, 1.0);
        TexCoord = aTexCoord;
    }
    
    • 在顶点着色器上进行坐标系转换,从局部空间到裁剪空间

      • 代码顺序是

        project*view*model*local

      • 解读顺序是

        相反的需从右往左读:将顶点local经过model矩阵到世界空间,再经过view矩阵到观察空间,再经过project到裁剪空间。

    • 再次重复

      到裁剪空间后,经过透视除法到标准化设备坐标系,再经过视口变换到屏幕坐标,这两个是opengl自动执行的

    片段着色器

    #version 330 core
    out vec4 FragColor;
    in vec2 TexCoord;
    uniform sampler2D texture1;
    uniform sampler2D texture2;
    void main()
    {
        FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
    }
    

    cpp

    Shader ourShader("assest/shader/1入门/1.8.transform.vs", "assest/shader/1入门/1.8.transform.fs");
    
    // 顶点数据
    float vertices[] = {
        // positions          // texture coords
        0.5f,  0.5f, 0.0f,   1.0f, 1.0f, // top right
        0.5f, -0.5f, 0.0f,   1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, // bottom left
        -0.5f,  0.5f, 0.0f,   0.0f, 1.0f  // top left 
    };
    unsigned int indices[] = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };
    // 顶点数组
    unsigned int VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    
    // 加载纹理
    unsigned int texture1, texture2;
    // texture 1
    glGenTextures(1, &texture1);
    glBindTexture(GL_TEXTURE_2D, texture1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
    unsigned char* data = stbi_load(FileSystem::getPath("assest/textures/container.jpg").c_str(), &width, &height, &nrChannels, 0);
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
    // texture 2 和texture1一样
    .......
    // 告诉OpenGL两个采样器对应哪个纹理单元
    ourShader.use();
    ourShader.setInt("texture1", 0);
    ourShader.setInt("texture2", 1);
    
    // render loop
    while (!glfwWindowShouldClose(window))
    {
        // input
        processInput(window);
    
        // render
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the depth buffer now!
    
        // bind textures on corresponding texture units
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
    	// 此节重点在这///
        // 构造矩阵变换
        glm::mat4 model = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first
        glm::mat4 view = glm::mat4(1.0f);
        glm::mat4 projection = glm::mat4(1.0f);
        model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        // 注意,我们将矩阵向我们要进行移动场景的反方向移动。
        view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
        // 透视投影矩阵
        projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
    
        // 设置uniform
        ourShader.use();
        unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");
        unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view");
        // 3种不同的方式发送数据给Shader
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);
        ourShader.setMat4("projection", projection);
    
        // 渲染box
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    
    • 重点代码

      // 将物体绕着x轴旋转-55.0度
      model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
      // 注意,我们将矩阵向我们要进行移动场景的反方向移动。
      view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
      // 透视投影矩阵
      projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
      
  • 效果

    • 经过model矩阵实现的旋转+透视投影可看到的效果
      • 稍微向后倾斜至地板方向。
      • 离我们有一些距离。
      • 有透视效果(顶点越远,变得越小)。

例子2:更加3D

  • 代码改变

    与上一个例子相比的改变

    • 改变了顶点数据,顶点数据是一个箱子的36个顶点
    • 去除了索引缓冲与索引绘制
    • model矩阵不再是绕着x旋转-55度,而是绕着y轴旋转度数time(运行时间作为度数)
  • 代码

    float vertices[] = {
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
        0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
    
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
    };
    model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f));
    
  • 效果

    请添加图片描述

    效果奇怪,奇怪的地方在于没有进行深度测试,导致后渲染的片段覆盖前渲染的片段,从而箱子的背面覆盖前面。

  • 如何修复

    • 由于OpenGL默认不进行深度测试,需要设置开启深度测试,开启后opengl自动完成

      只需在渲染代码前中加一句

      glEnable(GL_DEPTH_TEST);
      
    • 深度测试工作原理

      • OpenGL存储它的所有深度信息于一个Z缓冲,又称深度缓冲
      • GLFW会自动为你生成这样一个缓冲(就像它也有一个颜色缓冲来存储输出图像的颜色)
      • 深度值存储在每个片段里面(作为片段的z值),当片段想要输出它的颜色时,OpenGL会将它的深度值和z缓冲进行比较,如果当前的片段在其它片段之后,它将会被丢弃否则将会覆盖
  • 修复效果

例子3:箱子派对

  • 实现思路

    • 定义10个箱子的出生点

    • 循环10次

      每次model为单位矩阵,再将model矩阵进行平移到出生点,再可以加上旋转效果(代码顺序)

  • 代码

    float vertices[] = {
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
    	......
    };
    // 出生点-初始位置
    glm::vec3 cubePositions[] = {
        glm::vec3(0.0f,  0.0f,  0.0f),
        glm::vec3(2.0f,  5.0f, -15.0f),
        glm::vec3(-1.5f, -2.2f, -2.5f),
        glm::vec3(-3.8f, -2.0f, -12.3f),
        glm::vec3(2.4f, -0.4f, -3.5f),
        glm::vec3(-1.7f,  3.0f, -7.5f),
        glm::vec3(1.3f, -2.0f, -2.5f),
        glm::vec3(1.5f,  2.0f, -2.5f),
        glm::vec3(1.5f,  0.2f, -1.5f),
        glm::vec3(-1.3f,  1.0f, -1.5f)
    };
    // render box
    glBindVertexArray(VAO);
    for (unsigned int i = 0; i < 10; i++)
    {
        glm::mat4 model = glm::mat4(1.0f);
        model = glm::translate(model, cubePositions[i]);    // 先平移
        float angle = 20.0f * i * (float)glfwGetTime();
        model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));// 再旋转
        ourShader.setMat4("model", model);
    
        glDrawArrays(GL_TRIANGLES, 0, 36);
    }
    

    注意model矩阵,写代码的顺序是先平移再旋转,但是解读的话是先旋转再平移(请看本专栏中变换-矩阵的组合)。

  • 效果

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

干货收藏|医疗数据安全、临床业务容灾、智能运维及数字化转型方案集锦

数智赋能&#xff0c;助力医院高质量发展&#xff01;历时三天的2022中华医院信息网络大会&#xff08;CHINC&#xff09;圆满落下帷幕&#xff0c;美创科技赴五年之约&#xff0c;与医疗行业用户朋友在深圳再聚交流&#xff0c;也带来关于“医疗行业数据安全、数字化转型”的新…

【再临数据结构】Day1. 稀疏数组

前言 这不单单是稀疏数组的开始&#xff0c;也是我重学数据结构的开始。因此&#xff0c;在开始说稀疏数组的具体内容之前&#xff0c;我想先说一下作为一个有着十余年“学龄”的学生&#xff0c;所一直沿用的一个学习方法&#xff1a;3W法。我认为&#xff0c;只有掌握了正确的…

react的严格模式 和 解决react useEffect执行两次

useEffect执行两次 这个问题&#xff0c;主要是刚接触react的时候发的问题&#xff0c;当时也没总结。现在回过头来再总结一次&#xff01;&#xff01;&#xff01; 文章目录useEffect执行两次前言一、为什么useEffect执行两次1.React的严格模式&#xff08;模版创建项目&…

Hadoop综合案例 - 聊天软件数据

目录1、聊天软件数据分析案例需求2、基于Hive数仓实现需求开发2.1 建库2.2 建表2.3 加载数据2.4 ETL数据清洗2.5 需求指标统计---都很简单3、FineBI实现可视化报表3.1 FineBI介绍3.2 FineBI配置数据3.3 构建可视化报表1、聊天软件数据分析案例需求 MR速度慢—引入hive 背景&a…

深度剖析指针(中)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容仍旧是深度剖析指针噢&#xff0c;在上一篇博客中&#xff0c;我已经写过了字符指针、数组指针、指针数组、数组传参和指针传参的知识点&#xff0c;那么这篇博客小雅兰会讲解一下函数指针、函数指针数组 、指向函数指针数组…

【Spark分布式内存计算框架——Spark Streaming】8. Direct 方式集成底层原理 集成Kafka 0.10.x

Direct 方式集成底层原理 SparkStreaming集成Kafka采用Direct方式消费数据&#xff0c;如下三个方面优势&#xff1a; 第一、简单的并行度&#xff08;Simplified Parallelism&#xff09; 读取topics的总的分区数目 每批次RDD中分区数目&#xff1b;topic中每个分区数据 被…

布局三八女王节,巧借小红书数据分析工具成功引爆618

对于小红书“她”经济来说&#xff0c;没有比三八节更好的阵地了。伴随三八女王节逐渐临近&#xff0c;各大品牌蓄势待发&#xff0c;这场开春后第一个S级大促活动&#xff0c;看看品牌方们可以做什么&#xff1f; 洞察流量&#xff0c;把握节点营销时机 搜索小红书2023年的三…

学员作品|微博“绿洲”APP产品分析

一产品架构1. 产品功能架构图绿洲的主要功能模块可以拆分为六部分&#xff1a;首页、发现、发布动态、个人中心、水滴、消息。整体功能架构图如下&#xff1a;2. 用户使用路径图用于浏览动态&#xff1a;用于发布动态&#xff1a;新用户引导路径&#xff1a;二市场分析1. 产品定…

【Linux】Linux中gcc/g++的使用

本期主题&#xff1a;程序的编译过程和gcc/g的使用博客主页&#xff1a;小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限&#xff0c;出现错误希望大家不吝赐&#x1f341; 1.背景知识 预处理&#xff08;进行宏替换&#xff0c;去注释&#xff0c;头文件的…

索引、索引失效、索引的存储

文章目录1.索引种类2.创建索引注意点3.索引失效的情况4.为什么索引使用B树存储&#xff08;1&#xff09;如果使用数组来存储索引&#xff08;2&#xff09;如果使用二叉查找树来存储索引&#xff08;3&#xff09;如果使用平衡二叉查找树来存储索引&#xff08;4&#xff09;如…

同为(TOWE)防雷产品助力福建移动南平分公司防雷改造

01 公司简介中国移动通信集团福建有限公司南平分公司属于福建移动地级分公司&#xff0c;所属行业为电信、广播电视和卫星传输服务。现已建成覆盖范围广、业务品种多、通信质量高的综合通信网络&#xff0c;具备行业领先的经营管理制度。移动通信大楼的综合防雷及地接系统&…

第八节 构造器和this关键字、封装

构造器的作用 定义在类中的&#xff0c;可以用于初始化一个类的对象&#xff0c;并返回对象的地址。 构造器的注意事项 1.任何类定义出来&#xff0c;默认就自带了无参数构造器&#xff0c;写不写都有。 2.一旦定义了有参数构造器&#xff0c;那么无参数构造器就没有了&#xf…

互联网人看一看,这些神器你用过哪些?

很多小伙伴在剪辑视频的过程中经常可以看到一些语音素材&#xff0c;经常刷视频的小伙伴也可以看到很多视频中经常出现一些AI合成的声音或者音效&#xff0c;这些配音可以给视频增添很多亮点&#xff01;那么大家都是怎么将文字转语音的呢&#xff1f;今天给大家分享5款非常专业…

【Git】Git常用命令及练习—Git环境配置

目录 一、Git环境配置 1.1基本配置 1.2为常用指令配置别名&#xff08;可选&#xff09; 1.3 解决GitBash乱码问题 二、Git命令详细操作 1.获取本地仓库 2.基础操作命令及练习 基础操作练习 3.分支命令及练习 开发中分支使用原则与流程 分支练习 &#x1f49f; 创作不…

Ubuntu20.04安装Cuckoo

参考链接&#xff1a; &#xff08;1&#xff09;【主要参考】http://www.wityx.com/post/134851_1_1.html &#xff08;2&#xff09;【主要参考】在Ubuntu18.04上搭建Cuckoo Sandbox2.0.7 https://www.jianshu.com/p/4dd6373fa206 &#xff08;3&#xff09;与Cuckoo的斗智斗…

Kafka入门(五)

下面聊聊Kafka常用命令 1、Topic管理命令 以topic&#xff1a;test_1为例 1.1、创建topic ./bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 3 --partitions 3 --topic test_1参数说明&#xff1a; –bootstrap-server&#xff1a;…

【论文笔记】Decoupling Representation and Classifier for Long-Tailed Recognition

这一篇其实并不是提出什么新的东西&#xff0c;而且是做了点类似综述的技术调用实验。省流&#xff1a;T-normalization最好用 摘要 现状&#xff1a;Existing solutions usually involve class-balancing strategies, e.g. by loss re-weighting, data re-sampling, or tran…

【操作方法】windows防火墙添加出入站规则方法

【操作方法】windows防火墙添加出入站规则方法说明一、入站规则1.打开防火墙&#xff0c;点击“高级设置”2.点击“入站规则”后点击“新建规则”3.例3.1选择“端口”3.2添加需要放通的端口3.3选择操作动作为“允许连接”3.4选择应用区域&#xff0c;此处我选择所有区域二、出站…

Linux: malloc()的指向指针发生指向偏移后,释放前需要将指针指向复原。

Linux: malloc()的指向指针发生指向偏移后&#xff0c;释放前需要将指针指向复原。 #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <time…

A Contextual-Bandit Approach to Personalized News Article Recommendation-论文学习

A Contextual-Bandit Approach to Personalized News Article Recommendation-论文学习 github地址&#xff1a;bandit-learning 摘要 该算法根据用户和文章的上下文信息依次选择文章为用户服务&#xff0c;同时根据用户点击反馈调整其文章选择策略&#xff0c;以最大化用户…