OpenGL学习日记之模型绘制

news2025/3/1 18:31:59

自己编译运行过程中遇到的一些问题

下载Assimp已编译的lib(因为我们公司的电脑有很多权限和限制,也不能自己安装一些没有报备的软件,所以愁方便我就没有用cMake自己编译了)找到一位免费分享的博主的。
https://blog.csdn.net/lady_killer9/article/details/89429092

系统找不到zlib.dll文件的解决方法
https://blog.csdn.net/LHXvs2015/article/details/120674525
https://www.cnblogs.com/yangjinbang/p/8330786.html
在这里插入图片描述
下载Assimp可识别的模型地址
https://learnopengl-cn.github.io/03%20Model%20Loading/03%20Model/

现实生活中,我们都是美术同学通过一些现代的绘图工具,为我们导出模型来绘制,建模工具会自己生成所有的顶点坐标、顶点法线和纹理坐标,我们开发者就不需要去关注这些细节了。

Mesh

Mesh俗称网格,一个网格代表可绘制的实体。我们自定义一个网格类
至少要包含一组顶点数据,这组顶点数据应该包含顶点坐标,顶点法线,已经顶点的uv坐标。
一组绘制顺序索引,用于EBO绑定。
一组贴图数据,用于纹理映射。

#pragma once
// Std. Includes
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
// GL Includes
#include <GL/glew.h> // Contains all the necessery OpenGL includes
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>


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

struct Texture {
    GLuint id;
    string type;
    aiString path;
};

class Mesh {
public:  
    vector<Vertex> vertices;
    vector<GLuint> indices;
    vector<Texture> textures;

    //构造函数
    Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> textures)
    {
        this->vertices = vertices;
        this->indices = indices;
        this->textures = textures;

        // Now that we have all the required data, set the vertex buffers and its attribute pointers.
        this->setupMesh();
    }

    void Draw(Shader shader)
    {       
        GLuint diffuseNr = 1;
        GLuint specularNr = 1; 
        //绑定贴图与采样器
        for (GLuint i = 0; i < this->textures.size(); i++)
        {
            glActiveTexture(GL_TEXTURE0 + i);        
            stringstream ss;
            string number;
            string name = this->textures[i].type;
            if (name == "texture_diffuse")
                ss << diffuseNr++; 
            else if (name == "texture_specular")
                ss << specularNr++; 
            number = ss.str(); 
            
            //保证每个uniform采样器对应着正确的纹理单元
            glUniform1i(glGetUniformLocation(shader.Program, (name + number).c_str()), i);           
            glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
        }
      
        glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 16.0f);
        glBindVertexArray(this->VAO);
        glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
       
        for (GLuint i = 0; i < this->textures.size(); i++)
        {
            glActiveTexture(GL_TEXTURE0 + i);
            glBindTexture(GL_TEXTURE_2D, 0);
        }
    }
private:  
    GLuint VAO, VBO, EBO;
       
    //初始化各种缓冲和链接数据
    void setupMesh()
    {
      
        //初始化VAO,VBO,EBO 缓冲对象
        glGenVertexArrays(1, &this->VAO);
        glGenBuffers(1, &this->VBO);
        glGenBuffers(1, &this->EBO);

        glBindVertexArray(this->VAO);
       
        //将顶点数据初始化至缓冲中
        glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
        glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex), &this->vertices[0], GL_STATIC_DRAW);

        //将绘制顺序索引初始到缓冲中
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW);    
        glEnableVertexAttribArray(0);

        //将数据链接到顶点属性,告诉openGL如何解析这些数据
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));
        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoords));

        glBindVertexArray(0);
    }
};



模型类

现实生活中一个我们看到的模型都是由很多部位组成的,也可以说成是由很多mesh组合而成的,比如一张桌子,是由一个桌板加四个桌脚拼成的为了方便抽象,我们又封装了一层模型的类。
这个类主要就是去解析美术给我们的一个从Blender,Maya等工具导出的模型,将其拆分为一个Mesh数组,然后再调用Mesh类的绘制。

#pragma once
// Std. Includes
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
// GL Includes
#include <GL/glew.h> // Contains all the necessery OpenGL includes
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <SOIL.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

#include "Mesh.h"

