[OpenGL]使用OpenGL加载obj模型、绘制纹理

一、简介

本文介绍了如何使用OpenGL加载obj模型,绘制简单纹理。
在加载obj模型时,使用glm库确定对顶点进行坐标变换的MVP(model, view, projection)矩阵。
在绘制纹理时,使用stb_image.h头文件加载纹理图片,生成纹理。

按照本文代码实现后,理论上可以得到以下结果:

绘制结果

二、使用OpenGL加载obj模型、绘制纹理

0. 环境需要

  • Linux,或者 windos下使用wsl2。
  • 安装GLFW和GLAD。请参考[OpenGL] wsl2上安装使用cmake+OpenGL教程。
  • 安装glm。glm是个可以只使用头文件的库,因此可以直接下载release的压缩文件,然后解压到include目录下。例如,假设下载的release版本的压缩文件为glm-1.0.1-light.zip。将glm-1.0.1-light.zip复制include目录下,然后执行以下命令即可解压glm源代码:
    unzip glm-1.0.1-light.zip
    
  • 需要下载 stb_image.h 作为加载.png图像的库。将 stb_image.h 下载后放入include/目录下。

1. 项目目录

项目目录

其中:

  • Mesh.hpp 包含了自定义的 Vertex, Texture, 和 Mesh 类,用于加载 obj 模型、加载图片生成纹理。
  • Shader.hpp 用于创建 shader 程序。
  • vertexShader.glslfragmentShader.glsl是用于编译 shader 程序的 顶点着色器 和 片段着色器 代码。

下面介绍各部分的代码:

2. CMakeLists.txt代码

cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 14)

project(OpenGL_Load_Model)

include_directories(include)

find_package(glfw3 REQUIRED)
file(GLOB project_file main.cpp glad.c)
add_executable(${PROJECT_NAME} ${project_file})
target_link_libraries(${PROJECT_NAME} glfw)

3. Mesh.hpp 代码

#pragma once

#include <glad/glad.h> // holds all OpenGL type declarations
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "Shader.hpp"

#include <string>
#include <vector>
using namespace std;

struct Vertex
{
    // position
    glm::vec3 Position;
    // normal
    glm::vec3 Normal;
    // texCoords
    glm::vec2 TexCoords;
};

struct Texture
{
    string path;
    GLuint Id; // 纹理 id
};

class Mesh
{
  public:
    // mesh Data
    vector<Vertex> vertices;// vertex 数据,一个顶点包括 position, normal 和 texture coord 三个信息
    vector<unsigned int> indices;// index 数据,用于拷贝到 EBO 中
    Texture texture;

    unsigned int VAO;

