OpenGL之绘制三角形

news2024/11/24 9:46:23

目录

OpenGL绘制图形的流程

标准化设备坐标

VAO和VBO 

VBO(顶点缓冲对象)

VBO(顶点缓冲对象)创建流程 

VAO(顶点数组对象)

绘制三角形 

​编辑给三角形添加颜色 

顶点着色器

片段着色器

编译着色器

使用着色器为三角形添加颜色


OpenGL绘制图形的流程

  在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline,大多译为管线,实际上指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程)管理的。图形渲染管线可以被划分为两个主要部分:第一部分把你的3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素。 

  图形渲染管线接受一组3D坐标,然后把它们转变为你屏幕上的有色2D像素输出。图形渲染管线可以被划分为几个阶段,每个阶段将会把前一个阶段的输出作为输入。所有这些阶段都是高度专门化的(它们都有一个特定的函数),并且很容易并行执行。正是由于它们具有并行执行的特性,当今大多数显卡都有成千上万的小处理核心,它们在GPU上为每一个(渲染管线)阶段运行各自的小程序,从而在图形渲染管线中快速处理你的数据。这些小程序叫做着色器(Shader)。

  图形渲染管线的第一个部分是顶点着色器(Vertex Shader),它把一个单独的顶点作为输入。顶点着色器主要的目的是把3D坐标转为另一种3D坐标(后面会解释),同时顶点着色器允许我们对顶点属性进行一些基本处理。

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

  图元装配阶段的输出会传递给几何着色器(Geometry Shader)。几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。

  几何着色器的输出会被传入光栅化阶段(Rasterization Stage),这里它会把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。 

  片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。

  在所有对应颜色值确定以后,最终的对象将会被传到最后一个阶段,我们叫做Alpha测试和混合(Blending)阶段。这个阶段检测片段的对应的深度(和模板(Stencil))值,用它们来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。这个阶段也会检查alpha值(alpha值定义了一个物体的透明度)并对物体进行混合(Blend)。所以,即使在片段着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同。

标准化设备坐标

  顶点着色器处理后,顶点值应该是NDC坐标;NDC坐标使用glViewport提供的数据,通过视口转换变为屏幕坐标。生成的屏幕空间坐标将转换为片段,作为片段着色器的输入。

  (Normalized Device Coordinates, NDC) 顶点着色器中处理过后,就应该是标准化设备坐标了,x、y 和 z 的值在-1.0到1.0的一小段空间(立方体)。落在范围外的坐标都会被裁剪。

VAO和VBO 

VBO(顶点缓冲对象)

    在GPU上创建内存,储存的顶点数据 通过顶点缓冲对象(Vertex Buffer Objects, VBO)管理 顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。

    使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。从CPU把数据发送到显卡相对较慢,所以只要可能我们都要尝试尽量一次性发送尽可能多的数据。当数据发送至显卡的内存中后,顶点着色器几乎能立即访问顶点,这是个非常快的过程。

VBO(顶点缓冲对象)创建流程 

顶点缓冲对象是第一个出现的OpenGL对象。就像OpenGL中的其它对象一样,这个缓冲有一个独一无二的ID,所以我们可以使用glGenBuffers函数和一个缓冲ID生成一个VBO对象:

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

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

glBindBuffer(GL_ARRAY_BUFFER, VBO);  

从这一刻起,我们使用的任何(在GL_ARRAY_BUFFER目标上的)缓冲调用都会用来配置当前绑定的缓冲(VBO)。然后我们可以调用glBufferData函数,它会把之前定义的顶点数据复制到缓冲的内存中:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数。它的第一个参数是目标缓冲的类型:顶点缓冲对象当前绑定到GL_ARRAY_BUFFER目标上。第二个参数指定传输数据的大小(以字节为单位);用一个简单的sizeof计算出顶点数据大小就行。第三个参数是我们希望发送的实际数据。

第四个参数指定了我们希望显卡如何管理给定的数据。它有三种形式:

  • GL_STATIC_DRAW :数据不会或几乎不会改变。
  • GL_DYNAMIC_DRAW:数据会被改变很多。
  • GL_STREAM_DRAW :数据每次绘制时都会改变。

三角形的位置数据不会改变,每次渲染调用时都保持原样,所以它的使用类型最好是GL_STATIC_DRAW。如果,比如说一个缓冲中的数据将频繁被改变,那么使用的类型就是GL_DYNAMIC_DRAW或GL_STREAM_DRAW,这样就能确保显卡把数据放在能够高速写入的内存部分。