GLint TextureFromFile(const char* path, string directory);

class Model
{
public:
    /*  Functions   */
    // Constructor, expects a filepath to a 3D model.
    Model(string path)
    {
        this->loadModel(path);
    }

    // Draws the model, and thus all its meshes
    void Draw(Shader shader)
    {
        for (GLuint i = 0; i < this->meshes.size(); i++)
            this->meshes[i].Draw(shader);
    }

private:
    /*  Model Data  */
    vector<Mesh> meshes;
    string directory;
    vector<Texture> textures_loaded;	// Stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once.

    int mycount = 0;
    void loadModel(string path)
    {
        
        Assimp::Importer importer;
        const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);     
        if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
        {
            cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl;
            return;
        }       
        this->directory = path.substr(0, path.find_last_of('/'));
        this->processNode(scene->mRootNode, scene);
        //printf("mesh个数: %d", mycount);
    }

    void processNode(aiNode* node, const aiScene* scene)
    {
       
        for (GLuint i = 0; i < node->mNumMeshes; i++)
        {           
            aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];          
            this->meshes.push_back(this->processMesh(mesh, scene));
        }       
        for (GLuint i = 0; i < node->mNumChildren; i++)
        {
            this->processNode(node->mChildren[i], scene);
        }

    }

    Mesh processMesh(aiMesh* mesh, const aiScene* scene)
    {
        mycount++;
        vector<Vertex> vertices;
        vector<GLuint> indices;
        vector<Texture> textures;
      
        for (GLuint i = 0; i < mesh->mNumVertices; i++)
        {
            Vertex vertex;
            glm::vec3 vector; 
          
            vector.x = mesh->mVertices[i].x;
            vector.y = mesh->mVertices[i].y;
            vector.z = mesh->mVertices[i].z;
            vertex.Position = vector;
            
            vector.x = mesh->mNormals[i].x;
            vector.y = mesh->mNormals[i].y;
            vector.z = mesh->mNormals[i].z;
            vertex.Normal = vector;
           
            if (mesh->mTextureCoords[0]) 
            {
                glm::vec2 vec;               
                vec.x = mesh->mTextureCoords[0][i].x;
                vec.y = mesh->mTextureCoords[0][i].y;
                vertex.TexCoords = vec;
            }
            else
                vertex.TexCoords = glm::vec2(0.0f, 0.0f);
            vertices.push_back(vertex);
        }
      
        for (GLuint i = 0; i < mesh->mNumFaces; i++)
        {
            aiFace face = mesh->mFaces[i];
          
            for (GLuint j = 0; j < face.mNumIndices; j++)
                indices.push_back(face.mIndices[j]);
        }
       
        if (mesh->mMaterialIndex >= 0)
        {
            aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];            
          
            vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
            textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
           
            vector<Texture> specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
            textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
        }      
        return Mesh(vertices, indices, textures);
    }

    vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName)
    {
        vector<Texture> textures;
        for (GLuint i = 0; i < mat->GetTextureCount(type); i++)
        {
            aiString str;
            mat->GetTexture(type, i, &str);           
            GLboolean skip = false;
            for (GLuint j = 0; j < textures_loaded.size(); j++)
            {
                if (std::strcmp(textures_loaded[j].path.C_Str(), str.C_Str()) == 0)
                {
                    textures.push_back(textures_loaded[j]);
                    skip = true; 
                    break;
                }
            }
            if (!skip)
            {  
                Texture texture;
                texture.id = TextureFromFile(str.C_Str(), this->directory);
                texture.type = typeName;
                texture.path = str;
                textures.push_back(texture);
                this->textures_loaded.push_back(texture); 
            }
        }
        return textures;
    }
};




GLint TextureFromFile(const char* path, string directory)
{  
    string filename = string(path);
    filename = directory + '/' + filename;
    GLuint textureID;
    glGenTextures(1, &textureID);
    int width, height;
    unsigned char* image = SOIL_load_image(filename.c_str(), &width, &height, 0, SOIL_LOAD_RGB);
    
    glBindTexture(GL_TEXTURE_2D, textureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    glGenerateMipmap(GL_TEXTURE_2D);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);
    SOIL_free_image_data(image);
    return textureID;
}

最后就是渲染代码