    Mesh(string obj_path, string texture_path = "")
    {
        // load obj
        ifstream obj_file(obj_path, std::ios::in);
        if (obj_file.is_open() == false)
        {
            std::cerr << "Failed to load obj: " << obj_path << "\n";
            return;
        }

        int position_id = 0;
        int normal_id = 0;
        int texture_coord_id = 0;
        string line;
        while (getline(obj_file, line))
        {
            std::istringstream iss(line);
            std::string prefix;
            iss >> prefix;

            if (prefix == "v") // vertex
            {
                if (vertices.size() <= position_id)
                {
                    vertices.push_back(Vertex());
                }

                iss >> vertices[position_id].Position.x;
                iss >> vertices[position_id].Position.y;
                iss >> vertices[position_id].Position.z;
                position_id++;
            }
            else if (prefix == "vn") // normal
            {
                if (vertices.size() <= normal_id)
                {
                    vertices.push_back(Vertex());
                }

                iss >> vertices[normal_id].Normal.x;
                iss >> vertices[normal_id].Normal.y;
                iss >> vertices[normal_id].Normal.z;
                normal_id++;
            }
            else if (prefix == "vt") // texture coordinate
            {
                if (vertices.size() <= texture_coord_id)
                {
                    vertices.push_back(Vertex());
                }

                iss >> vertices[texture_coord_id].TexCoords.x;
                iss >> vertices[texture_coord_id].TexCoords.y;
                texture_coord_id++;
            }
            else if (prefix == "f") // face
            {

                for (int i = 0; i < 3; ++i)
                {
                    std::string vertexData;
                    iss >> vertexData;
                    unsigned int ver, tex, nor;
                    sscanf(vertexData.c_str(), "%d/%d/%d", &ver, &tex, &nor);
                    indices.push_back(ver - 1);
                }
            }
        }
        obj_file.close();

        // load texture
        GLuint textureID;
        glGenTextures(1, &textureID); // 生成纹理 ID
        glBindTexture(GL_TEXTURE_2D, textureID); // 绑定纹理,说明接下来对纹理的操作都应用于对象 textureID 上

        // 设置纹理参数
        // 设置纹理在 S 方向(水平方向)的包裹方式为 GL_REPEAT
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        // 设置纹理在 T 方向(垂直方向)的包裹方式为 GL_REPEAT
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        // 设置纹理的缩小过滤方式,当纹理变小时,使用 GL_LINEAR (线性过滤)方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        // 设置纹理的放大过滤方式,当纹理变大时,使用 GL_LINEAR (线性过滤)方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // 加载纹理图像
        int width, height, nrChannels;
        stbi_set_flip_vertically_on_load(true);
        unsigned char *data = stbi_load(texture_path.c_str(), &width, &height, &nrChannels, 0);
        if (data)
        {
            GLenum format;
            if (nrChannels == 1)
                format = GL_RED;
            else if (nrChannels == 3)
                format = GL_RGB;
            else if (nrChannels == 4)
                format = GL_RGBA;

            // 生成纹理
            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
            glGenerateMipmap(GL_TEXTURE_2D); // 生成 Mipmaps
        }
        else
        {
            std::cerr << "Failed to load texture: " << texture_path << "\n";
        }
        stbi_image_free(data); // 释放图像内存
        glBindTexture(GL_TEXTURE_2D, 0); // 解绑纹理

        texture.Id = textureID;
        texture.path = texture_path;

        setupMesh();
    }

    // render the mesh
    void Draw(Shader &shader)
    {
        // draw mesh
        glActiveTexture(GL_TEXTURE0);                                    // 激活 纹理单元0
        glBindTexture(GL_TEXTURE_2D, texture.Id);                        // 绑定纹理,将纹理texture.id 绑定到 纹理单元0 上
        glUniform1i(glGetUniformLocation(shader.ID, "texture1"), 0); // 将 shader 中的 texture1 绑定到 纹理单元0

        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);
        glBindTexture(GL_TEXTURE_2D, 0);
        glBindVertexArray(0);
    }

  private:
    // render data
    unsigned int VBO, EBO;

    // initializes all the buffer objects/arrays
    void setupMesh()
    {
        // create buffers/arrays
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glGenBuffers(1, &EBO);

        glBindVertexArray(VAO);
        // load data into vertex buffers
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        // A great thing about structs is that their memory layout is sequential for all its items.
        // The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2
        // array which again translates to 3/2 floats which translates to a byte array.
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

        // set the vertex attribute pointers
        // vertex Positions
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)0);
        // vertex normals
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, Normal));
        // vertex texture coords
        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, TexCoords));

        glBindVertexArray(0);
    }
};

4. Shader.hpp 代码

Shader.hpp 即 LearnOpenGL-入门-着色器 中的 由于管理 shader 的头文件。

#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h>
#include <glm/glm.hpp>

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

