【OpenGL】GLFW创建三角形

news/2024/5/6 2:41:14/文章来源:https://blog.csdn.net/qq_40344790/article/details/127221055

文章目录

    • 基础知识
    • 顶点输入
    • 创建顶点着色器
    • 片段着色器
    • 链接顶点属性和VAO顶点数组对象
    • 元素缓冲对象EBO
    • 完整程序

基础知识

在学习图形渲染前,首先了解3个词汇:

  1. 顶点数组对象:Vertex Array Object,VAO
  2. 顶点缓冲对象:Vertex Buffer Object,VBO
  3. 元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO

另外,在图形渲染中,要记住2D坐标和像素也是不同的,2D坐标精确表示一个点在2D空间中的位置,而2D像素是这个点的近似值,2D像素受到你的屏幕/窗口分辨率的限制。

3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline,大多译为管线,实际上指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程)管理的。图形渲染管线可以被划分为两个主要部分:第一部分把你的3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素。

在GPU上并行处理图形渲染管线的小程序叫做着色器(Shader)。OpenGL着色器是用OpenGL着色器语言(OpenGL Shading Language, GLSL)写成的。

在这里插入图片描述
为了让OpenGL知道我们的坐标和颜色值构成的到底是什么,OpenGL需要你去指定这些数据所表示的渲染类型。是希望把这些数据渲染成一系列的点?一系列的三角形?还是仅仅是一个长长的线?做出的这些提示叫做图元(Primitive),任何一个绘制指令的调用都将把图元传递给OpenGL。这是其中的几个:GL_POINTS、GL_TRIANGLES、GL_LINE_STRIP(这几个指令在前面几节已经用过了)。

从上面的图形渲染过程图可以看出,前3步是坐标处理,后3步是像素处理,详细过程如下:

  1. 顶点数据进入顶点着色器,可以设置顶点属性
  2. 所有顶点进入图元装配阶段,形成几何图形,上例是一个三角形
  3. 图形生成后进入几何着色器,这时可以添加新的顶点,例如添加一个新顶点形成2个三角形
  4. 几何处理完成后,进入光栅化阶段,会将图元转变为屏幕上真实显示的像素,形成片段,并且会丢弃掉视图之外的元素
  5. 片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方
  6. 片段着色器确定好所有元素的颜色值后,进入测试混合阶段,主要会检测元素的深度值等信息

顶点输入

开始绘制图形之前,我们需要先给OpenGL输入一些顶点数据。OpenGL仅当3D坐标在3个轴(x、y和z)上-1.0到1.0的范围内时才处理它。所有在这个范围内的坐标叫做标准化设备坐标

标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间。任何落在范围外的坐标都会被丢弃/裁剪,不会显示在你的屏幕上。而屏幕显示坐标是以屏幕左上角为原点,x右为正,y下为正。

在这里插入图片描述
三角形的定点定义如下:

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

定义这样的顶点数据以后,我们会把它作为输入发送给图形渲染管线的第一个处理阶段:顶点着色器

我们通过顶点缓冲对象(Vertex Buffer Objects, VBO)管理这个内存,它会在GPU内存(通常被称为显存)中储存大量顶点。使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。

我们可以使用glGenBuffers函数和一个缓冲ID生成一个VBO对象:

unsigned int VBO;
glGenBuffers(1, &VBO);

OpenGL有很多缓冲对象类型,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。OpenGL允许我们同时绑定多个缓冲,只要它们是不同的缓冲类型。我们可以使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上:

glBindBuffer(GL_ARRAY_BUFFER, VBO);  绑定顶点缓冲对象	

然后我们可以调用glBufferData函数,它会把之前定义的顶点数据复制到缓冲的内存中:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);	//将数据绑定到缓冲

创建顶点着色器

第一件事是用着色器语言GLSL(OpenGL Shading Language)编写顶点着色器,然后编译这个着色器,这样我们就可以在程序中使用它了。

一个非常基础的GLSL顶点着色器的源代码:

#version 330 core
layout (location = 0) in vec3 aPos;void main()
{gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

为了设置顶点着色器的输出,我们必须把位置数据赋值给预定义的gl_Position变量,它在幕后是vec4类型的。

然后需要将顶点着色器的源代码硬编码在代码文件顶部的C风格字符串中:

// 定义顶点着色器
const char *vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""void main()\n""{\n""   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n""}\0";

然后要创建一个顶点着色器对象:

	// vertex shader 创建并编译顶点着色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// check for shader compile errors 检测是否编译成功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;}

片段着色器

片段着色器所做的是计算像素最后的颜色输出。为了让事情更简单,我们的片段着色器将会一直输出橘黄色。

在计算机图形中颜色被表示为有4个元素的数组:红色、绿色、蓝色和alpha(透明度)分量,通常缩写为RGBA。当在OpenGL或GLSL中定义一个颜色的时候,我们把颜色每个分量的强度设置在0.0到1.0之间。比如说我们设置红为1.0f,绿为1.0f,我们会得到两个颜色的混合色,即黄色。

定义片段着色器:

// 定义片段着色器
const char *fragmentShaderSource = "#version 330 core\n""out vec4 FragColor;\n""void main()\n""{\n""   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""}\n\0";

创建片段着色器对象:

	// fragment shader 创建并编译片段着色器unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// check for shader compile errors 检测是否编译成功glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}

两个着色器都创建完成后,如果要使用刚才编译的着色器我们必须把它们链接(Link)为一个着色器程序对象,然后在渲染对象的时候激活这个着色器程序,所以需要创建一个着色器程序对象。它是多个着色器合并之后并最终链接完成的版本。

着色器程序对象代码如下:

	// link shaders 创建并链接着色器程序对象unsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// check for linking errors 检测链接是否成功glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);	//删除顶点着色器glDeleteShader(fragmentShader);	//删除片段着色器

链接顶点属性和VAO顶点数组对象

我们必须告诉OpenGL如何去解析顶点数据,我们使用一个顶点缓冲对象将顶点数据初始化至缓冲中,建立了一个顶点和一个片段着色器,并告诉了OpenGL如何把顶点数据链接到顶点着色器的顶点属性上。在OpenGL中绘制一个物体,代码会像是这样:

// 0. 复制顶点数组到缓冲中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
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。

顶点数组对象(Vertex Array Object, VAO)可以像顶点缓冲对象那样被绑定,任何随后的顶点属性调用都会储存在这个VAO中。这样的好处就是,当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。这使在不同顶点数据和属性配置之间切换变得非常简单,只需要绑定不同的VAO就行了。刚刚设置的所有状态都将存储在VAO中(OpenGL核心模式要求使用VAO)。

元素缓冲对象EBO

EBO是一个缓冲区,就像一个顶点缓冲区对象一样,它存储 OpenGL 用来决定要绘制哪些顶点的索引。这种所谓的索引绘制(Indexed Drawing)正是我们问题的解决方案。首先,我们先要定义(不重复的)顶点,和绘制出矩形所需的索引:

float vertices[] = {0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角
};unsigned int indices[] = {// 注意索引从0开始! // 此例的索引(0,1,2,3)就是顶点数组vertices的下标,// 这样可以由下标代表顶点组合成矩形0, 1, 3, // 第一个三角形1, 2, 3  // 第二个三角形
};

创建元素缓冲对象并添加索引:

unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

然后从索引缓冲区渲染三角形:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

另外,还可以设置绘制时的模式,如线框模式或常规模式:

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);	//线框模式GL_LINE / 填充模式GL_FILL

最终渲染图形如下:

在这里插入图片描述
在这里插入图片描述

完整程序

main.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>#include <iostream>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;// 定义顶点着色器
const char *vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""void main()\n""{\n""   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n""}\0";
// 定义片段着色器
const char *fragmentShaderSource = "#version 330 core\n""out vec4 FragColor;\n""void main()\n""{\n""   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""}\n\0";int main()
{// glfw: initialize and configure 初始化glfw// ------------------------------glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif// glfw window creation 窗口创建// --------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// glad: load all OpenGL function pointers 初始化glad// ---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// build and compile our shader program// ------------------------------------// vertex shader 创建并编译顶点着色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// check for shader compile errors 检测是否编译成功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;}// fragment shader 创建并编译片段着色器unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// check for shader compile errors 检测是否编译成功glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// link shaders 创建并链接着色器程序对象unsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// check for linking errors 检测链接是否成功glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);	//删除顶点着色器glDeleteShader(fragmentShader);	//删除片段着色器// set up vertex data (and buffer(s)) and configure vertex attributes 定义顶点数组(顶点输入)// ------------------------------------------------------------------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 };unsigned int indices[] = {  // note that we start from 0! 数组索引从0开始0, 1, 3,  // first Triangle1, 2, 3   // second Triangle};// 创建VAO、VBO和EBOunsigned 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). 绑定缓冲glBindVertexArray(VAO);	//绑定顶点数组对象glBindBuffer(GL_ARRAY_BUFFER, VBO);	//绑定顶点缓冲对象	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);	//将数据绑定到缓冲glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);	//绑定EBO元素缓冲对象glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);	//链接顶点属性(设置顶点属性指针)glEnableVertexAttribArray(0);	//启用顶点属性// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbindglBindBuffer(GL_ARRAY_BUFFER, 0);// remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.glBindVertexArray(0);// uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);// render loop 循环渲染// -----------while (!glfwWindowShouldClose(window)){// input 接受输入// -----processInput(window);// render 渲染// ------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// draw our first triangle 画出两个三角形glUseProgram(shaderProgram);	//使用着色器程序glBindVertexArray(VAO); // 绑定VAO seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized//glDrawArrays(GL_TRIANGLES, 0, 6);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);	//渲染元素glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);	//线框模式GL_LINE / 填充模式GL_FILL// glBindVertexArray(0); // no need to unbind it every time // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// optional: de-allocate all resources once they've outlived their purpose: 资源释放// ------------------------------------------------------------------------glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glDeleteProgram(shaderProgram);// glfw: terminate, clearing all previously allocated GLFW resources. 结束窗口// ------------------------------------------------------------------glfwTerminate();return 0;
}// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}