VAO(顶点数组对象)

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

  OpenGL的核心模式要求我们使用VAO,所以它知道该如何处理我们的顶点输入。如果我们绑定VAO失败,OpenGL会拒绝绘制任何东西。

一个顶点数组对象会储存以下这些内容:

  • glEnableVertexAttribArray和glDisableVertexAttribArray的调用。
  • 通过glVertexAttribPointer设置的顶点属性配置。
  • 通过glVertexAttribPointer调用与顶点属性关联的顶点缓冲对象。

创建一个VAO和创建一个VBO很类似:

unsigned int VAO;
glGenVertexArrays(1, &VAO);

绘制三角形 

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

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

void processInput(GLFWwindow* window);

int main()
{
	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
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
	if (window == NULL) {
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	//GLFW将窗口的上下文设置为当前线程的上下文
	glfwMakeContextCurrent(window);

	//GLAD
	// glad: 加载所有OpenGL函数指针
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	//创建VBO和VAO对象,并赋予ID
	unsigned int VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	//绑定VBO和VAO对象
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//为当前绑定到target的缓冲区对象创建一个新的数据存储。
	//如果data不是NULL,则使用来自此指针的数据初始化数据存储
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//告知Shader如何解析缓冲里的属性值
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	//开启VAO管理的第一个属性值
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);


	// 渲染循环
	while (!glfwWindowShouldClose(window)) {
		processInput(window);
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //状态设置
		glClear(GL_COLOR_BUFFER_BIT); //状态使用

		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);
		// glfw: 交换缓冲区和轮询IO事件(按键按下/释放、鼠标移动等)
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	// glfw: 回收前面分配的GLFW先关资源. 
	glfwTerminate();

	return 0;
}

void processInput(GLFWwindow* window) 
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}

给三角形添加颜色 

顶点着色器

  顶点着色器(Vertex Shader)是几个可编程着色器中的一个。如果我们打算做渲染的话,现代OpenGL需要我们至少设置一个顶点和一个片段着色器。

  我们需要做的第一件事是用着色器语言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);
}

片段着色器

片段着色器(Fragment Shader)是第二个也是最后一个我们打算创建的用于渲染三角形的着色器。片段着色器所做的是计算像素最后的颜色输出。

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

下面是一个简单片段着色器的代码:

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
} 

编译着色器

 1、为了让OpenGL使用着色器,必须在运行时从源码中动态编译着色器。首先创建着色器对象。

2、各个阶段的着色器需要通过着色器程序对象链接起来。着色器程序对象是多个着色器组合的最终链接版本。

3、将着色器链接到程序时,会将每个着色器的输出链接到下一个着色器的输入。如果输出和输入不匹配,会出现链接错误。

现在,我们暂时将顶点着色器的源代码硬编码在代码文件顶部的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"; 

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";

我们首先要做的是创建一个着色器对象,注意还是用ID来引用的。所以我们储存这个顶点着色器为unsigned int,然后用glCreateShader创建这个着色器:

unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);

我们把需要创建的着色器类型以参数形式提供给glCreateShader。由于我们正在创建一个顶点着色器,传递的参数是GL_VERTEX_SHADER。

下一步我们把这个着色器源码附加到着色器对象上,然后编译它:

glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);

glShaderSource函数把要编译的着色器对象作为第一个参数。第二参数指定了传递的源码字符串数量,这里只有一个。第三个参数是顶点着色器真正的源码,第四个参数我们先设置为NULL

你可能会希望检测在调用glCompileShader后编译是否成功了,如果没成功的话,你还会希望知道错误是什么,这样你才能修复它们。检测编译时错误可以通过以下代码来实现:

int  success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

首先我们定义一个整型变量来表示是否成功编译,还定义了一个储存错误消息(如果有的话)的容器。然后我们用glGetShaderiv检查是否编译成功。如果编译失败,我们会用glGetShaderInfoLog获取错误消息,然后打印它。

if(!success)
{
    glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
    std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}

如果编译的时候没有检测到任何错误,顶点着色器就被编译成功了。

使用着色器为三角形添加颜色

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

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

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";

void processInput(GLFWwindow* window);

