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

OpenGL进阶 | 绘制一个三角形

一、准备绘图数据

  • VBO(Vertex Buffer Object)

        在opengl中,所有的数据都要放在显存中,通过VBO(Vertex Buffer Object)可将CPU数据传到GPU。

        VBO(Vertex Buffer Object)是OpenGL中的一种机制,用于将顶点数据存储在显存中,以便GPU可以快速访问和处理。VBO是一种缓冲对象,类似于CPU中的数组或列表,可以用来存储顶点的位置、颜色、纹理坐标等属性。使用VBO可以避免每次渲染时都需要从CPU到GPU之间复制顶点数据的过程,从而提高了渲染的效率。

GLuint vbo;
void Init()
{float data[] = {-0.2f,-0.2f,-0.6f,1.0f,0.2f,-0.2f,-0.6f,1.0f,-0.2f,0.2f,-0.6f,1.0f};glGenBuffers(1, &vbo);                                                   //需要1个VBO,把vbo写入到显卡进去,供后续操作glBindBuffer(GL_ARRAY_BUFFER, vbo);                                      //把vbo设置到卡槽上//glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12, nullptr,GL_STATIC_DRAW);//只在GPU上开辟内存不传数据glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12,data,GL_STATIC_DRAW);      //将数据从cpu传到Gpu,此后data数据可删除。glBindBuffer(GL_ARRAY_BUFFER, 0);                                        //卡槽重新绑定,防止误操作
}

二、编写Shader

1.顶点着色器

        vertex shader,test.vs文件如下:

attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
void main()
{gl_Position=ProjectionMatrix*ViewMatrix*ModelMatrix*position;
}
  •  uniform和attribute

在OpenGL中,uniform和attribute是用于在着色器程序中传递数据的两种不同类型。

  1. Uniform变量: Uniform变量是一种全局变量,用于在不同的着色器阶段之间传递数据。它们在着色器程序中的任何地方都可以访问,不受顶点或片段的限制。Uniform变量通常用于传递全局数据,例如变换矩阵、光照参数、纹理等。在程序中,你可以使用glGetUniformLocation函数获取Uniform变量的位置(或插槽),然后使用glUniform函数将值传递给Uniform变量。

  2. Attribute变量: Attribute变量是一种顶点属性,用于在顶点着色器中接收每个顶点的输入数据。它们通常用于表示顶点的位置、颜色、法线等属性。Attribute变量只能在顶点着色器中使用,并且每个顶点都会有对应的属性值。在程序中,你可以使用glGetAttribLocation函数获取Attribute变量的位置(或插槽),然后使用glVertexAttribPointer函数设置属性数据的格式和位置。

        关于插槽(location)的分配,Uniform变量和Attribute变量都是从0开始分配的。可以使用glGetUniformLocation和glGetAttribLocation函数获取它们在着色器程序中的位置(或插槽)值。对于Uniform变量,可以使用glUniform函数将值传递给指定位置的Uniform变量。对于Attribute变量,可以使用glVertexAttribPointer函数将属性数据绑定到指定位置的Attribute变量。

        需要注意的是,Uniform变量和Attribute变量在不同的着色器阶段之间传递数据的方式和使用方法是不同的。Uniform变量用于在整个着色器程序中传递全局数据,而Attribute变量用于在顶点着色器中接收每个顶点的属性数据。

2.片段着色器

        fragment shader,test.fs文件如下:

#ifdef GL_ES
precision mediump float;
#endif
void main()
{gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}

三、编译Shader

1.相关函数

  • glCreateShader

GLuint glCreateShader(GLenum shaderType);

        shaderType指示要创建的着色器的类型,支持两种类型的着色器:

  1.  GL_VERTEX_SHADER类型的着色器是一个用于在可编程顶点处理器上运行的着色器。
  2.  GL_FRAGMENT_SHADER类型的着色器是一个着色器,旨在在可编程片段处理器上运行。

        glCreateShader创建一个空的着色器对象,并返回一个可以引用的非零值(Shader ID)。着色器对象用于维护定义着色器的源代码字符串。

  • glShaderSource

        glShaderSource是OpenGL中用于设置着色器源代码的函数。它的作用是将字符串形式的着色器源代码加载到指定的着色器对象中,以便后续编译和链接。具体来说,glShaderSource函数有四个参数:

void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);
  1. shader:要设置源代码的着色器对象的ID。
  2. count:要设置的源代码字符串数量。
  3. string:源代码字符串数组的指针。
  4. length:源代码字符串数组中每个字符串的长度,如果为NULL,则默认使用字符串的长度。
  • glCompileShader

        glCompileShader是OpenGL中用于编译着色器对象的函数。它的作用是将glShaderSource函数加载的着色器源代码编译成可执行的着色器程序,供OpenGL渲染时使用。

具体来说,glCompileShader函数有一个参数:

void glCompileShader(GLuint shader);
  1. shader:要编译的着色器对象的ID。
  • glGetShaderiv

            glGetShaderiv是OpenGL中获取着色器对象参数的函数之一,它的作用是获取指定着色器对象的特定参数信息,例如编译状态、参数个数、参数类型等等。具体来说,glGetShaderiv函数有三个参数:

void glGetShaderiv(GLuint shader, GLenum pname, GLint *params);
  1. shader:要查询的着色器对象的ID。

  2. pname:要查询的参数名称,可选值包括:

    • GL_SHADER_TYPE:着色器类型,取值为GL_VERTEX_SHADER或GL_FRAGMENT_SHADER。
    • GL_DELETE_STATUS:着色器是否已被标记为删除。
    • GL_COMPILE_STATUS:着色器编译状态,取值为GL_TRUE或GL_FALSE。
    • GL_INFO_LOG_LENGTH:着色器信息日志的长度,以字符数为单位。
    • GL_SHADER_SOURCE_LENGTH:着色器源代码的长度,以字符数为单位。
    • GL_NUM_SHADER_BINARY_FORMATS:支持的着色器二进制格式数量。
    • GL_SHADER_BINARY_FORMATS:支持的着色器二进制格式列表。
    • 其他参数,例如GL_SHADER_IDENTITY_MATRIX等等。
  3. params:指向存储返回参数值的变量的指针。

  • glDeleteShader

        glDeleteShader是OpenGL中删除着色器对象的函数之一。它的作用是删除已经创建的着色器对象,释放显存中的资源。具体来说,glDeleteShader函数有一个参数:

void glDeleteShader(GLuint shader);
  1. shader:要删除的着色器对象的ID。

        需要注意的是,如果着色器对象已经被附加到程序对象中,那么在程序对象链接之前无法删除着色器对象。因此,通常建议在使用完着色器对象后立即删除它,以免占用过多的显存资源。

2.举个例子

GLuint CompileShader(GLenum shaderType, const char* shaderCode)
{GLuint shader = glCreateShader(shaderType);glShaderSource(shader, 1, &shaderCode, nullptr);glCompileShader(shader);GLint compileResult = GL_TRUE;glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);if (compileResult == GL_FALSE) {char szLog[1024] = { 0 };GLsizei logLen = 0;glGetShaderInfoLog(shader, 1024, &logLen, szLog);printf("Compile Shader fail error log : %s \nshader code :\n%s\n", szLog, shaderCode);glDeleteShader(shader);shader = 0;}return shader;
}

四、链接成程序

1.相关函数

  • glCreateProgram

        glCreateProgram是OpenGL中创建着色器程序对象的函数之一。它的作用是创建一个着色器程序对象并返回其ID,用于管理多个着色器对象的链接过程。具体来说,glCreateProgram函数没有参数,只返回一个GLuint类型的着色器程序对象ID:

GLuint glCreateProgram(void);
  • glAttachShader

        glAttachShader是OpenGL中将着色器对象附加到程序对象的函数之一。它的作用是将一个或多个着色器对象附加到一个程序对象上,为后续的链接操作做准备。具体来说,glAttachShader函数有两个参数:

void glAttachShader(GLuint program, GLuint shader);
  1. program:要附加到的程序对象的ID。
  2. shader:要附加的着色器对象的ID。
  • glLinkProgram

        glLinkProgram是OpenGL中链接着色器程序的函数之一,用于将一个程序对象中所有附加的着色器对象链接为一个可执行程序。在链接过程中,OpenGL会将不同着色器之间的变量名和类型进行匹配和连接,最终生成一个可供GPU执行的着色器程序。具体来说,glLinkProgram函数有一个参数:

void glLinkProgram(GLuint program);
  1. program:要链接的程序对象的ID。

        需要注意的是,glLinkProgram函数链接完成后会将链接日志存储在程序对象中,我们可以通过调用glGetProgramiv函数查询链接状态,或者通过调用glGetProgramInfoLog函数获取链接日志。另外,如果链接失败,程序对象的状态将会被标记为链接失败,并且该程序对象无法使用。

  • glDetachShader

        glDetachShader是OpenGL中将着色器对象从程序对象中分离的函数之一。它的作用是将一个着色器对象从一个程序对象中分离,使该着色器对象可以在其他程序对象中使用。具体来说,glDetachShader函数有两个参数:

void glDetachShader(GLuint program, GLuint shader);
  1. program:要分离着色器对象的程序对象的ID。
  2. shader:要分离的着色器对象的ID。
  • glGetProgramiv

        glGetProgramiv是OpenGL中获取着色器程序对象参数的函数之一。它的作用是获取指定着色器程序对象的特定参数信息,例如链接状态、参数个数、参数类型等等。具体来说,glGetProgramiv 函数有三个参数:

void glGetProgramiv(GLuint program, GLenum pname, GLint *params);
  1. program:要查询的着色器程序对象的ID。

  2. pname:要查询的参数名称,可选值包括:

    1. GL_DELETE_STATUS:程序是否已被标记为删除。
    2. GL_LINK_STATUS:程序链接状态,取值为GL_TRUE或GL_FALSE。
    3. GL_VALIDATE_STATUS:程序验证状态,取值为GL_TRUE或GL_FALSE。
    4. GL_INFO_LOG_LENGTH:链接或验证日志的长度,以字符数为单位。
    5. GL_ATTACHED_SHADERS:附加的着色器对象数量。
    6. GL_ACTIVE_ATTRIBUTES:激活的顶点属性数量。
    7. GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:激活的顶点属性名称的最大长度。
    8. GL_ACTIVE_UNIFORMS:激活的Uniform变量数量。
    9. GL_ACTIVE_UNIFORM_MAX_LENGTH:激活的Uniform变量名称的最大长度。
    10. 其他参数,例如GL_PROGRAM_BINARY_RETRIEVABLE_HINT等等。
  3. params:指向存储返回参数值的变量的指针。

  • glDeleteProgram

        glDeleteProgram是OpenGL中删除着色器程序对象的函数之一。它的作用是删除已经创建的着色器程序对象,释放显存中的资源。具体来说,glDeleteProgram函数有一个参数:

void glDeleteProgram(GLuint program);
  1. program:要删除的着色器程序对象的ID。

2.举个例子

GLuint CreateProgram(GLuint vsShader, GLuint fsShader) {GLuint program = glCreateProgram();glAttachShader(program, vsShader);glAttachShader(program, fsShader);glLinkProgram(program);glDetachShader(program, vsShader);glDetachShader(program, fsShader);GLint nResult;glGetProgramiv(program, GL_LINK_STATUS, &nResult);if (nResult == GL_FALSE) {char log[1024] = { 0 };GLsizei writed = 0;glGetProgramInfoLog(program, 1024, &writed, log);printf("create gpu program fail,link error : %s\n", log);glDeleteProgram(program);program = 0;}return program;
}

五、读取shader源码到GPU程序

GLuint program;
void Init()
{//...//准备绘图数据//...int fileSize = 0;unsigned char * shaderCode = LoadFileContent("Res/test.vs", fileSize);GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char*)shaderCode);delete shaderCode;shaderCode = LoadFileContent("Res/test.fs", fileSize);GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, (char*)shaderCode);delete shaderCode;program = CreateProgram(vsShader, fsShader);glDeleteShader(vsShader);glDeleteShader(fsShader);
}

六、读取shader中的变量

1.相关函数

  • glGetUniformLocation

        glGetUniformLocation是OpenGL中用于获取Uniform变量的位置(或插槽)的函数之一。它用于查询指定着色器程序对象中的Uniform变量的位置,以便后续对其进行赋值。具体来说,glGetUniformLocation函数有两个参数:

GLint glGetUniformLocation(GLuint program, const GLchar *name);
  1. program:要查询Uniform变量的着色器程序对象的ID。
  2. name:Uniform变量的名称。(Uniform变量的名称必须与着色器程序中定义的Uniform变量的名称完全匹配。)
  • glGetAttribLocation

        glGetAttribLocation是OpenGL中用于获取Attribute变量的位置(或插槽)的函数之一。它用于查询指定着色器程序对象中的Attribute变量的位置,以便后续绑定顶点数据。具体来说,glGetAttribLocation函数有两个参数:

GLint glGetAttribLocation(GLuint program, const GLchar *name);
  1. program:要查询Attribute变量的着色器程序对象的ID。
  2. name:Attribute变量的名称。(Attribute变量的名称必须与着色器程序中定义的Attribute变量的名称完全匹配。)

2.举个例子

GLint positionLocation,modelMatrixLocation,viewMatrixLocation,projectionMatrixLocation;
void Init()
{//...//准备绘图数据//...//...//读取shader源码到GPU程序//...positionLocation = glGetAttribLocation(program, "position");modelMatrixLocation = glGetUniformLocation(program, "ModelMatrix");viewMatrixLocation = glGetUniformLocation(program, "ViewMatrix");projectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
}

七、设置MVP矩阵

1.MVP矩阵

        在OpenGL中设置MVP(Model-View-Projection)矩阵是用于进行物体的变换和投影的重要步骤之一。通常,Model矩阵表示物体的模型变换,View矩阵表示摄像机的观察变换,而Projection矩阵表示投影变换。

        对于Model矩阵和View矩阵,默认是单位矩阵,所以不需要显式设置它们,可以通过使用glm库中的glm::mat4的默认构造函数创建单位矩阵。

        对于Projection矩阵,可以使用glm库中的glm::perspective函数来设置。

glm::mat4 glm::perspective(float fov, float aspect, float near, float far);
  1. fov:视野角度(Field of View),以弧度为单位。
  2. aspect:视口的宽高比(宽度除以高度)。
  3. near:近平面距离摄像机的距离。
  4. far:远平面距离摄像机的距离。

        该函数将返回一个透视投影矩阵,所有在近平面和远平面内且处于平截头体内的顶点都会被渲染。可以将其应用于Projection矩阵。

2.设置MVP矩阵

glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
void SetViewPortSize(float width, float height)
{projectionMatrix = glm::perspective(glm::radians(45.0f), width / height, 0.1f, 1000.0f);
}

八、设置Uniform变量

1.glUniformMatrix4fv

        glUniformMatrix4fv是OpenGL中用于将4x4矩阵数据传递给Uniform变量的函数之一。它用于将一个或多个4x4矩阵值传递给在着色器程序中定义的Matrix4类型的Uniform变量。

void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
  1. location:要传递数据的Uniform变量的位置(或插槽)。
  2. count:要传递的矩阵数量。如果你只传递一个矩阵,则count为1。
  3. transpose:指定是否应该在传递矩阵之前对其进行转置。通常情况下,你可以将其设置为GL_FALSE。
  4. value:指向包含要传递数据的GLfloat数组的指针。矩阵数据按列主序存储在数组中。

2.代码示例

void Draw()
{glUseProgram(program);//启用着色器程序glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));   //将模型矩阵传递给着色器程序中的模型矩阵Uniform变量modelMatrixLocationglUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));    //将视图矩阵传递给着色器程序中的视图矩阵Uniform变量viewMatrixLocationglUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));  //将投影矩阵传递给着色器程序中的投影矩阵Uniform变量projectionMatrixLocationglUseProgram(0);      //停用着色器程序
}

九、读取vbo数据,绘制三角形

1.相关函数

  • glVertexAttribPointer

        glVertexAttribPointer函数用于指定顶点属性的指针,并设置相关参数。

void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);