以上。

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

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

相关文章

跨境电商如何通过WhatsApp Business进行客户服务?

关键词&#xff1a;跨境电商&#xff0c;WhatsApp Business&#xff0c;客户服务 2022年&#xff0c;WhatsApp在Android设备和iPhone上拥有20亿活跃用户&#xff0c;它是世界上最受欢迎的消息传递应用程序之一。这些用户也是一系列产品和服务的客户。因此&#xff0c;越来越多…

Ubuntu卸载firefox浏览器安装google浏览器

1. 前言 Ubuntu20.4系统&#xff0c;默认用的firefox浏览器&#xff0c;在2022.09.25日之后打开钉钉网页版&#xff0c;突然提示目前该浏览器不支持企业钉钉网页版了&#xff0c;请使用UC浏览器或google浏览器&#xff0c;之前firefox是支持打开钉钉网页版的&#xff0c;现在突…

验证基础-随机约束与随机控制

目录​​​​​​​ 随机约束和分布 约束 权重分布 约束块控制 内嵌约束 随机函数 数组约束 随机控制 随机约束和分布 随着芯片体积增大、复杂度提高&#xff0c;定向测试已经无法满足验证的需求&#xff0c;随机测试的比例逐渐升高。定向测试能找到你认为可能存在的缺…

leetcode 738单调递增的数字

单调递增的数字 找到一个比目标值小的最大递增数列 递归法 从左到右遍历&#xff0c;找符合递增的部分&#xff0c; 当发现不符合的部分&#xff0c;不符合部分都置9 找到符合部分-1的最大递增数&#xff08;后面都置9要借位&#xff09; 例&#xff1a;输入668841 发现6688…

GMSL虚拟通道ID简介

Maxim千兆多媒体串行链路(GMSL) SERDES技术 通过一根电缆在两个端点之间提供高带宽和丰富的点对点互连,其长度可达15米。 SERDES(序列化器/反序列化器)技术广泛应用于传感器和网络通信。 SERDES在同一链路上支持多种协议。 由于其灵活性和性能,汽车工业应用程序严重依赖于…

关于TCP和UDP的联系与区别以及网络字节序和主机字节序的转换函数实践

1. TCP和UDP的相同点: TCP和UDP都是在网络层,都是传输层协议,都能都是保护网络层的传输,双方的通信都需要开放端口。 2.TCP和UDP的不同点: TCP传输协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC793定义。 UDP是Internet协议集支持一个无连接的…

SD-WAN:现代网络的基石

罗马工程构成了现代文明的基石&#xff0c;建造了横跨已知世界的渡槽&#xff0c;连接了各行各业的人民。拱门支撑着这些壮观的结构&#xff0c;但这些宏伟建筑成就的核心是基石。 SD-WAN 是现代网络的基石&#xff0c;为实现一致的服务质量 (QoS)、基于云的集中式网络管理和控…

scrapy爬取网站图片(静态加载)

1.创建一个scrapy项目 scrapy startgproject tupian cd tupian 创建爬虫文件 scrapy genspider Image www.com(域名)后续需要更改 开通pip管道是需要注意,我们将之前的类注释了,所以我们需要将原来的pip管道的名称加以修改 在终端运行就可以获取数据, 运行后会出现错误是…

面试官:Hash 碰撞是什么?如何解决?被问懵了……