class Shader
{
  public:
    unsigned int ID;
    // constructor generates the shader on the fly
    // ------------------------------------------------------------------------
    Shader(const char *vertexPath, const char *fragmentPath)
    {
        // 1. retrieve the vertex/fragment source code from filePath
        std::string vertexCode;
        std::string fragmentCode;
        std::ifstream vShaderFile;
        std::ifstream fShaderFile;
        // ensure ifstream objects can throw exceptions:
        vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        try
        {
            // open files
            vShaderFile.open(vertexPath);
            fShaderFile.open(fragmentPath);
            std::stringstream vShaderStream, fShaderStream;
            // read file's buffer contents into streams
            vShaderStream << vShaderFile.rdbuf();
            fShaderStream << fShaderFile.rdbuf();
            // close file handlers
            vShaderFile.close();
            fShaderFile.close();
            // convert stream into string
            vertexCode = vShaderStream.str();
            fragmentCode = fShaderStream.str();
        }
        catch (std::ifstream::failure &e)
        {
            std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
        }
        const char *vShaderCode = vertexCode.c_str();
        const char *fShaderCode = fragmentCode.c_str();
        // 2. compile shaders
        unsigned int vertex, fragment;
        // vertex shader
        vertex = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex, 1, &vShaderCode, NULL);
        glCompileShader(vertex);
        checkCompileErrors(vertex, "VERTEX");
        // fragment Shader
        fragment = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment, 1, &fShaderCode, NULL);
        glCompileShader(fragment);
        checkCompileErrors(fragment, "FRAGMENT");
        // shader Program
        ID = glCreateProgram();
        glAttachShader(ID, vertex);
        glAttachShader(ID, fragment);
        glLinkProgram(ID);
        checkCompileErrors(ID, "PROGRAM");
        // delete the shaders as they're linked into our program now and no longer necessary
        glDeleteShader(vertex);
        glDeleteShader(fragment);
    }
    // activate the shader
    // ------------------------------------------------------------------------
    void use() const
    {
        glUseProgram(ID);
    }
    // utility uniform functions
    // ------------------------------------------------------------------------
    void setBool(const std::string &name, bool value) const
    {
        glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
    }
    // ------------------------------------------------------------------------
    void setInt(const std::string &name, int value) const
    {
        glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
    }
    // ------------------------------------------------------------------------
    void setFloat(const std::string &name, float value) const
    {
        glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
    }
    // ------------------------------------------------------------------------
    void setVec2(const std::string &name, const glm::vec2 &value) const
    {
        glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
    }
    void setVec2(const std::string &name, float x, float y) const
    {
        glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
    }
    // ------------------------------------------------------------------------
    void setVec3(const std::string &name, const glm::vec3 &value) const
    {
        glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
    }
    void setVec3(const std::string &name, float x, float y, float z) const
    {
        glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
    }
    // ------------------------------------------------------------------------
    void setVec4(const std::string &name, const glm::vec4 &value) const
    {
        glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
    }
    void setVec4(const std::string &name, float x, float y, float z, float w) const
    {
        glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
    }
    // ------------------------------------------------------------------------
    void setMat2(const std::string &name, const glm::mat2 &mat) const
    {
        glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
    }
    // ------------------------------------------------------------------------
    void setMat3(const std::string &name, const glm::mat3 &mat) const
    {
        glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
    }
    // ------------------------------------------------------------------------
    void setMat4(const std::string &name, const glm::mat4 &mat) const
    {
        glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
    }

  private:
    // utility function for checking shader compilation/linking errors.
    // ------------------------------------------------------------------------
    void checkCompileErrors(GLuint shader, std::string type)
    {
        GLint success;
        GLchar infoLog[1024];
        if (type != "PROGRAM")
        {
            glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
            if (!success)
            {
                glGetShaderInfoLog(shader, 1024, NULL, infoLog);
                std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
                          << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
            }
        }
        else
        {
            glGetProgramiv(shader, GL_LINK_STATUS, &success);
            if (!success)
            {
                glGetProgramInfoLog(shader, 1024, NULL, infoLog);
                std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n"
                          << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
            }
        }
    }
};
#endif

5. vertexShader.glsl 和 fragmentShader.glsl 代码

vertexShader.glsl

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNor;
layout (location = 2) in vec2 aTexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec2 textureCoord;
void main()
{
    textureCoord = aTexCoord;
    gl_Position = projection * view * model * vec4(aPos, 1.0f);
}

fragmentShader.glsl

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

6. main.cpp代码