参数解释如下:

  1. index:顶点属性的索引,对应于着色器程序中的顶点属性变量。
  2. size:顶点属性的分量数量,例如3表示顶点属性由三个分量组成(如位置属性为x、y、z)。
  3. type:顶点属性的数据类型,例如GL_FLOAT表示浮点型数据。
  4. normalized:指定是否对非浮点型数据进行归一化处理,通常设置为GL_FALSE。
  5. stride:顶点属性之间的字节偏移量,用于在顶点数据中定位不同属性的数据。
  6. pointer:顶点属性数据的指针,指向顶点数据缓冲区中的起始位置。
  • glEnableVertexAttribArray

        glEnableVertexAttribArray函数用于启用指定索引的顶点属性数组。

void glEnableVertexAttribArray(GLuint index);

参数解释如下:

  1. index:顶点属性的索引,对应于着色器程序中的顶点属性变量。
  • glDrawArrays

        glDrawArrays函数用于执行基于顶点数组的图元绘制操作。

void glDrawArrays(GLenum mode, GLint first, GLsizei count);

参数解释如下:

  1. mode:指定绘制的图元类型,例如GL_POINTS表示绘制点,GL_TRIANGLES表示绘制三角形等。
  2. first:指定顶点数组中的起始索引,表示从哪个顶点开始绘制。
  3. count:指定要绘制的顶点数量。

2.代码示例

