【OpenGL 002】着色器 GLSL 语言及GLFW代码案例

news2024/11/25 6:54:21

文章目录

      • 1.GLSL语言简介
        • @本节案例 code 1
      • 2.GLSL的数据类型
        • ① 向量(Vector)
          • - 向量重组示例
          • - 向量重组禁忌
      • 3.GLSL的输入输出
        • @本节案例 code 2
      • 4.着色器示例
      • 5.Uniform
        • @本节案例 code 3

通过第一节 【OpenGL 001】Ubuntu 搭建 GLFW 环境及其相关测试 demo 想必已经搭建好了GLFW环境,了解了 OpenGL 基础,这节开始通过 GLFW 对 OpenGL 进一步学习。


1.GLSL语言简介

上一节已经介绍过着色器,那么,着色器使用 GLSL(OpenGL Shading Language)语言编写,GLSL是一种类C语言,用于图形计算,包含了一些针对向量和矩阵操作的有用特性。

main函数是GLSL着色器的入口点,所有的着色操作都在这里进行。

① 以下是一个简单着色器的代码:

功能 - 顶点着色器的功能就是简单地接收顶点位置,并传递给GPU去绘制

// 指定GLSL的版本号,此处使用 3.30 核心版本,即 OpenGL 3.3 版本
#version 330 core

// 输入顶点位置,通过vec3(三维向量)表示
layout(location = 0) in vec3 aPos;

void main()
{
    // 把输入的顶点位置传给 gl_Position,这是GPU用来绘制的顶点位置
    // 将三维顶点位置转换成vec4
    gl_Position = vec4(aPos, 1.0);
}

对于顶点着色器,每个输入变量也叫顶点属性(Vertex Attribute)。

可声明的顶点属性是有上限的,它一般由硬件来决定。OpenGL确保至少有16个包含4分量的顶点属性可用,但是有些硬件或许允许更多的顶点属性,可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限:

@本节案例 code 1

查询 GL_MAX_VERTEX_ATTRIBS:

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

#include <iostream>

int main()
{
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); 
    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    int nrAttributes;
    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
    std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;

    glfwTerminate();
    return 0;
}

compile and run:

[jn@jn build]$ make
Consolidate compiler generated dependencies of target glfwTest
[ 33%] Building CXX object CMakeFiles/glfwTest.dir/main.cpp.o
[ 66%] Linking CXX executable glfwTest
[100%] Built target glfwTest
[jn@jn build]$ ./glfwTest
Maximum nr of vertex attributes supported: 16
[jn@jn build]$

2.GLSL的数据类型

GLSL中包含C等其它语言大部分的默认基础数据类型:int、float、double、uint和bool。
向量(Vector)和矩阵(Matrix)是GLSL的两种容器类型(用于数据存储的数据结构)。

① 向量(Vector)

GLSL中的向量是一个可以包含有2、3或者4个分量的容器,分量的类型可以是前面默认基础类型的任意一个。它们可以是下面的形式(n代表分量的数量):

类型含义
vecn包含 n 个 float 分量的默认向量
bvecn包含 n 个 bool 分量的向量
ivecn包含 n 个 int 分量的向量
uvecn包含 n 个 unsigned int 分量的向量
dvecn包含 n 个 double 分量的向量

一个向量的分量可以通过vec.x这种方式获取,这里x是指这个向量的第一个分量。你可以分别使用.x、.y、.z和.w来获取它们的第1、2、3、4个分量。GLSL也允许对颜色使用r,g,b,a,或是对纹理坐标使用stpq访问相同的分量。

- 向量重组示例

假设有一个四维向量 vec4,其分量分别为 (x, y, z, w)。以下是一些重组的示例:

可以如下这么做:

  • 提取和重组分量

    vec4 v = vec4(1.0, 2.0, 3.0, 4.0);
    vec3 v1 = v.xyz;   // 结果是 (1.0, 2.0, 3.0)
    vec2 v2 = v.xy;    // 结果是 (1.0, 2.0)
    
  • 重组分量

    vec4 v = vec4(1.0, 2.0, 3.0, 4.0);
    vec4 v1 = v.zwxy;  // 结果是 (3.0, 4.0, 1.0, 2.0)
    vec4 v2 = v.ywzx;  // 结果是 (2.0, 4.0, 1.0, 3.0)
    
  • 颜色分量重组

    vec4 color = vec4(0.5, 0.8, 0.3, 1.0);
    vec4 newColor = color.bgra;  // 结果是 (0.3, 1.0, 0.8, 0.5)
    