int main()
{
	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
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
	if (window == NULL) {
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	//GLFW将窗口的上下文设置为当前线程的上下文
	glfwMakeContextCurrent(window);

	//GLAD
	// glad: 加载所有OpenGL函数指针
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	// 创建和编译着色器程序 
	//顶点着色器
	unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	// 检查编译错误
	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;
	}
	// 片段着色器
	unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);
	// 检查编译错误
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
	}
	//着色器程序
	unsigned int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	//链接错误检查
	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);



	//创建VBO和VAO对象,并赋予ID
	unsigned int VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	//绑定VBO和VAO对象
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//为当前绑定到target的缓冲区对象创建一个新的数据存储。
	//如果data不是NULL,则使用来自此指针的数据初始化数据存储
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//告知Shader如何解析缓冲里的属性值
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	//开启VAO管理的第一个属性值
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);


	// 渲染循环
	while (!glfwWindowShouldClose(window)) {
		processInput(window);
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //状态设置
		glClear(GL_COLOR_BUFFER_BIT); //状态使用

		glUseProgram(shaderProgram);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);
		// glfw: 交换缓冲区和轮询IO事件(按键按下/释放、鼠标移动等)
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	// glfw: 回收前面分配的GLFW先关资源. 
	glfwTerminate();
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteProgram(shaderProgram);

	return 0;
}

void processInput(GLFWwindow* window) 
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}

 

参考:你好,三角形 - LearnOpenGL CN (learnopengl-cn.github.io) 

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

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

相关文章

二、Django REST Framework (DRF)序列化反序列化

参考&#xff1a; 为什么要学DRF和什么是REST API | 大江狗的博客 上一章&#xff1a; 一、Django REST Framework (DRF)& RESTful 风格api_做测试的喵酱的博客-CSDN博客 一、DRF框架介绍 1.1 介绍 Django REST Framework (DRF)这个神器我们可以快速开发出优秀而且…

基于SpringBoot的网吧管理系统的设计与实现

背景 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…

ICR-预测三种医学状况 #$60,000 #Kaggle

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息由AI辅助创作&#xff0c;仅供参考 比赛名称 ICR - Identifying Age-Related Conditions[2] (见文末阅读原…

chatgpt赋能Python-pythonforrange

Python中的Range函数 在Python编程语言中&#xff0c;range()是一个用于生成一系列数字的函数。它可以接受1至3个整型参数&#xff1a;起始值、终止值和步长。生成的数字包括起始值&#xff0c;但不包括终止值。步长默认为1。 Range函数的语法 Python中range()函数的常规语法…

C++视角下的Qt按钮:从基础应用到高级定制

C视角下的Qt按钮&#xff1a;从基础应用到高级定制 一、Qt按钮基础 (Qt Button Basics)1.1 Qt按钮的定义与创建 (Definition and Creation of Qt Buttons)1.2 Qt按钮的属性 (Properties of Qt Buttons)文本 (Text)图标 (Icon)大小 (Size)样式 (Style)是否可用 (Enabled) 1.3 Qt…

Java【TCP 协议3】提高效率的五大机制

文章目录 前言一、滑动窗口与高速重传1, 什么是滑动窗口2, 什么是高速重传2.1, ack 丢包2.2, 数据丢包 二、流量控制1, 什么是流量控制 三、拥塞控制1, 什么是拥塞控制 四、延迟应答1, 什么是延迟应答 五、捎带应答1, 什么是捎带应答 总结 前言 各位读者好, 我是小陈, 这是我的…

JavaScript实现1-100之间所有的素数的代码

以下为实现1-100之间所有的素数的程序代码和运行截图 目录 前言 一、1-100之间所有的素数 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xff1b; 2.本博文代码可以根据题目要求实现…

防火墙(二)

进一步了解防火墙 一、SNAT原理与应用模拟实验 二、DNAT的原理与应用模拟实验 三、抓包四、防火墙规则的备份和还原 一、SNAT原理与应用 SNAT应用环境&#xff1a;局域网主机共享单个公网IP地址接入Internet&#xff08;私有不能早Internet中正常路由&#xff09; SNAT原理&am…

【2023 · CANN训练营第一季】新手班 昇腾AI入门课(PyTorch)

1 昇腾AI全栈架构 昇腾计算产业是基于昇腾系列处理器和基础软件构睫的全栈Al计算基础设施&#xff0e;行业应用及服务&#xff0c;包括昇腾系列处理器、Atlas系列硬件、CANN (Compute Architecture for Neural Networks&#xff0c;异构计算架构》、Al计算框架、应用使能、全流…

