计算机图形学 实验二 三维模型读取与控制
目录
一、实验内容
二、具体内容
(在实验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…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