- 向量重组禁忌

不可以如下这么做:

vec4 v1 = vec4(1.0, 2.0, 3.0, 4.0);
vec3 v2 = vec3(5.0, 6.0, 7.0);

// 错误:不能从 v1 和 v2 中直接组合一个新的向量
vec4 v3 = v1.xyzw + v2; // 这会引发错误,因为 v2 不是 vec4 类型

向量重组还不能

vec4 v = vec4(1.0, 2.0, 3.0, 4.0);

// 错误:不能重组成 vec5,因为没有 vec5 类型
vec5 v2 = v.xyzw; // vec5 不存在

以及向量重组不能

vec3 v = vec3(1.0, 2.0, 3.0);

// 错误: vec3 的重组不能包含重复的分量
vec4 v2 = v.xyzx; // 错误,因为 vec4 中不能有两个相同的分量

并且向量重组不能

vec4 v = vec4(1.0, 2.0, 3.0, 4.0);

// 错误:重组不能处理条件逻辑
vec4 result = (v.x > 2.0) ? v.yzxw : v.zwxy; // 需要额外的条件处理

② 矩阵(Matrix)
矩阵是用于表示和处理图形变换的重要工具。矩阵在图形管线中的作用主要是进行各种空间变换,如模型变换、视图变换和投影变换。了解如何使用矩阵可以帮助实现更复杂和灵活的图形效果。后续用到的话,做更多介绍。

3.GLSL的输入输出

GLSL定义了in和out关键字来声明输入和输出数据。

顶点着色器的输入是从顶点数据中直接接收,另外顶点着色器使用location这一元数据指定输入变量。例如,layout (location = 0)。顶点着色器需要为其输入提供了额外的layout标识,这样才能把它链接到顶点数据。

layout (location = 0) 标识符可以省略,可以在OpenGL代码中使用glGetAttribLocation查询属性位置值。

@本节案例 code 2

见 vertexShaderSource ,省略 layout(location = 0) 和 layout(location = 1),然后使用 glGetAttribLocation 获取位置。

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

// Vertex and Fragment shader source code
const char* vertexShaderSource = R"(
#version 330 core
//layout(location = 0) in vec3 aPos; // Attribute 0
//layout(location = 1) in vec3 aColor; // Attribute 1
in vec3 aPos; // Attribute 0
in vec3 aColor; // Attribute 1

out vec3 vertexColor;

void main() {
    gl_Position = vec4(aPos, 1.0);
    vertexColor = aColor;
}
)";

const char* fragmentShaderSource = R"(
#version 330 core
in vec3 vertexColor;

out vec4 FragColor;

void main() {
    FragColor = vec4(vertexColor, 1.0);
}
)";

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    glViewport(0, 0, width, height);
}

GLuint compileShader(GLenum type, const char* source) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);

    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(shader, 512, NULL, infoLog);
        fprintf(stderr, "Shader compilation failed: %s\n", infoLog);
    }
    return shader;
}

GLuint createShaderProgram() {
    GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
    GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    GLint success;
    GLchar infoLog[512];
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        fprintf(stderr, "Program linking failed: %s\n", infoLog);
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return shaderProgram;
}

void setupVertexAttributes(GLuint shaderProgram, GLuint& VAO, GLuint& VBO, GLuint& EBO) {
    glUseProgram(shaderProgram);

    // Get vertex attribute locations
    GLint posAttrib = glGetAttribLocation(shaderProgram, "aPos");
    GLint colorAttrib = glGetAttribLocation(shaderProgram, "aColor");

    // Vertex data
    GLfloat vertices[] = {
        // positions        // colors
         0.5f,  0.5f, 0.0f,  1.0f, 0.0f, 0.0f, // top right
         0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f, // bottom left
        -0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 1.0f  // top left 
    };
    GLuint indices[] = {  // Note that we start from 0!
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };

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

    // Set position attribute
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(posAttrib);

    // Set color attribute
    glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(colorAttrib);

    glBindVertexArray(0);
}