```cpp
// Std. Includes
#include <string>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

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

// GL includes
#include "Shader.h"
#include "Camera.h"
#include "Model.h"

// GLM Mathemtics
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// Other Libs
#include <SOIL.h>

// Properties
GLuint screenWidth = 800, screenHeight = 600;

// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement();

const GLuint WIDTH = 800, HEIGHT = 600;
// Camera
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
GLfloat yaw = -90.0f;	// Yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right (due to how Eular angles work) so we initially rotate a bit to the left.
GLfloat pitch = 0.0f;
GLfloat lastX = WIDTH / 2.0;
GLfloat lastY = HEIGHT / 2.0;
bool keys[1024];
bool firstMouse = true;

GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;

// The MAIN function, from here we start our application and run our Game loop
int main()
{
    // Init GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed
    glfwMakeContextCurrent(window);

    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);
    glfwSetCursorPosCallback(window, mouse_callback);
    glfwSetScrollCallback(window, scroll_callback);

    // Options
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    // Initialize GLEW to setup the OpenGL Function pointers
    glewExperimental = GL_TRUE;
    glewInit();

    // Define the viewport dimensions
    glViewport(0, 0, screenWidth, screenHeight);

    // Setup some OpenGL options
    glEnable(GL_DEPTH_TEST);

    // Setup and compile our shaders
    Shader shader("VertexShaderSource2_2_1.txt", "FragmentShaderSource2_2_1.txt");

    // Load models
    Model ourModel("nanosuit/nanosuit.obj");

    // Draw in wireframe
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // Game loop
    while (!glfwWindowShouldClose(window))
    {
        // Set frame time
        GLfloat currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // Check and call events
        glfwPollEvents();
        Do_Movement();

        // Clear the colorbuffer
        glClearColor(0.05f, 0.05f, 0.05f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shader.Use();   // <-- Don't forget this one!
        // Transformation matrices

        glm::mat4 view(1);
        glm::mat4 projection(1);

        view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
        projection = glm::perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);
        // Get the uniform locations

        glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
        glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));

        // Draw the loaded model
        glm::mat4 model(1);
        model = glm::translate(model, glm::vec3(0.0f, -1.75f, 0.0f)); // Translate it down a bit so it's at the center of the scene
        model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));	// It's a bit too big for our scene, so scale it down
        glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
        ourModel.Draw(shader);

        // Swap the buffers
        glfwSwapBuffers(window);
    }

    glfwTerminate();
    return 0;
}

#pragma region "User input"

// Moves/alters the camera positions based on user input
void Do_Movement()
{
    // Camera controls
    GLfloat cameraSpeed = 5.0f * deltaTime;
    if (keys[GLFW_KEY_W])
        cameraPos += cameraSpeed * cameraFront;
    if (keys[GLFW_KEY_S])
        cameraPos -= cameraSpeed * cameraFront;
    if (keys[GLFW_KEY_A])
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (keys[GLFW_KEY_D])
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);

    if (action == GLFW_PRESS)
        keys[key] = true;
    else if (action == GLFW_RELEASE)
        keys[key] = false;
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
    /*if (firstMouse)
{
    lastX = xpos;
    lastY = ypos;
    firstMouse = false;
}

GLfloat xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; // Reversed since y-coordinates go from bottom to left
lastX = xpos;
lastY = ypos;

GLfloat sensitivity = 0.05;	// Change this value to your liking
xoffset *= sensitivity;
yoffset *= sensitivity;

yaw += xoffset;
pitch += yoffset;

// Make sure that when pitch is out of bounds, screen doesn't get flipped
if (pitch > 89.0f)
    pitch = 89.0f;
if (pitch < -89.0f)
    pitch = -89.0f;

glm::vec3 front;
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
cameraFront = glm::normalize(front);*/
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{

}

#pragma endregion

顶点着色器代码

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;

out vec2 TexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
    TexCoords = texCoords;
}

片段着色器代码

#version 330 core

in vec2 TexCoords;

out vec4 color;

uniform sampler2D texture_diffuse1;

void main()
{    
    color = vec4(texture(texture_diffuse1, TexCoords));
}

参考链接:https://learnopengl-cn.readthedocs.io/zh/latest/03%20Model%20Loading/03%20Model/

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

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

相关文章

聊聊8万8的私董会,很扎心

聊聊8万8的私董会&#xff0c;很扎心 道几句真心话&#xff0c;很扎心&#xff0c;但也很现实。 如果你喜欢刷抖音&#xff0c;这种感觉应该会更加明显。 股市哀鸿遍野&#xff0c;实体一地鸡毛&#xff0c;我们办公室楼下的门面换了一波又一波。 别说那些不起眼的小生意&a…

第48章 抽离Axios拦截守及其全局变量定义

1 准备工作 1.1 重构src\store\index.js import { createStore } from vuex; export default createStore({ state: { //通过该全局变量&#xff0c;获取全局化存储的1个指定用户的令牌字符串。 token: localStorage.getItem(Token) ? localStorage.getItem(Token) : , //通…

CHAPTER 3 Web Server - httpd配置(二)

Web Server - httpd配置二3.1 httpd配置3.1.1 基于用户的访问控制3.1.2 basic认证配置示例&#xff1a;1. 添加用户2. 添加网页文件3. 定义安全域4. 修改父目录权限5. 访问效果6. 在配置文件中定义一个".htaccess"隐藏文件7. 添加组3.1.3 虚拟主机1. 构建方案2. 基于…

Storage

WebStorage主要提供了一种机制&#xff0c;可以让浏览器提供一种比cookie更直观的key、value存储方式&#xff1a; localStorage&#xff1a;本地存储&#xff0c;提供的是一种永久性的存储方法&#xff0c;在关闭掉网页重新打开时&#xff0c;存储的内容依然保留&#xff1b;…

TCP/IP网络协议族分成及其每层作用

1、可以分为应用层、传输层、网络层、链路层 2、各层的作用 应用层(可以想象成是快递打包过程) 决定了向用户提供应用服务时通信的活动&#xff0c;将要进行的操作或者数据进行一个打包。 传输层&#xff08;可以理解为选择顺丰、圆通等快递公司&#xff09; 提供数据传输的方…

从混沌到清晰,阿里全球商品类目域建设思考

作者&#xff1a;丁浩然 阿里全球化业务平台团队 商品是电商产品体系核心之一&#xff0c;类目则是商品模型核心之一&#xff0c;类目系统提供的基础业务数据贯穿了整个电商体系。本文将为大家分享商品类目域在全球化过程中的建设与思考。 众所周知&#xff0c;商品是电商产品体…

vue后台管理系统项目-table选择多行数据分页列表、一键全选重置功能

table选择多行数据 功能介绍&#xff1a; 1.列表分页功能&#xff1b; 2.一键全选&#xff0c;选中列表所有数据&#xff1b; 3.全选&#xff0c;选中当前页数据&#xff1b; 4.重置&#xff0c;清除选中状态&#xff1b; 5.列表搜索查询&#xff1b; 效果&#xff1a; 1.列表分…

剑指 Offer 28. 对称的二叉树

剑指 Offer 28. 对称的二叉树 难度&#xff1a;easy\color{Green}{easy}easy 题目描述 请实现一个函数&#xff0c;用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样&#xff0c;那么它是对称的。 例如&#xff0c;二叉树 [1,2,2,3,4,4,3] 是对称的。 但是下…

项目管理中,如何制定一个好的项目计划?

项目计划&#xff0c;是一个项目的起点。计划不清晰&#xff0c;执行力再强也只会让项目跑偏。 制定一个好的项目计划有哪些要点&#xff1a; 1、确定目标 项目目标是项目所要达到的期望结果&#xff0c;拥有明确的目标能够帮助我们做好规划&#xff0c;用有效的方式做正确…

一文带你看透前端世界里的日期时间,对就是Date

很高兴我们能够通过不同空间&#xff0c;不同时间&#xff0c;通过这篇博客相识&#xff0c;那一定是一种缘分&#xff0c;一种你和狗哥的缘分。今天我希望通过这篇博客对我所熟知的前端世界里的日期时间做一个汇总&#xff0c;不止是代码上的汇总哦&#xff01; 目录 一、时区…

​一致魔芋在北交所上市:市值突破11亿元,吴平夫妇为实控人​

2月21日&#xff0c;湖北一致魔芋生物科技股份有限公司&#xff08;下称“一致魔芋”&#xff0c;BJ:839273&#xff09;在北京证券交易所上市。本次上市&#xff0c;一致魔芋的发行价为11.38元/股&#xff0c;发行1350万股&#xff0c;募资总额约为1.54亿元。 本次发行后&…

【语音之家】AI产业沙龙—动手体验语音AI开发利器 - NVIDIA NeMo代码实战

由CCF语音对话与听觉专委会 、中国人工智能产业发展联盟&#xff08;AIIA&#xff09;评估组、NVIDIA、语音之家、希尔贝壳共同主办的【语音之家】AI产业沙龙—动手体验语音AI开发利器 - NVIDIA NeMo代码实战&#xff0c;将于2023年2月28日19:00-20:30线上直播&#xff0c;同时…

详解matplotlib的color配置

详解matplotlib的color配置 Matplotlib可识别的color格式 格式举例RGB或RGBA&#xff0c;由[0, 1]之间的浮点数组成的元组&#xff0c;分别代表红色、绿色、蓝色和透明度(0.1, 0.2, 0.5), (0.1, 0.2, 0.5, 0.3不区分大小写的十六进制RGB或RGBA字符串。‘#0f0f0f’, ‘#0f0f0f…

图像质量的评价指标【PSNR/SSIM/LIPIS/IE/NIE/Prepetual loss】

前言 做插帧这么久了&#xff0c;这几个指标还没系统的研究过&#xff0c;这次开一个博客写下这几个指标的区别 这里贴一个比较全的评价指标的库https://github.com/csbhr/OpenUtility/tree/c9cf713c99523c0a2e0be6c2afa988af751ad161 以以下两张图为例 预测图片 真实图片 …

el-form表单初始化赋值表单dataForm,,校验有问题,校验必填的也校验成功了

大家好啊,今天写表单发现我直接赋值对象 导致初始化校验必填校验成功以及validator校验有误的问题我的其企业名称 在初始化的时候 竟然都校验了 并且看起来像校验成功我在点击下一步的时候validator的时候&#xff0c;竟然也是校验成功&#xff0c;也不提示必填的错误最后检查我…

用 tensorflow.js 做了一个动漫分类的功能(一)

前言&#xff1a;浏览某乎网站时发现了一个分享各种图片的博主&#xff0c;于是我顺手就保存了一些。但是一张一张的保存实在太麻烦了&#xff0c;于是我就想要某虫的手段来处理。这样保存的确是很快&#xff0c;但是他不识图片内容&#xff0c;最近又看了 mobileNet 的预训练模…

【Kafka】三.Kafka怎么保证高可用 学习总结

Kafka 的副本机制 Kafka 的高可用实现主要依赖副本机制。 Broker 和 Partition 的关系 在分析副本机制之前&#xff0c;先来看一下 Broker 和 Partition 之间的关系。Broker 在英文中是代理、经纪人的意思&#xff0c;对应到 Kafka 集群中&#xff0c;是一个 Kafka 服务器节…

Blazor入门100天 : 身份验证和授权 (4) - 自定义字段

目录 建立默认带身份验证 Blazor 程序角色/组件/特性/过程逻辑DB 改 Sqlite将自定义字段添加到用户表脚手架拉取IDS文件,本地化资源freesql 生成实体类,freesql 管理ids数据表初始化 Roles,freesql 外键 > 导航属性完善 freesql 和 bb 特性 本节源码 https://github.com/…

数据备份学习笔记2

Linux实现本地备份的命令&#xff1a; mkdir -p /root/backup/date "%Y-%m-%d" tar -zcvPf /root/backup/date "%Y-%m-%d"/test20230221.tar.gz /root/test20230221/ 我们再看下tar命令选项&#xff1a; tar -czvf txt3.tar.gz txt3 tar -xvf txt4.tar.g…

二叉查找树(C++)

背景&#xff1a; 最近我要学习二叉平衡树了&#xff0c;在学习二叉平衡树之前&#xff0c;我需要学会二叉搜索树&#xff0c;因为二叉平衡树就是根据二叉搜索树的思想进行优化的。 二叉查找树简介&#xff1a; 二叉查找树是什么呢&#xff1f;&#xff08;也叫二叉搜索树&…