void Draw()
{glClearColor(0.0f, 1.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//...//设置Uniform变量//...glBindBuffer(GL_ARRAY_BUFFER, vbo);  //将顶点缓冲对象绑定到OpenGL的顶点缓冲区(GL_ARRAY_BUFFER)glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, 0);   //定义位置属性glEnableVertexAttribArray(positionLocation);  //启用位置属性索引为positionLocation的顶点属性数组glDrawArrays(GL_TRIANGLES, 0, 3);    //执行绘制操作。该函数指定了绘制的模式、起始顶点索引和顶点数量。glBindBuffer(GL_ARRAY_BUFFER, 0);    //解绑顶点缓冲对象
}

十、补充说明

        shader通常称为着色器,作用是把CPU上的点渲染出来,shader在GPU上是并行执行的,比如三个顶点的数据,会在三个core上并行处理。

        比如我们绘制一个三角形,需要三个顶点数据。顶点着色器将会被执行三次,每次使用不同的顶点数据作为输入。(不需要为每个顶点创建一个单独的vertex shader文件,我们可以使用相同的vertex shader文件来处理所有三个顶点,只需要为每个顶点提供不同的位置属性作为输入),并使用统一变量mvpMatrix进行模型-视图-投影变换。(即:position不一样,m、v、p矩阵相同

  • 3*4个数据的顶点矩阵,三个顶点:
    float data[] = {-0.2f,-0.2f,-0.6f,1.0f,0.2f,-0.2f,-0.6f,1.0f,0.0f,0.2f,-0.6f,1.0f};
  • vertex shader文件: 
attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

相关文章:

OpenGL进阶 | 绘制一个三角形

一、准备绘图数据 VBO(Vertex Buffer Object) 在opengl中,所有的数据都要放在显存中,通过VBO(Vertex Buffer Object)可将CPU数据传到GPU。 VBO(Vertex Buffer Object)是OpenGL中的一…...

CSAPP Lab3- bufbomb

实验目标 (1)掌握函数调用时的栈帧结构 (2)利用输入缓冲区的溢出漏洞,将攻击代码嵌入当前程序的栈帧中,使得程序执行我们所期望的过程 实验代码 (1)makecookie:生成c…...

分布式系统之CAP定理介绍

前言 在分布式系统的设计和实现中,CAP定理是一个非常重要的概念。本文将介绍CAP定理的概念、含义和应用。 什么是 CAP 定理? CAP定理是分布式系统设计中的一个基本原则,它指出,在分布式系统中,一致性(Consi…...

vcomp140.dll怎么安装?提示vcomp140.dll丢失怎样修复?

在用电脑玩游戏或者打开软件工作的时候,电脑提示vcomp140.dll丢失无法执行此代码,是什么回事呢?需要怎么修复呢?不用紧张,小编今天就把vcomp140.dll文件修复方法分享给大家。我总结了几个修复经验; vcomp14…...

CA OpenSSL自签名证书(服务器/客户端)

参考文章 https://juejin.cn/post/7092789498823573518 https://blog.csdn.net/mengting2040/article/details/120001810 目录 使用 OpenSSL 生成证书创建根证书创建 Root Pair创建 Root Key创建 Root Crt 创建服务器端证书创建服务器端keyip需要换成自己服务器的外网ip地址&am…...

计算机视觉(4)—— 未有深度学习之前

目录 四、未有深度学习之前 4.1 图像分割 4.1.1 基于阈值分割 4.1.2 基于边缘分割 4.1.3 基于区域分割 (1)区域生长法 (2)分水岭算法 4.1.4 基于图论分割 (1)Graph Cuts 分割 ​(2&…...

怎么获取winform中动态代码生成的控件的状态

winform怎么获取动态代码生成窗口里面的控件的属性状态 MainForm中调用 private void ShowPropertyForm() { PropertyForm form new PropertyForm(selectedShape); form.ShowDialog(); pictureBox1.Refresh(); …...

Windows安装Maven并配置环境

Windows下安装和配置Maven的步骤 介绍:步骤:步骤 1:下载Maven步骤 2:解压缩Maven分发包步骤 3:设置环境变量步骤 4:验证安装 结论: 介绍: Maven是一个非常流行的构建和项目管理工具…...

致力于中小企业JavaEE企业级快速开发平台、后台框架平台

一、开源项目简介 J2eeFAST 是一个 Java EE 企业级快速开发平台, 致力于打造中小企业最好用的开源免费的后台框架平台 。系统基于(Spring Boot、Spring MVC、Apache Shiro、MyBatis-Plus、Freemarker、Bootstrap、AdminLTE)经典技术开发&…...

【神经网络】tensorflow实验9--分类问题

1. 实验目的 ①掌握逻辑回归的基本原理,实现分类器,完成多分类任务; ②掌握逻辑回归中的平方损失函数、交叉熵损失函数以及平均交叉熵损失函数。 2. 实验内容 ①能够使用TensorFlow计算Sigmoid函数、准确率、交叉熵损失函数等&#xff0c…...

LeetCode2. 两数相加

写在前面: 题目链接:LeetCode2两数相加 编程语言:C 题目难度:中等 一、题目描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 …...

基于无线传感网络(WSN)的目标跟踪技术(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 无线传感器网络由于其自组织性、鲁棒性及节点数量巨大的特点,非常适合于目标跟踪。无线传感器网络中的移动目标跟踪实际上就是…...

百度发布首个可信AI工具集TrustAI,助力数据分析与增强

百度发布首个集分析与增强于一体的可信AI工具集TrustAI,该工具集旨在帮助用户快速、准确地对各种类型的数据进行分析和增强,从而提高数据的价值和可信度。 随着人工智能技术的快速发展,数据的价值和重要性日益凸显。然而,在数据处…...

电力系统负荷与电价预测优化模型(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

asp.net+C#超市商品进销存管理系统

本超市商品管理系统主要超市内部提供服务,系统分为管理员员工两部分。 本研究课题重点主要包括了下面几大模块:管用户登录,员工管理,商品管理,进货管理,销售管理,供应商信息,会员信…...

轻量级K8s发行版的五大优势,助力企业快速拥抱边缘计算

随着物联网和移动设备的普及,边缘计算已成为当前信息技术领域的热门话题。为了满足这一需求,越来越多的企业开始探索使用容器化技术来打造轻量级的K8s发行版。这种发行版可以更加灵活地部署在物理边缘,提供更快速、更稳定的服务。 在这篇文章…...

【深入理解redis】数据结构

文章目录 动态字符串SDS字符串编码类型 intsetDictZipListZipList的连锁更新问题 QuickListSkipListRedisObjectStringListSet结构ZSETHash Redis 共有 5 种基本数据结构:String(字符串)、List(列表)、Set(…...

《计算机网络—自顶向下方法》 第三章Wireshark实验:DNS协议分析

域名系统 DNS(Domain Name System) 是互联网使用的命名系统,用于把便于大家使用的机器名字转换为 IP 地址。许多应用层软件经常直接使用 DNS,但计算机的用户只是间接而不是直接使用域名系统。 互联网采用层次结构的命名树作为主机的名字,并使…...

JUC(十二)-线程中断相关问题(LockSupport,sleep,InterruptException)

JUC线程中断相关问题总结 线程中断相关问题总结 JUC线程中断相关问题总结一、 sleep 和线程中断之间的关系和特点结论测试验证代码如下 二、 LockSupport 和线程中断之间的关系结论测试验证代码如下 一、 sleep 和线程中断之间的关系和特点 结论 线程调用 Thread.sleep之后会进…...

Kotlin高级协程

Kotlin高级协程 一.前言二.先从线程说起三.协程的设计思想四.协程特点:优雅的实现移步任务五.协程基本使用六.协程和线程相比有什么特点,如何优雅的实现异步任务 一.前言 在文章正式上干货之前,先说一点背景吧;我是 Kotlin 协程官…...

车载软件架构——闲聊几句AUTOSAR BSW(四)

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 我们并不必要为了和谐,而时刻保持通情达理;我们需要具备的是,偶尔有肚量欣然承认在某些方面我们可能会有些不可理喻。该有主见的时候能掷地有声地镇得住场…...

Linux:rpm查询安装 yum安装

环境: 需要插入安装镜像 镜像内有所需的安装库 我这里使用的虚拟机直接连接光盘 连接的光盘挂载在/dev/cdrom 由于我们无法直接进入,所以选择把/dev/cdrom挂载到别的地方即可 mount /dev/cdrom /123 将/dev/cdrom 挂载到 /123 目录下 Packages下就是…...

Android音视频开发之音频录制和播放

1.封装音频录制工具类: public class RecorderAudioManagerUtils {private static volatile RecorderAudioManagerUtils mInstance;public static RecorderAudioManagerUtils getInstance() {if (mInstance null) {synchronized (RecorderAudioManagerUtils.class…...

Java之单例模式

目录 一.上节内容 1.什么是线程安全 2.线程不安全的原因 3.JMM(Java内存模型) 4.synchronized锁 5.锁对象 6.volatile关键字 7.wait()和notify() 8.Java中线程安全的类 二.单例模式 1.什么是单例 2.怎么设计一个单例 1.口头约定 2.使用编程语言的特性 三.饿汉模式…...

【分组码系列】线性分组码的网格图和维特比译码

线性分组码的网格图 由于码字的比特位是统计独立的,所以编码过程可以利用有限状态机来描述,它能精确地确定初始和最终状态。可以利用网格图进一步描述编码过程[36],采用维特比算法进行最大似然译码. 在GF(2)上定义线性分组码(n,k)。相应的(n-k)Xn维校验阵可以写成 令码字为系…...

代码命名规范是真优雅呀!代码如诗

日常编码中,代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图,也是一项必备的能力。那它们有什么规律呢? Java项目的代码结构,能够体现它的设计理念。Java采用长命名的方式来规范类的命名,能够自己表达…...

你不知道的自动化?使用自动化测试在项目中创造高业务价值...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 脱离数据支撑谈价…...

通过实现一个简单的 JavaScript 猜数字大小的游戏,介绍如何进行布局样式处理

JavaScript 猜数字大小是一个非常简单、却又经典的游戏,可以锻炼玩家的逻辑思维能力。在这个游戏中,电脑会随机生成一个数字,玩家需要根据提示逐步猜出正确的数字。接下来,我们将通过实现一个简单的 JavaScript 猜数字大小游戏来介…...

Java设计模式(二十二)策略模式

一、概述 策略模式是一种行为型设计模式,它允许在运行时选择算法的行为。策略模式通过将算法封装成独立的策略类,使得它们可以相互替换,而不影响使用算法的客户端。这样可以使客户端代码与具体算法的实现细节解耦,提高了代码的可…...

【沐风老师】一步一步教你在3dMax中进行UVW贴图和展开UVW的方法

将简单或程序材质应用于对象并不难。但是当表面需要在其上显示某种纹理时,它会变得更加复杂。任何纹理贴图都放在材质的 Diffuse 插槽中,但渲染的结果可能无法预测。这就是为什么我们需要了解 3DMAX 如何将纹理应用于 3D 对象,什么是 UVW 贴图…...