int main() {
    // Initialize GLFW
    if (!glfwInit()) {
        fprintf(stderr, "Failed to initialize GLFW\n");
        return -1;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Create a windowed mode window and its OpenGL context
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Example", NULL, NULL);
    if (!window) {
        fprintf(stderr, "Failed to create GLFW window\n");
        glfwTerminate();
        return -1;
    }

    // Make the window's context current
    glfwMakeContextCurrent(window);

    // Load OpenGL function pointers using glad
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        fprintf(stderr, "Failed to initialize OpenGL context\n");
        return -1;
    }

    // Set the viewport size callback
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // Compile and link shaders
    GLuint shaderProgram = createShaderProgram();

    // Setup vertex attributes
    GLuint VAO, VBO, EBO;
    setupVertexAttributes(shaderProgram, VAO, VBO, EBO);

    // Render loop
    while (!glfwWindowShouldClose(window)) {
        // Clear the color buffer
        glClear(GL_COLOR_BUFFER_BIT);

        // Render
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        // Swap buffers
        glfwSwapBuffers(window);

        // Poll for and process events
        glfwPollEvents();
    }

    // Cleanup
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(shaderProgram);

    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}

Code 2 Result:
在这里插入图片描述

4.着色器示例

顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0

out vec4 vertexColor; // 为片段着色器指定一个颜色输出

void main()
{
    gl_Position = vec4(aPos, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色
}

片段着色器:

#version 330 core
out vec4 FragColor;

in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)

void main()
{
    FragColor = vertexColor;
}

5.Uniform

Uniform是另一种从我们的应用程序在 CPU 上传递数据到 GPU 上的着色器的方式,但uniform和顶点属性有些不同。首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。

要在 GLSL 中声明 uniform,我们只需将 uniform 关键字添加到具有类型和名称的着色器中。从那时起,我们就可以在着色器中使用新声明的 uniform。我们来看看这次是否能通过uniform设置三角形的颜色:

#version 330 core
out vec4 FragColor;

uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量

void main()
{
    FragColor = ourColor;
}

在片段着色器中声明了一个uniform vec4的ourColor,并把片段着色器的输出颜色设置为uniform值的内容。因为uniform是全局变量,我们可以在任何着色器中定义它们,而无需通过顶点着色器作为中介。顶点着色器中不需要这个uniform,所以我们不用在那里定义它。

如果声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误!

对于使用 uniform vec4 ourColor;,如下,获取该变量的着色器的uniform属性的索引位置。当得到uniform的索引/位置值后,我们就可以更新它的值了。这次我们不去给像素传递单独一个颜色,而是让它随着时间改变颜色:

float timeValue = glfwGetTime();
float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

完整代码如下:

@本节案例 code 3
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <cmath> // For sin() function

// Vertex and Fragment shader source code
const char* vertexShaderSource = R"(
#version 330 core
layout(location = 0) in vec3 aPos; // Attribute 0
layout(location = 1) in vec3 aColor; // Attribute 1

out vec3 vertexColor;

void main() {
    gl_Position = vec4(aPos, 1.0);
    vertexColor = aColor;
}
)";

const char* fragmentShaderSource = R"(
#version 330 core
in vec3 vertexColor;

out vec4 FragColor;

uniform vec4 ourColor;

void main() {
    FragColor = ourColor;
}
)";

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    glViewport(0, 0, width, height);
}

GLuint compileShader(GLenum type, const char* source) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);

    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(shader, 512, NULL, infoLog);
        fprintf(stderr, "Shader compilation failed: %s\n", infoLog);
    }
    return shader;
}

GLuint createShaderProgram() {
    GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
    GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    GLint success;
    GLchar infoLog[512];
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        fprintf(stderr, "Program linking failed: %s\n", infoLog);
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return shaderProgram;
}

void setupVertexAttributes(GLuint& VAO, GLuint& VBO) {
    GLfloat vertices[] = {
        // positions        // colors
         0.5f,  0.5f, 0.0f,  1.0f, 0.0f, 0.0f, // top right
         0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f, // bottom left
        -0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 1.0f  // top left 
    };
    GLuint indices[] = {  // Note that we start from 0!
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    GLuint EBO;
    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);

    // Set position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // Set color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);
}