Hash如何存数据 hash表的本质其实就是数组,hash表中通常存放的是键值对Entry。 如下图:这里的学号是个key,哈希表就是根据key值来通过哈希函数计算得到一个值,这个值就是下标值,用来确定这个Entry要存放在哈希表中哪个位置。 Hash碰撞 hash碰撞指的是,两个不同的值(比如张…

你真的了解SQL中的EXISTS谓词吗?

EXISTS 谓词的用法 支撑 SQL 和关系数据库的基础理论主要有两个&#xff1a;一个是数学领域的集合论&#xff0c;另一个是作为现代逻辑学标准体系的谓词逻辑&#xff08;predicate logic&#xff09;&#xff0c;准确地说是“一阶谓词逻辑”。EXISTS 是为了实现谓词逻辑中“量…

管理系统权限总结

概念 功能权限和数据权限。 功能权限&#xff1a;用户是否能打开某一个网页&#xff0c;是否能点击编辑按钮等。数据权限&#xff1a;用户可以使用的数据范围。 用户 应用系统的具体操作者&#xff0c;用户可以自己拥有权限信息&#xff0c;可以归属于0&#xff5e;n个角色&…

使用VSCode连接远程服务器

1 效果展示 最近在使用云服务器开项目&#xff0c;发现VSCode的remote插件能远程连接服务器进行开发&#xff0c;这样就非常方便了。效果如下&#xff1a; 可以看到&#xff0c;这样操作&#xff0c;使得云端开发和本地开发几乎没什么不同&#xff0c;如果是云服务器就更方便了…

Vue脚手架报错:‘v-model‘ directives require no argument 解决方案

1、报错&#xff1a; v-model directives require no argument 截图 2、原因&#xff1a; ESLint对vetur进行了eslint检查 3、解决方法 ① 修改模板中使用v-show 将 v-model:show"show" 改为 v-model"show" ② vetur插件的作者给出了解决办法 我们可…

20201306吴龙灿第三章学习笔记

目录Ⅰ知识点归纳1.进程的概念什么是进程?进程的特征动态性并发性独立性异步性结构性程序和进程主要区别2.多任务处理系统(1)背景(2)多任务处理系统代码介绍3.进程同步(1)同步(2)进程唤醒与睡眠无效唤醒A 进程:B 进程:避免无效唤醒A 进程:Linux 内核的例子Ⅱ实践内容与…

docker jenkins升级以及失败处理

一、概述 jenkins是由docker安装的,目前的jenkins版本为2.356。然后jenkins右上角提示版本升级 点击了升级,升级完成后,需要重启一下。 然后就芭比Q了,访问jenkins出现504错误。查看docker日志,提示需要jdk升级到1.8。默认的jenkins的jdk版本为1.7,然后docker就开始一直…

督办管理系统——让企业工作落实到位

开展督查督办工作是企业在经营管理过程中的重要环节和管理手段&#xff0c;是企业办公室系统政务服务的一项重要工作。其具有间接性、权威性、实效性等特点。要加强企业督查督办工作&#xff0c;必须思想认识到位&#xff0c;充分把握督查督办工作原则;制度建设到位&#xff0c…

linux NTP同步时间后比实际时间慢8小时

1. issue ntp同步时间后比实际时间慢8小时 2. analysis 查询系统当前的时区设置 date -R&#xff0c;看到系统是 0000 时区&#xff0c;而中国统一采用北京所在的东8时区&#xff0c;由此造成了8小时的时间偏差。 3. solution 将PC ubuntu /usr/share/zoneinfo/Asia/Shanghai…

Django定义路由_子路由_函数视图

Django定义路由什么是路由&#xff0c;怎么去定义路由&#xff1f;添加路由Path 函数路由定义的痛点处理路由中的动态参数什么是路由&#xff0c;怎么去定义路由&#xff1f; 通常在我们创建项目包中&#xff0c;有个url.py的文件&#xff0c;我们需要去定义路由信息&#xff…

二叉树专项训练LeetCode

144. 二叉树的前序遍历 二叉树入门 递归 与 迭代 class Solution {List<Integer> ans new ArrayList<>();void dfs(TreeNode root){if(root null) {return;}ans.add(root.val);dfs(root.left);dfs(root.right);}public List<Integer> preorderTraversal(T…

【Golang开发面经】蔚来(两轮技术面)

文章目录一面1. channel 缓冲与非缓冲2. mysql引擎3. 索引如何建立&#xff1f;4. linux 如何看进程5. redis 字符串的底层6. 线程池理解7. 线程池的拒绝策略8.悲观锁&#xff0c;乐观锁9. HTTP 各个版本的区别10. HTTP2.0之前怎么实现服务器推送机制&#xff1f;11. websocket…