1). 代码整体流程

  1. 初始化glfw,glad,窗口
  2. 编译 shader 程序
  3. 加载obj模型、纹理图片
  4. 设置MVP变换矩阵
  5. 开始绘制
  6. 释放资源

2). main.cpp代码

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "Shader.hpp"
#include "Mesh.hpp"

#include "glm/ext.hpp"
#include "glm/mat4x4.hpp"

#include <random>
#include <iostream>
// 用于处理窗口大小改变的回调函数
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
// 用于处理用户输入的函数
void processInput(GLFWwindow *window);

// 指定窗口默认width和height像素大小
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

/************************************/

int main()
{

    /****** 1.初始化glfw, glad, 窗口 *******/
    // glfw 初始化 + 配置 glfw 参数
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 在创建窗口之前
    glfwWindowHint(GLFW_SAMPLES, 4); // 设置多重采样级别为4
    // glfw 生成窗口
    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;
    }
    // 设置窗口window的上下文
    glfwMakeContextCurrent(window);
    // 配置window变化时的回调函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // 使用 glad 加载 OpenGL 中的各种函数
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    // 启用 深度测试
    glEnable(GL_DEPTH_TEST);
    // 启用 多重采样抗锯齿
    glEnable(GL_MULTISAMPLE);
    // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 使用线框模式,绘制时只绘制 三角形 的轮廓
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // 使用填充模式,绘制时对 三角形 内部进行填充

    /************************************/

    /****** 2.编译 shader 程序 ******/
    Shader ourShader("../resources/vertexShader.glsl", "../resources/fragmentShader.glsl");
    /************************************/

    /****** 3.加载obj模型、纹理图片 ******/

    // Mesh ourModel("../resources/models/backpack/backpack.obj", "../resources/models/backpack/backpack.jpg"); //
    // backpack
    Mesh ourModel("../resources/models/spot/spot.obj", "../resources/models/spot/spot.png"); // dairy cow
    // Mesh ourModel("../resources/models/rock/rock.obj", "../resources/models/rock/rock.png"); // rock
    /************************************/

    /****** 4.设置 MVP 矩阵 ******/
    // model 矩阵
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
    model = glm::rotate(model, glm::radians(0.0f), glm::vec3(1.0f, 0.0f, 0.0f));
    model = glm::rotate(model, glm::radians(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    model = glm::rotate(model, glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
    model = glm::scale(model, glm::vec3(0.5f, 0.5f, 0.5f));

    // view 矩阵
    glm::mat4 view = glm::mat4(1.0f);
    view = glm::lookAt(glm::vec3(0.0f, 0.0f, -1.5f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

    // projection 矩阵
    glm::mat4 projection = glm::mat4(1.0f);
    projection = glm::perspective(glm::radians(60.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
    /************************************/

    /****** 5.开始绘制 ******/
    float rotate = 0.0f;
    while (!glfwWindowShouldClose(window))
    {
        rotate += 0.00005f;
        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        // 清除颜色缓冲区 并且 清楚深度缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // 使用我们之前编译连接好的 shader 程序
        // 必须先使用 shaderProgram 然后才能操作 shaderProgram 中的 uniform 变量
        ourShader.use();

        model = glm::rotate(model, glm::radians(rotate), glm::vec3(0.0f, 1.0f, 0.0f));
        ourShader.setMat4("model", model);
        ourShader.setMat4("view", view);
        ourShader.setMat4("projection", projection);

        ourModel.Draw(ourShader);

        glfwSwapBuffers(window); // 在gfw中启用双缓冲,确保绘制的平滑和无缝切换
        glfwPollEvents(); // 用于处理所有挂起的事件,例如键盘输入、鼠标移动、窗口大小变化等事件
    }

    /************************************/
    /****** 6.释放资源 ******/
    // glfw 释放 glfw使用的所有资源
    glfwTerminate();
    /************************************/
    return 0;
}

// 用于处理用户输入的函数
void processInput(GLFWwindow *window)
{
    // 当按下 Esc 按键时调用 glfwSetWindowShouldClose() 函数,关闭窗口
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, true);
    }
}

// 在使用 OpenGL 和 GLFW 库时,处理窗口大小改变的回调函数
// 当窗口大小发生变化时,确保 OpenGL 渲染的内容能够适应新的窗口大小,避免图像被拉伸、压缩或出现其他比例失真的问题
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
    glViewport(0, 0, width, height);
}

4. 编译运行及结果

编译运行:

cd ./build
cmake ..
make 
./OpenGL_Load_Model

绘制结果:

绘制结果

三、全部代码及模型文件

全部代码以及模型文件可以在使用OpenGL加载obj模型、绘制纹理中下载。

四、参考

[1].[OpenGL]使用OpenGL绘制三维立方体
[2].[OpenGL]使用OpenGL绘制带纹理三角形

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

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

相关文章

108.WEB渗透测试-信息收集-FOFA语法(8)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;107.WEB渗透测试-信息收集-FOFA语法&#xff08;7&#xff09; 指挥系统的后台&#xff…

排序题目:重新排列后的最大子矩阵

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;重新排列后的最大子矩阵 出处&#xff1a;1727. 重新排列后的最大子矩阵 难度 7 级 题目描述 要求 给定一个大小为 m n \texttt{m} \times \tex…

可以白嫖PPT模板的6个网站,赶紧收藏

推荐6个PPT模板网站&#xff0c;免费下载&#xff0c;绝对的高质量&#xff0c;赶紧收藏&#xff01; 1、菜鸟图库 ppt模板免费下载|ppt背景图片 - 菜鸟图库 菜鸟图库网有非常丰富的免费素材&#xff0c;像设计类、办公类、自媒体类等素材都很丰富。PPT模板种类很多&#xff0…

Python和MATLAB库尔巴克–莱布勒散度信息论统计学生物学和算法模型

&#x1f3af;要点 高斯混合模型聚类和t分布随机邻域嵌入底层分析信息论测量复合彩票统计学计算结果离散分布速率最优估计器样本统计相似性快速闭环散度和交叉熵计算催乳素诱导模型贝叶斯快速推理模型视觉皮层活动神经数据分布 Python散度 在数理统计中&#xff0c;库尔巴克…

Gson将对象转换为JSON(学习笔记)

JSON有两种表示结构&#xff0c;对象和数组。对象结构以"{"大括号开始&#xff0c;以"}"大括号结束。中间部分由0或多个以”&#xff0c;"分隔的”key(关键字)/value(值)"对构成&#xff0c;关键字和值之间以":"分隔&#xff0c;语法结…

PHP程序如何实现限制一台电脑登录?

PHP程序如何实现限制一台电脑登录&#xff1f; 可以使用以下几种方法&#xff1a; 1. IP地址限制&#xff1a;在PHP中&#xff0c;可以通过获取客户端的IP地址&#xff0c;然后与允许登录的IP地址列表进行比对。如果客户端的IP地址不在列表中&#xff0c;就禁止登录。 “php $…

HTTP 1.0 2.0 3.0详解

HTTP HTTP全称超文本传输协议&#xff0c;是一种属于应用层的通信协议。它允许将超文本标记语言文档&#xff08;HTML&#xff09;从Web服务器传输到客户端的浏览器。 HTTP报文结构 请求报文结构 请求方法&#xff1a; GET&#xff1a;一般用来请求已被URI识别的资源&#x…

永不失联!遨游双卫星三防手机成为高效应急关键所在

今年9月被戏称为“台风月”&#xff0c;台风“摩羯”、“贝碧嘉”以及热带气旋“普拉桑”接连来袭&#xff0c;极端天气不仅导致了电力中断、道路损毁&#xff0c;更使得传统的通信网络遭受重创&#xff0c;给应急通信保障工作带来了极大的压力。面对“三断”的实战难题&#x…

从文本图片到多模态:3D 数字人打开企业全域商业增长新空间

摘要&#xff1a;数字化与AI浪潮推动各行业变革&#xff0c;内容形式也发生巨变&#xff0c;从文本到多媒体的多模态表达&#xff0c;标志着内容创造走向升维。AIGC 3D生成技术的突飞猛进&#xff0c;彻底打破了传统3D内容生产门槛高、周期长、成本高昂的问题。将3D数字人的打造…

数学建模研赛总结

目录 前言进度问题四分析问题五分析数模论文经验分享总结 前言 本文为博主数学建模比赛第五天的内容记录&#xff0c;希望所写的一些内容能够对大家有所帮助&#xff0c;不足之处欢迎大家批评指正&#x1f91d;&#x1f91d;&#x1f91d; 进度 今天已经是最后一天了&#xf…

nginx常用的性能优化

第一步调整工作进程数&#xff1a; 设置成auto&#xff0c;会自动按照CPU核心数来启动工作进程数&#xff0c;如果设置具体数字&#xff0c;则只会使用指定数量的CPU核心&#xff0c;无法将CPU同一时间都能用得到&#xff0c;所以就不能发挥服务器的最大的性能。 第二步增加进程…

el-table添加fixed后错位问题

1 方案1 return {isShow:false, }mounted() {this.isShowtrue},watch: {$route(newRoute) {this.monitoredRoute newRoute; // 将新的路由信息保存到组件的monitoredRoute属性中// 执行其他操作或调用其他方法},//或$route(newRoute) {this.monitoredRoute newRoute; // 将新…

Java项目实战II基于Java+Spring Boot+MySQL的免税商品优选购物商城(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着全球贸易的日益繁荣和消费者需求的多样化&#xff0c;免税商品购物已成为众多旅行者和消费者的热…

浸没式密封连接器

在当今科技快速发展的背景下&#xff0c;电子设备的整合度与性能需求持续提高&#xff0c;而连接技术作为电子设备间交互的关键&#xff0c;其重要性显而易见。在各式各样的连接技术当中&#xff0c;浸没式密封连接器凭借其独到设计和高超性能&#xff0c;在特定使用环境中显示…

SpringBoot3中ymal配置文件(持续更新)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 在SpringBoot项目中,使用application.properties进行配置管理时&#xff0c;…

实习问题(配置文件获取参数)

Java中用SpringBoot框架&#xff0c;当我们要获取配置文件yml里的参数时&#xff0c;用Value注解获取 如果配置文件中没有srvSealUploadPath这个参数的话&#xff0c;可以用Value("${srvSealUploadPath:data/idoc/temp}")&#xff0c;这个的意思是&#xff0c;如果配…

[大语言模型] 情感认知在大型语言模型中的近期进展-2024-09-26

[大语言模型] 情感认知在大型语言模型中的近期进展-2024-09-26 目录 文章目录 [大语言模型] 情感认知在大型语言模型中的近期进展-2024-09-26目录论文信息摘要主要内容包括&#xff1a;研究方法与资源的分类&#xff1a;结论&#xff1a; 论文信息 Title: Recent Advancement …

vector中push_back和emplace_back的区别

push_back 在引入右值引用&#xff0c;转移构造函数&#xff0c;转移复制运算符之前&#xff0c;通常使用push_back()向容器中加入一个右值元素&#xff08;临时对象&#xff09;的时候&#xff0c;首先会调用构造函数构造这个临时对象&#xff0c;然后需要调用拷贝构造函数将…

后端Java-SpringBoot整合MyBatisPlus步骤(超详细)

1.新建项目。 2.点击完上一步的next之后&#xff0c;选择pom.xml文件中的依赖。 3.点击pom文件进行项目初始化。 按照下面的俩步骤刷新一下maven &#xff0c;让文件生效 4.新建一个application.yml文件 5. 新建一个数据库mp&#xff0c;在数据库中新建一张user表 6.连接数据…

onnx TRT 版本对应关系

Onnx 版本和opset 关系 https://github.com/onnx/onnx/blob/main/docs/Versioning.md Onnx runtime 对应 onnx opset 版本 Compatibility | onnxruntime Tensor RT 和onnx 支持版本可以看如下并选择对应分支 https://github.com/onnx/onnx-tensorrt/blob/release/8.4-GA/doc…