int main() {
    // Initialize GLFW
    if (!glfwInit()) {
        fprintf(stderr, "Failed to initialize GLFW\n");
        return -1;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Create a windowed mode window and its OpenGL context
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Dynamic Color Example", NULL, NULL);
    if (!window) {
        fprintf(stderr, "Failed to create GLFW window\n");
        glfwTerminate();
        return -1;
    }

    // Make the window's context current
    glfwMakeContextCurrent(window);

    // Load OpenGL function pointers using glad
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        fprintf(stderr, "Failed to initialize OpenGL context\n");
        return -1;
    }

    // Set the viewport size callback
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // Compile and link shaders
    GLuint shaderProgram = createShaderProgram();

    // Setup vertex attributes
    GLuint VAO, VBO;
    setupVertexAttributes(VAO, VBO);

    // Render loop
    while (!glfwWindowShouldClose(window)) {
        // Clear the color buffer
        glClear(GL_COLOR_BUFFER_BIT);

        // Calculate dynamic green value
        float timeValue = glfwGetTime();
        float greenValue = (sin(timeValue) / 2.0f) + 0.5f;

        // Use shader program and set uniform color
        glUseProgram(shaderProgram);
        GLint vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
        glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

        // Render
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        // Swap buffers
        glfwSwapBuffers(window);

        // Poll for and process events
        glfwPollEvents();
    }

    // Cleanup
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);

    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}

Code Result 动态呼吸灯效果:
在这里插入图片描述

待续。。。

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

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

相关文章

『功能项目』GameObject对象池 - 第三职业【39】

本章项目成果展示 我们打开上一篇38管理器基类的项目&#xff0c; 本章要做的事情是利用对象池制作第三个职业——魔法师 在GameRoot对象下创建空物体 重命名为PoolRoot 将GameRoot拖拽至预制体 创建脚本&#xff1a; 编写脚本&#xff1a;PoolManager.cs using UnityEngine;…

使用豆包MarsCode 编写 Node.js 全栈应用开发实践

以下是「豆包MarsCode 体验官」优秀文章&#xff0c;作者狼叔。 欢迎更多用户使用豆包MarsCode 并分享您的产品使用心得及反馈、创意项目开发等&#xff0c;【有奖征集&#xff5c;人人都是豆包MarsCode 测评官&#xff01;】活动正在火热进行中&#xff0c;欢迎大家投稿参加&a…

【Python报错已解决】 SyntaxError: invalid syntax

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法2.1 方法一&#xff1a;修复缺失的括号或引号2.…

甘肃五仁月饼:传统风味,舌尖上的乡愁

在中秋佳节的美食画卷中&#xff0c;甘肃食家巷五仁月饼以其独特的魅力占据着重要的一席之地。甘肃五仁月饼&#xff0c;那朴实无华的外表下&#xff0c;藏着无尽的美味与情怀。它的饼皮金黄酥脆&#xff0c;散发着淡淡的麦香&#xff0c;仿佛在诉说着古老的制作工艺。轻轻咬上…

Java:动态代理

Java&#xff1a;动态代理 什么是代理 代理模式 是一种设计模式&#xff0c;它为其他对象提供了一种代理以控制对这个对象的访问。代理对象通常包装实际的目标对象&#xff0c;以提供一些附加的功能&#xff08;如延迟加载、访问控制、日志记录等&#xff09;。我们一般可以使…

C++中的内存管理和模板初识

一、内存管理 1.1内存区域的划分 1.1.1内存划分区域图示 1.1.1补&#xff1a;堆和栈都可以进行动态分配和静态分配吗&#xff1f; 不是的&#xff0c;堆无法进行静态分配&#xff0c;只能动态分配&#xff1b;栈可以利用_alloca动态分配&#xff0c;但是分配的空间不能用fre…

基于Logistic-Map混沌序列的数字信息加解密算法matlab仿真,支持对文字,灰度图,彩色图,语音进行加解密

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于Logistic-Map混沌序列的数字信息加解密算法matlab仿真,系统包含GUI操作界面&#xff0c;系统支持对文字,灰度图,彩色图,语音进行加解密。 2.测试软件版本以及…

项目运行插件-日志管理

日志管理 项目运行时模块提供了项目日志收集&#xff0c;检索和保存查询方案等功能。 体验地址&#xff1a; http://119.163.197.219:13456/view/runtime/index.html#/log/aioLogPage 沟通加QQ群 &#xff1a; 908377977 gitee 开源地址 &#xff1a; https://gitee.com/aio…

打印文档时,只有图片中的文本不清晰该如何处理

最近打印东西的时候&#xff0c;发现只有图片中的文本并不清晰&#xff0c;就想研究一下如何改善这个问题。 打印机是佳能的 MF113w&#xff0c;一个不错的多功能激光黑白打印机&#xff0c;支持无线打印。唯一问题就是每次 DHCP 分配 IP 到期后&#xff0c;这款打印机就会亮错…