nRF52832 定时器REPEATED模式,导致异常重启的问题排查全过程

文章目录 一、遇到问题二、JLink连接时&#xff0c;无法复现三、查看日志四、回退改动五、解决问题六、问题剖析 一、遇到问题 nRF52832项目增加一个功能&#xff0c;自测没问题就发出去了。结果300台机器&#xff0c;有7台出现异常&#xff0c;无法正常使用。细看了一遍提价上…

论文阅读_音频生成_AudioLM

论文信息 name_en: AudioLM: a Language Modeling Approach to Audio Generation name_ch: AudioLM&#xff1a;一种音频生成的语言建模方法 paper_addr: http://arxiv.org/abs/2209.03143 doi: https://doi.org/10.48550/arXiv.2209.03143 date_read: 2023-04-25 date_publis…

打开数据结构大门——实现小小顺序表

文章目录 前言顺序表的概念及分类搭建项目&#xff08;Seqlist&#xff09;:apple:搭建一个顺序表结构&&定义所需头文件&&函数:banana:初始化:pear:打印:watermelon:数据个数:smile:检查容量:fireworks:判空:tea:在尾部插入数据:tomato:在尾部删除数据:lemon:在…

封装Appium启动参数,提高自动化测试效率的关键

目录 前言&#xff1a; 一、开发环境搭建 二、代码实现 1.导入Appium相关的库文件。 2.创建Appium的启动参数对象&#xff0c;并设置相关参数。 3.启动测试服务。 4.执行测试用例。 5.结束测试服务。 三、总结 前言&#xff1a; Appium是一款广泛使用的自动化测试工具…

Microsoft Office 2007的安装

哈喽&#xff0c;大家好。今天一起学习的是office2007的安装&#xff0c;有兴趣的小伙伴也可以来一起试试手。 一、测试演示参数 演示操作系统&#xff1a;Windows 7 不建议win10及以上操作系统使用 系统类型&#xff1a;64位 演示版本&#xff1a;cn_office_ultimate_2007_D…

从 SIEM 到下一代 SIEM 的演变

在此文中&#xff0c;我们详细介绍了下一代 SIEM 的演变。传统的 SIEM 主要用于提高网络可见性和网络安全性&#xff0c;同时支持合规性。它们跨应用程序、网络和系统摄取、收集和存储日志数据。 SIEM 使捕获和搜索数据变得更加容易&#xff0c;这些数据有助于组织进行审计、取…

详解RGB和XYZ色彩空间转换之下

前言 首先需要指明本文中描述的R,G,B并非通常的sRGB中的三个分量R,G,B&#xff0c;而是波长分别为700nm&#xff0c;546.1nm&#xff0c;435.8nm的单色红光&#xff0c;单色绿光&#xff0c;单色蓝光。sRGB中的RGB中的红色、绿色、蓝色已经不是单色光了。虽然习惯上大家都叫RGB…

Docker数据目录迁移方法

文章目录 前言一、停掉Docker服务&#xff1f;二、迁移docker数据到数据盘目三、备份原数据目录四、添加软链接五、重启docker服务六、确认服务没有问题后&#xff0c;删除备份的目录总结 前言 服务器上安装的docker服务&#xff0c;数据默认存储在/var/lib/docker目录&#x…

html5网页播放器视频切换、倍速切换、视频预览的代码实例

本文将对视频播放相关的功能进行说明&#xff0c;包括初始化播放器、播放器尺寸设置、视频切换、倍速切换、视频预览、自定义视频播放的开始/结束时间、禁止拖拽进度、播放器皮肤、控件按钮以及播放控制等。 图 / html5视频播放器调用效果&#xff08;倍速切换&#xff09; 初始…

网络知识点之-动态路由

动态路由是指路由器能够自动地建立自己的路由表&#xff0c;并且能够根据实际情况的变化适时地进行调整。 中文名&#xff1a;动态路由外文名&#xff1a;dynamic routing 简述 动态路由是与静态路由相对的一个概念&#xff0c;指路由器能够根据路由器之间的交换的特定路由信息…

usb摄像头驱动-core层USB集线器(Hub)驱动

usb摄像头驱动-core层USB集线器&#xff08;Hub&#xff09;驱动 文章目录 usb摄像头驱动-core层USB集线器&#xff08;Hub&#xff09;驱动usb_hub_inithub_probehub_eventport_eventhub_port_connect_changehub_port_connectusb_new_deviceannounce_device 在USB摄像头驱动中…