计算机图形学 实验二 三维模型读取与控制
目录
一、实验内容
二、具体内容
(在实验2.3的基础上进行修改)
1、OFF格式三维模型文件的读取
2、三维模型的旋转动画
3、键盘鼠标的交互
4、模型的修改
三、代码
一、实验内容
- 读取实验提供的off格式三维模型,并对其赋色。利用鼠标和键盘的交互,控制动画效果,模型的颜色自己可以自行设置,好看就行。
二、具体内容
(在实验2.3的基础上进行修改)
1、OFF格式三维模型文件的读取
参考上机实验2.2的内容,完成对OFF格式三维模型文件的读取与显示,可改变物体的显示颜色,尽量特别,但不要太难看。
1)修改init()方法,读取OFF格式三维模型文件cow.off。
2)修改颜色:
在readoff()方法中:将坐标值([-1,1])映射到颜色值([0,1])
方法1:坐标值加1,除2(结果和实验给的类似)
方法2:坐标值取绝对值
(应该还不算难看)
2、三维模型的旋转动画
参考实验2.1中动画的生成方式,并结合实验2.3中对模型进行旋转变换的过程,生成旋转动画。
默认绕X轴旋转,每1000毫秒转一下rotateDelta角度。
定义相关变量:
在mian函数中定义相关操作:
3、键盘鼠标的交互
参考实验2.1中鼠标与键盘的交互,通过键盘设定选择绕x、y、z轴进行旋转,通过鼠标左右键控制动画的开始与暂停。
1)通过键盘设定选择绕x、y、z轴进行旋转:
在key_callback函数内增加增加如下代码,通过按“X”、“Y”、“Z”控制。
2)通过鼠标左右键控制动画的开始与暂停:
增加mouse_button_callback函数:
然后在main函数中绑定。
3)修改提示语:
4、模型的修改
参考以下代码,通过键盘设定可以在cow.off和cube.off之间切换。
清除顶点数组缓存:
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
二维向量:
std::vector<std::vector<?>>
其他STL相关代码可以查阅C++ STL 教程 | 菜鸟教程 (runoob.com)
1)添加变量表示绘制的是牛还是方块:
2)修改init()函数:通过判断currentModel选择读取的文件:
3)在key_callback函数中添加如下代码:
通过按下“N”绘制牛,按下“M”绘制方块。
4)并修改相关提示语。
效果如下:
三、代码
1、main.cpp
#include "Angel.h"
#include "TriMesh.h"
#include <vector>
#include <string>
//#include "main.h"
using namespace std;const int X_AXIS = 0;
const int Y_AXIS = 1;
const int Z_AXIS = 2;const int TRANSFORM_SCALE = 0;
const int TRANSFORM_ROTATE = 1;
const int TRANSFORM_TRANSLATE = 2;const double DELTA_DELTA = 0.3; // Delta的变化率
const double DEFAULT_DELTA = 0.5; // 默认的Delta值double scaleDelta = DEFAULT_DELTA;
double rotateDelta = DEFAULT_DELTA;
double translateDelta = DEFAULT_DELTA;glm::vec3 scaleTheta(1.0, 1.0, 1.0); // 缩放控制变量
glm::vec3 rotateTheta(0.0, 0.0, 0.0); // 旋转控制变量
glm::vec3 translateTheta(0.0, 0.0, 0.0); // 平移控制变量int currentTransform = TRANSFORM_ROTATE; // 设置当前变换
int mainWindow;//------------------------------------------------------------------------
bool isplaying = true; // 动画状态
int rotationAxis = X_AXIS; // 当前旋转轴,默认为 X 轴
int rotationTime = 1000; // 每1000帧旋转一次string currentModel ="cow";struct openGLObject
{// 顶点数组对象GLuint vao;// 顶点缓存对象GLuint vbo;// 着色器程序GLuint program;// 着色器文件std::string vshader;std::string fshader;// 着色器变量GLuint pLocation;GLuint cLocation;GLuint matrixLocation;GLuint darkLocation;
};openGLObject cube_object;TriMesh* cube = new TriMesh();void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}void bindObjectAndData(TriMesh* mesh, openGLObject& object, const std::string& vshader, const std::string& fshader) {// 创建顶点数组对象glGenVertexArrays(1, &object.vao); // 分配1个顶点数组对象glBindVertexArray(object.vao); // 绑定顶点数组对象// 创建并初始化顶点缓存对象glGenBuffers(1, &object.vbo);glBindBuffer(GL_ARRAY_BUFFER, object.vbo);glBufferData(GL_ARRAY_BUFFER,mesh->getPoints().size() * sizeof(glm::vec3) + mesh->getColors().size() * sizeof(glm::vec3),NULL,GL_STATIC_DRAW);// @TODO: Task3-修改完TriMesh.cpp的代码成后再打开下面注释,否则程序会报错glBufferSubData(GL_ARRAY_BUFFER, 0, mesh->getPoints().size() * sizeof(glm::vec3), &mesh->getPoints()[0]);glBufferSubData(GL_ARRAY_BUFFER, mesh->getPoints().size() * sizeof(glm::vec3), mesh->getColors().size() * sizeof(glm::vec3), &mesh->getColors()[0]);object.vshader = vshader;object.fshader = fshader;object.program = InitShader(object.vshader.c_str(), object.fshader.c_str());// 从顶点着色器中初始化顶点的位置object.pLocation = glGetAttribLocation(object.program, "vPosition");glEnableVertexAttribArray(object.pLocation);glVertexAttribPointer(object.pLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));// 从顶点着色器中初始化顶点的颜色object.cLocation = glGetAttribLocation(object.program, "vColor");glEnableVertexAttribArray(object.cLocation);glVertexAttribPointer(object.cLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(mesh->getPoints().size() * sizeof(glm::vec3)));// 获得矩阵存储位置object.matrixLocation = glGetUniformLocation(object.program, "matrix");}void init()
{std::string vshader, fshader;// 读取着色器文件路径vshader = "shaders/vshader.glsl";fshader = "shaders/fshader.glsl";//cube->generateCube();//cube->readOff("./Models/cow.off");if (currentModel == "cow") {cube->readOff("./Models/cow.off");}else {cube->generateCube();}bindObjectAndData(cube, cube_object, vshader, fshader);// 设置背景色为黑色glClearColor(0.0, 0.0, 0.0, 1.0);
}// 渲染函数
void display()
{// 清空颜色缓冲和深度缓冲glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glUseProgram(cube_object.program);glBindVertexArray(cube_object.vao);// 初始化变换矩阵 glm::mat4表示 4x4 矩阵glm::mat4 m(1.0, 0.0, 0.0, 0.0,0.0, 1.0, 0.0, 0.0,0.0, 0.0, 1.0, 0.0,0.0, 0.0, 0.0, 1.0);// @TODO: Task4-在此处修改函数,计算最终的变换矩阵// 调用函数传入三种变化的变化量,累加得到变化矩阵// 注意三种变化累加的顺序// 构建旋转矩阵glm::mat4 rotationMatrix = glm::rotate(glm::mat4(1.0), rotateTheta.x, glm::vec3(1.0, 0.0, 0.0))* glm::rotate(glm::mat4(1.0), rotateTheta.y, glm::vec3(0.0, 1.0, 0.0))* glm::rotate(glm::mat4(1.0), rotateTheta.z, glm::vec3(0.0, 0.0, 1.0));// 构建缩放矩阵glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0), glm::vec3(scaleTheta.x, scaleTheta.y, scaleTheta.z));// 构建平移矩阵glm::mat4 translateMatrix = glm::translate(glm::mat4(1.0), glm::vec3(translateTheta.x, translateTheta.y, translateTheta.z));// 按照平移、旋转、缩放的顺序相乘得到最终的变换矩阵m = translateMatrix * rotationMatrix * scaleMatrix;// 传递变换矩阵到着色器glUniformMatrix4fv(cube_object.matrixLocation, 1, GL_FALSE, glm::value_ptr(m));// 绘制立方体中的各个三角形glDrawArrays(GL_TRIANGLES, 0, cube->getPoints().size());
}// 通过Delta值更新Theta
// axis 表示坐标轴,sign 表示增加或减少
// currentTransform 表示当前变换类型
void updateTheta(int axis, int sign) {switch (currentTransform) {// 根据变换类型,增加或减少某种变换的变化量case TRANSFORM_SCALE://增加或减少缩放的 Theta 值scaleTheta[axis] += sign * scaleDelta;break;case TRANSFORM_ROTATE://增加或减少旋转的 Theta 值rotateTheta[axis] += sign * rotateDelta;break;case TRANSFORM_TRANSLATE://增加或减少平移的 Theta 值translateTheta[axis] += sign * translateDelta;break;}
}// 复原Theta和Delta
void resetTheta()
{scaleTheta = glm::vec3(1.0, 1.0, 1.0); //scaleTheta 表示缩放变换的角度rotateTheta = glm::vec3(0.0, 0.0, 0.0);translateTheta = glm::vec3(0.0, 0.0, 0.0);scaleDelta = DEFAULT_DELTA; //缩放变换的单位变化量rotateDelta = DEFAULT_DELTA;translateDelta = DEFAULT_DELTA;
}// 更新变化Delta值
void updateDelta(int sign)
{switch (currentTransform) {// 根据变化类型增加或减少每一次变化的单位变化量case TRANSFORM_SCALE:scaleDelta += sign * DELTA_DELTA;break;case TRANSFORM_ROTATE:rotateDelta += sign * DELTA_DELTA;break;case TRANSFORM_TRANSLATE:translateDelta += sign * DELTA_DELTA;break;}
}void cleanData();// 处理键盘输入的回调函数
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{switch (key){// 退出。case GLFW_KEY_ESCAPE:if (action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE);break;// 1:缩放模式case GLFW_KEY_1:if (action == GLFW_PRESS) currentTransform = TRANSFORM_SCALE;break;// 2: 旋转模式case GLFW_KEY_2:if (action == GLFW_PRESS) currentTransform = TRANSFORM_ROTATE;break;// 3: 移动模式case GLFW_KEY_3:if (action == GLFW_PRESS) currentTransform = TRANSFORM_TRANSLATE;break;// 4: 绘制线。case GLFW_KEY_4:if (action == GLFW_PRESS) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);break;// 5: 绘制面。case GLFW_KEY_5:if (action == GLFW_PRESS) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);break;// Q: 增加 x。case GLFW_KEY_Q:if (action == GLFW_PRESS || action == GLFW_REPEAT) updateTheta(X_AXIS, 1);break;// A: 减少 x。case GLFW_KEY_A:if (action == GLFW_PRESS || action == GLFW_REPEAT) updateTheta(X_AXIS, -1);break;// W: 增加 y。case GLFW_KEY_W:if (action == GLFW_PRESS || action == GLFW_REPEAT) updateTheta(Y_AXIS, 1);break;// S: 减少 y。case GLFW_KEY_S:if (action == GLFW_PRESS || action == GLFW_REPEAT) updateTheta(Y_AXIS, -1);break;// E: 增加 z。case GLFW_KEY_E:if (action == GLFW_PRESS || action == GLFW_REPEAT) updateTheta(Z_AXIS, 1);break;// D: 减少 z。case GLFW_KEY_D:if (action == GLFW_PRESS || action == GLFW_REPEAT) updateTheta(Z_AXIS, -1);break;// R: 增加变化量。case GLFW_KEY_R:if (action == GLFW_PRESS) updateDelta(1);break;// F: 减少变化量。case GLFW_KEY_F:if (action == GLFW_PRESS) updateDelta(-1);break;// T: 所有值重置。case GLFW_KEY_T:if (action == GLFW_PRESS) resetTheta();break;//-------------------------------------------------------------------// 选择绕 X 轴旋转case GLFW_KEY_X:if (action == GLFW_PRESS) rotationAxis = X_AXIS;break;// 选择绕 Y 轴旋转case GLFW_KEY_Y:if (action == GLFW_PRESS) rotationAxis = Y_AXIS;break;// 选择绕 Z 轴旋转case GLFW_KEY_Z:if (action == GLFW_PRESS) rotationAxis = Z_AXIS;break;// N: 加载cow.off模型case GLFW_KEY_N:if (action == GLFW_PRESS) {glBindVertexArray(0);//清除顶点数组缓存glBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);currentModel = "cow";init();}break;// M: 加载cube模型case GLFW_KEY_M:if (action == GLFW_PRESS) {glBindVertexArray(0);//清除顶点数组缓存glBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);currentModel = "cube";init();}break;}}//-------------------------------------------------------------------------------
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {isplaying = true; // 左键按下,开始动画}if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {isplaying = false; // 右键按下,暂停动画}
}// 输出帮助信息
void printHelp() {printf("%s\n\n", "3D Transfomations");printf("Keyboard options:\n");printf("n: Draw cow\n");printf("m: Draw block\n");printf("left mouse button: start playing\n");printf("right mouse button: Pause playback\n");printf("x: Rotate around the X-axis\n");printf("y: Rotate around the Y-axis\n");printf("z: Rotate around the Z-axis\n");printf("The following are the operations previously used:\n");printf("1: Transform Scale\n");printf("2: Transform Rotate\n");printf("3: Transform Translate\n");printf("q: Increase x\n");printf("a: Decrease x\n");printf("w: Increase y\n");printf("s: Decrease y\n");printf("e: Increase z\n");printf("d: Decrease z\n");printf("r: Increase delta of currently selected transform\n");printf("f: Decrease delta of currently selected transform\n");printf("t: Reset all transformations and deltas\n");
}// 清理数据
void cleanData() {cube->cleanData();// 释放内存delete cube;cube = NULL;// 删除绑定的对象glDeleteVertexArrays(1, &cube_object.vao);glDeleteBuffers(1, &cube_object.vbo);glDeleteProgram(cube_object.program);
}int main(int argc, char** argv)
{// 初始化GLFW库,必须是应用程序调用的第一个GLFW函数glfwInit();// 配置GLFWglfwWindowHint(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//设置字符格式#pragma execution_character_set("GBK");GLFWwindow* window = glfwCreateWindow(600, 600, "homework", NULL, NULL);if (window == NULL) {std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetKeyCallback(window, key_callback);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 调用任何OpenGL的函数之前初始化GLADif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}init();// 输出帮助信息printHelp();// 启用深度测试glEnable(GL_DEPTH_TEST);//------------------------------------------------------------------------glfwSetMouseButtonCallback(window, mouse_button_callback); // 设置鼠标回调int flag = clock();while (!glfwWindowShouldClose(window)){display();// 交换颜色缓冲 以及 检查有没有触发什么事件(比如键盘输入、鼠标移动等)glfwSwapBuffers(window);glfwPollEvents();//--------------------------------------------------------------------------------//处理动画int now = clock();if (isplaying) {// 每1000帧旋转一定的角度if ((now - flag) >= rotationTime) {if (rotationAxis == X_AXIS) {rotateTheta.x += rotateDelta; // 沿X轴旋转}else if (rotationAxis == Y_AXIS) {rotateTheta.y += rotateDelta; // 沿Y轴旋转}else if (rotationAxis == Z_AXIS) {rotateTheta.z += rotateDelta; // 沿Z轴旋转}flag = now;}}}cleanData();return 0;
}
2、TriMesh.cpp
#include "TriMesh.h"// 一些基础颜色
const glm::vec3 basic_colors[8] = {glm::vec3(1.0, 1.0, 1.0), // Whiteglm::vec3(1.0, 1.0, 0.0), // Yellowglm::vec3(0.0, 1.0, 0.0), // Greenglm::vec3(0.0, 1.0, 1.0), // Cyanglm::vec3(1.0, 0.0, 1.0), // Magentaglm::vec3(1.0, 0.0, 0.0), // Redglm::vec3(0.0, 0.0, 0.0), // Blackglm::vec3(0.0, 0.0, 1.0) // Blue
};// 立方体的各个点
const glm::vec3 cube_vertices[8] = {glm::vec3(-0.5, -0.5, -0.5),glm::vec3(0.5, -0.5, -0.5),glm::vec3(-0.5, 0.5, -0.5),glm::vec3(0.5, 0.5, -0.5),glm::vec3(-0.5, -0.5, 0.5),glm::vec3(0.5, -0.5, 0.5),glm::vec3(-0.5, 0.5, 0.5),glm::vec3(0.5, 0.5, 0.5)
};TriMesh::TriMesh()
{
}TriMesh::~TriMesh()
{
}std::vector<glm::vec3> TriMesh::getVertexPositions()
{return vertex_positions;
}std::vector<glm::vec3> TriMesh::getVertexColors()
{return vertex_colors;
}std::vector<vec3i> TriMesh::getFaces()
{return faces;
}std::vector<glm::vec3> TriMesh::getPoints()
{return points;
}std::vector<glm::vec3> TriMesh::getColors()
{return colors;
}void TriMesh::cleanData() {vertex_positions.clear();vertex_colors.clear();faces.clear();points.clear();colors.clear();glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}void TriMesh::storeFacesPoints() {// @TODO: Task-2修改此函数在points和colors容器中存储每个三角面片的各个点和颜色信息// 根据每个三角面片的顶点下标存储要传入GPU的数据// 清空points和colors容器 points.clear();colors.clear();// 遍历每个面 for (const auto& face : faces) {// 根据索引获取顶点的位置和颜色 unsigned int x = face.x;unsigned int y = face.y;unsigned int z = face.z;glm::vec3 pos1 = vertex_positions[x];glm::vec3 col1 = vertex_colors[x];glm::vec3 pos2 = vertex_positions[y];glm::vec3 col2 = vertex_colors[y];glm::vec3 pos3 = vertex_positions[z];glm::vec3 col3 = vertex_colors[z];// 将顶点位置和颜色添加到points和colors容器中 points.push_back(pos1);colors.push_back(col1);points.push_back(pos2);colors.push_back(col2);points.push_back(pos3);colors.push_back(col3);}}// 立方体生成12个三角形的顶点索引
void TriMesh::generateCube() {// 创建顶点前要先把那些vector清空cleanData();// @TODO: Task1-修改此函数,存储立方体的各个面信息// vertex_positions和vertex_colors先保存每个顶点的数据for (int i = 0; i < 8; ++i) {vertex_positions.push_back(cube_vertices[i]);// 这里简单使用基本颜色数组中的颜色,每个顶点按顺序分配颜色 vertex_colors.push_back(basic_colors[i % 8]);}// faces再记录每个面片上顶点的下标// 立方体12个面的顶点索引 // 每个面由两个三角形组成 faces.push_back(vec3i(1, 3, 7)); // 前面 faces.push_back(vec3i(1, 7, 5));faces.push_back(vec3i(0, 2, 6)); // 后面 faces.push_back(vec3i(0, 6, 4));faces.push_back(vec3i(2, 6, 7)); // 右面 faces.push_back(vec3i(2, 7, 3));faces.push_back(vec3i(0, 4, 5)); // 左面 faces.push_back(vec3i(0, 5, 1));faces.push_back(vec3i(4, 5, 7)); // 顶面 faces.push_back(vec3i(4, 7, 6));faces.push_back(vec3i(0, 1, 3)); // 底面 faces.push_back(vec3i(0, 3, 2));storeFacesPoints();
}void TriMesh::readOff(const std::string& filename)
{// fin打开文件读取文件信息if (filename.empty()){return;}std::ifstream fin;fin.open(filename);if (!fin){printf("File on error\n");return;}else{printf("File open success\n");cleanData();int nVertices, nFaces, nEdges;// 读取OFF字符串std::string str;fin >> str;// 读取文件中顶点数、面片数、边数fin >> nVertices >> nFaces >> nEdges;// 根据顶点数,循环读取每个顶点坐标for (int i = 0; i < nVertices; i++){glm::vec3 tmp_node;fin >> tmp_node.x >> tmp_node.y >> tmp_node.z;vertex_positions.push_back(tmp_node);//vertex_colors.push_back(tmp_node);// 将坐标值([-1,1])映射到颜色值([0,1])/*//方法1:加1,除2(结果和实验给的一样)glm::vec3 color = (tmp_node + glm::vec3(1.0f)) * 0.5f;*///方法2:取坐标绝对值float a = tmp_node.x>0? tmp_node.x:-tmp_node.x;float b = tmp_node.y>0? tmp_node.y:-tmp_node.y;float g = tmp_node.z>0? tmp_node.z:-tmp_node.z;glm::vec3 color(a,b,g);vertex_colors.push_back(color);}// 根据面片数,循环读取每个面片信息,并用构建的vec3i结构体保存for (int i = 0; i < nFaces; i++){int num, a, b, c;// num记录此面片由几个顶点构成,a、b、c为构成该面片顶点序号fin >> num >> a >> b >> c;faces.push_back(vec3i(a, b, c));}}fin.close();storeFacesPoints();
};
相关文章:

计算机图形学 实验二 三维模型读取与控制
目录 一、实验内容 二、具体内容 (在实验2.3的基础上进行修改) 1、OFF格式三维模型文件的读取 2、三维模型的旋转动画 3、键盘鼠标的交互 4、模型的修改 三、代码 一、实验内容 读取实验提供的off格式三维模型,并对其赋色。利用鼠标和键盘的交互࿰…...

NAT网络工作原理和NAT类型
NAT基本工作流程 通常情况下,某个局域网中,只有路由器的ip是公网的,局域网中的设备都是内网ip,内网ip不具备直接与外部应用通信的能力。 处于内网的设备如何借助NAT来实现访问外网的应用? 对于开启了NAT功能的局域网…...

wget命令之Tomcat(三)
引言 Tomcat是一个开源的Java Web应用服务器,实现了多个关键的Java EE规范,包括Servlet、JSP(JavaServer Pages)、JavaWebSocket等。由于Tomcat技术先进、性能稳定且免费,它成为了许多企业和开发者的首选Web应用服务器…...

IP地址修改器 5.0 重制版
IP地址修改器是一款由 kn007 大佬编写的一个小工具,可以帮助小白用户方便的进行IP地址,网卡MAC修改等等功能,工具支持多网卡,并且支持管理导入多份配置等。 程序主要原理还是利用了WMI的Win32_NetworkAdapter、Win32_NetworkAdap…...

vscode编译s32ds工程
基本可以参考下面的文章,但是需要注意的是添加完环境变量后需要重启一下vscode。我现在已经能顺利编译。感谢原创 阿隆汽车 MBD_杂谈_使用VSCode编译s32k_vscode s32k-CSDN博客 https://blog.csdn.net/ALongAuto/article/details/134961294...

大数据专业为什么要学习Hadoop课程
在当今信息爆炸的时代,大数据成为了影响各行各业的重要因素,而Hadoop作为大数据处理的核心技术之一,自然成为大数据专业学生需要掌握的一项重要技能。本文将详细探讨大数据专业为何要学习Hadoop课程,帮助读者理解其必要性和实际应…...

Xilinx FPGA的Vivado开发流程
Xilinx FPGA 的 Vivado 开发流程主要包括以下步骤: 创建工程: 启动 Vivado 软件:双击 Vivado 图标打开软件。新建工程向导:在 Quick Start 中选择 Create Project,打开新建工程向导。设置工程信息: 工程名称…...

音频模型介绍
在处理音频数据方面,有多种模型表现出色,它们在不同的音频处理任务上有着各自的优势: 自动编码器:包括多通道变分自动编码器、自回归模型和生成对抗网络等,这些模型在音乐生成领域取得了令人印象深刻的成果。 深度生成…...

《编写沪深两市实时交易数据接收程序全攻略》
《编写沪深两市实时交易数据接收程序全攻略》 一、引言二、获取股票数据的方法(一)使用爬虫框架(二)调用股票接口(三)使用免费数据 API(四)利用 Excel 的 power query 三、数据接口及…...

一文学会easyexcel导入数据,多sheet页、字典转换【附带源码】
文章目录 前言一、业务流程二、实现1、引入easyexcel、fastjson、lombok包2、创建Json工具类3、创建自定义字典转换注解4、创建字典转换实现类5、创建数据对象类6、创建多sheet页封装对象7、创建Excel导入工具类8、创建测试类 三、接口测试1、启用项目2、使用数据导出的文件&am…...

Spring中的 InitializingBean、BeanPostProcessor、@PostConstruct 等初始化动作的执行时机分析
初始化Bean的时序图如下: 小结说明: 1、相同点:InitializingBean 的(afterPropertiesSet方法)、BeanPostProcessor、PostConstruct 都是在bean的属性注入完毕之后才执行,都可以用来进行bean的初始化动作 2、初始化执行顺序优先级…...

如何利用指纹浏览器爬虫绕过Cloudflare的防护?
网络爬虫能够系统地浏览网页并提取所需的数据,通常被用于市场研究、数据分析或者竞争情报。然而,一些反爬虫机制给网络爬虫的工作带来了不少挑战和风险。 其中,Cloudflare提供了多层次的防护机制,包括IP封锁、速率限制、CAPTCHA验…...

idea 基础简单应用(java)
Java IDE(集成开发环境)的使用方法因不同的IDE而异,但通常都包含一些基本的操作和功能。以下以IntelliJ IDEA这一流行的Java IDE为例,介绍Java IDE的基本使用方法与指南: 一、下载与安装 请点击观看 idea免费安装步…...

windows环境下vscode下载安装
vscode官网 1.vscode官网:Visual Studio Code - Code Editing. Redefined 进入官网,点击下载 右键文件,以管理员方式运行,开始安装 第一步:同意此协议 第二步:更改安装位置,可以在d盘新建一个文件夹&…...

Obsidian之与Typora图片格式相互兼容
来源 [Obsidian之与Typora图片格式相互兼容 - 简书 (jianshu.com)](https://www.jianshu.com/p/303433fe82b9) 下载插件customer attachment location,并设置...

美半导体巨头正切断中国供应链,给自己“挖坑”?
美国对华半导体“脱钩断链”政策持续升级,近日开始对半导体产业链进行“去中化”。 据外媒《华尔街日报》11月5日报道,受美国政府最新指令指示,美国半导体巨头应用材料公司(Applied Materials)和泛林集团(L…...

RHCE---搭建lnmp云存储
一、恢复快照后,检查安全性(查看selinux 以及防火墙) 二、搭建LNMP环境 [rootserver ~]# yum -y install nginx mariadb-server php*三、上传软件 1、将nextcloud-25.0.1.zip压缩包传递到根目录下 2、解压缩nextcloud-25.0.1.zip …...

一些 uniapp相关bug
1.当input聚焦时布局未上移 <scroll-view style"height: calc(100vh - 100rpx - 38rpx)" :scroll-y"true"><wd-form ref"formRef" :model"fbObj">....<wd-inputlabel"联系方式"prop"contact"clear…...

操作系统-4.2文件系统的层次结构虚拟文件系统
文章目录 文件系统的层次结构物理格式化open系统调用打开文件的背后过程图中内容解释文件打开的详细步骤操作总结 虚拟文件系统1. **虚拟文件系统的作用**2. **虚拟文件系统的结构**3. **VFS 工作机制**4. **VFS 的优点** 文件系统的层次结构 用一个例子来辅助记忆文件系统的层…...

【深度学习】DreamClear:提升图片分辨率的模型
基于PixArt-XL-2模型,效果很好。 DreamClear:高容量真实世界图像修复与隐私安全数据集构建 在图像修复领域,处理真实世界中的低质量(Low-Quality, LQ)图像并恢复其高质量(High-Quality, HQ)版本一直是一个具有挑战性的任务。今天,我们将介绍一个最新的开源项目——Dr…...

操作系统进程互斥的四种软件实现和三种硬件实现
进程互斥是操作系统中保证多个进程不会同时访问共享资源的一种机制。 进程互斥的四种软件实现方式: 一、单标志法 核心思想:使用一个布尔变量(或称为标志位)来表示临界区的访问权限。该变量为true时表示允许某个进程访问临界区&…...

C++虚继承演示
在继承中如果出现: 这种情况,B和C都继承了A,D继承了B、C 在D中访问A的成员会出现: 这样的警告 是因为在继承时A出现两条分支:ABD、ACD 编译器不知道访问的A中的元素是经过B继承还是C继承 所以B、C在继承A时要用到…...

React Native的生命周期
React Native 组件的生命周期分为三个阶段:Mounting(挂载)、Updating(更新) 和 Unmounting(卸载)。每个阶段都会触发不同的生命周期方法。 下面是详细的生命周期解释,并通过一个项目…...

linux系统中涉及到用户管理的命令知识
用户创建与密码设置 Linux中新建用户使用useradd命令,只有root用户才能执行,若useradd命令直接输入不管用,可使用绝对路径/usr/sbin/useradd。设置用户登录密码使用passwd命令。 su命令相关 su代表switch user,用于切换用户。切换…...

LeetCode 0685.冗余连接 II:并查集(和I有何不同分析)——详细题解(附图)
【LetMeFly】685.冗余连接 II:并查集(和I有何不同分析)——详细题解(附图) 力扣题目链接:https://leetcode.cn/problems/redundant-connection-ii/ 在本问题中,有根树指满足以下条件的 有向 图。该树只有一个根节点&…...

Dubbo负载均衡
负载均衡策略与配置细节 Dubbo 内置了 client-based 负载均衡机制,如下是当前支持的负载均衡算法,结合上文提到的自动服务发现机制,消费端会自动使用 Weighted Random LoadBalance 加权随机负载均衡策略 选址调用。 如果要调整负载均衡算法…...

PymuPDF4llm提取pdf文件文字、表格与图片
一、PymuPDF4llm 的功能特点 (一)文本提取 简单易用 PymuPDF4llm 的文本提取功能非常简单易用。只需使用pip install pymupdf4llm进行安装,然后通过import pymupdf4llm导入库,就可以使用md_text pymupdf4llm.to_markdown("…...

20241108通过iperf3确认中科创达的高通CM6125的WIFI的网速【失败】
20241108通过iperf3确认中科创达的高通CM6125的WIFI的网速【失败】 2024/11/8 15:43 由于以太网不能用,那就测试一下WIFI,iperf3链接/测试异常。 一般认为可能的原因有: 1、CM6125开发板的WIFI不带天线,影响性能。 2、CM6125的And…...

Stored procedures in PostgreSQL
select 存储过程,在现了解的情况,还是没有mysql,sqlserver等好写好用。 --postgreSQL 11.0 以下版本 create or replace FUNCTION procInsertSchool (pSchoolId Char(5),pSchoolName VarChar(100),pSchoolTelNo VarChar(8) ) RETURNS void language plp…...

第10章 多表查询
一、什么是多表查询 多表查询,也称为关联查询,指两个或更多个表一起完成查询操作。 前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立…...