AI提质增效率赋能工业产品质检,基于高精度YOLOv5全系列参数【n/s/m/l/x】模型开发构建工业生产场景下PCB电路板缺陷问题智能化分割检测识别分析系统

在PCB电路板的生产制造过程中&#xff0c;质量检测是确保产品质量、维护品牌形象的关键环节。然而&#xff0c;传统的人工检测方式依赖于经验丰富的工人师傅通过光学显微镜等设备进行逐块检查&#xff0c;这不仅劳动强度大、效率低下&#xff0c;而且受限于人的主观判断、视力疲…

《华为 eNSP 模拟器安装教程》

1.电脑安装环境要求&#xff1a; 检查电脑是否安装过 eNSP 和依赖软件&#xff0c;如果有&#xff0c;请全部卸载。 安装软件列表&#xff1a; 2.软件安装&#xff1a; 安装 WinPcap&#xff1a; 打开安装包&#xff0c;单击【Next】 单击【I Agree】 单击【Install】 单击【…

《信息系统安全》课程实验指导

第1关&#xff1a;实验一&#xff1a;古典密码算法---代换技术 任务描述 本关任务&#xff1a;了解古典密码体制技术中的代换技术&#xff0c;并编程实现代换密码的加解密功能。 注意所有明文字符为26个小写字母&#xff0c;也就是说字母表为26个小写字母。 相关知识 为了完…

1、常用的数据库、表操作

基本的建表和数据库拷贝操作。 一、数据定义语言DDL show databases; # 查看全部数据库 show create database db; # 查看数据库db create database db; # 创建数据库db drop database db; # 删除数据库db use db; # 使用数据库db基本…

1 Linux SSH安全加固_linux system-auth

![在这里插入图片描述](https://img-blog.csdnimg.cn/20201117150524918.png?x-oss-processimage/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTA3OTc3,size_16,color_FFFFFF,t_70#pic_center) ![在这里插入图片描述](https://…

11、LLaMA-Factory自定义数据集微调

1、数据集定义 针对实际的微调需求&#xff0c;使用专门针对业务垂直领域的私有数据进行大模型微调才是我们需要做的。因此&#xff0c;我们需要探讨如何在LLaMA-Factory项目及上述创建的微调流程中引入自定义数据集进行微调。**对于LLaMA-Factory项目&#xff0c;目前仅支持两…

什么是 Grafana?

什么是 Grafana&#xff1f; Grafana 是一个功能强大的开源平台&#xff0c;用于创建、查看、查询和分析来自多个来源的数据。通过可视化仪表盘&#xff08;Dashboard&#xff09;&#xff0c;它能够帮助用户监控实时数据、生成历史报告&#xff0c;甚至进行预测分析。Grafana…

深入理解Java虚拟机:Jvm总结-类文件结构以及类加载机制

第六章 类文件结构 6.1 意义 代码编译的结果从本地机器码转变为字节码&#xff0c;冲破了平台界限。 6.2 无关性的基石 实现语言无关性的基础仍然是虚拟机和字节码存储格式。Java虚拟机不与包括Java语言在内的任何程序语言绑定&#xff0c;它只与“Class文件”这种特定的二…

vue2实践:el-table实现由用户自己添加删除行数的动态表格

需求 项目中需要提供一个动态表单&#xff0c;如图&#xff1a; 当我点击添加时&#xff0c;便添加一行&#xff1b;点击右边的删除时&#xff0c;便删除这一行。 至少要有一行数据&#xff0c;但是没有上限。 思路 这种每一行的数据固定&#xff0c;但是不定行数的&#x…

校园水电费管理|基于java的校园水电费管理小程序系统 (源码+数据库+文档)

校园水电费管理 目录 基于java的校园水电费管理小程序系统 一、前言 二、系统设计 三、系统功能设计 小程序端 后台功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕…

Selenium使用浏览器用户配置进行测试

本文主要介绍了如何在使用Selenium WebDriver进行自动化测试时&#xff0c;创建和使用自定义的Firefox配置文件。 什么是Firefox配置文件&#xff1f; Firefox会将用户的个人信息&#xff0c;如书签、密码和用户偏好设置存储在一个称为配置文件的文件集合中&#xff0c;这些文…