【记一次帮宝实现基于vs2017和openmesh的OpenGL作业】

OpenGL

记录一次OpenGL作业

下载visual studio

我这边下载的是2017版本,经过测试更新的版本也可行

下载依赖对应的库

openmesh

openmesh
官网描述只支持2015和2017版本的vs,小伙伴们下载的时候要注意对应,但是我使用2017版本的openmesh在vs2022上也能使用,如果怕出错还是下载对应的vs吧。

freeglut

freeglut
freeglut需要自己编译,需要下载cmake里找到cmake-3.22.1-windows-x86_64.msi然后下载安装,如果已经装过cmake请忽略
1.打开cmake,并将source code指向你下载的freeglut路径 然后在路径下建一个build,这就是待会编译完的东西生成的地方
2. FREEGLUT_BUILD_SHARED_LIBS、FREEGLUT_BUILD_STATIC_LIBS:分别为共享动态库项目和静态库项目这里都选择。
3. 点击Configure(配置),再点击Generate(生成)。
cmake截图
4.生成sln文件用vs打开编译,编译的时候要选择x64和release(重要)

配置依赖的第三方库路径和库路径

项目配置:
打开vs的最上面的项目,选择最后一个属性进行配置
a. 项目属性 ----> C/C++ —> 包含目录 —> 你的openmesh和freeglut的.h文件的路径,一般是工程文件下的include里,多个路径之间用英文的分号间隔开
b. 项目属性 ----> C/C++ —> 库目录 —> 你的openmesh和freeglut的.lib文件的路径,注意,一定要指向64位的lib文件,指向32位的会出问题
c. 项目属性 ----> 链接器 —> 输入 —> 附加依赖项 —> freeglutd.lib
openmesh有四个lib文件,比如OpenMeshCored.lib,都加上
d. freeglutd.dll 库文件放到系统的C:\Windows\System32下,如果还报dll找不到,你去freeglut和openmesh的目录下找对应的dll文件(注意一定要是64位的),放到系统目录下
e. 项目属性 ----> C/C++ —> 预处理器 —> 添加附加宏_USE_MATH_DEFINES

测试代码

此段代码是引用网络上大神的,侵删
注意,有些头文件的路径是我机器上的,如果使用这块代码请指向你的目录

#include <iostream>
#include<stdlib.h>
#include<OpenMesh/Core/IO/MeshIO.hh>
#include<OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include<C:\Users\89280\Downloads\freeglut-3.2.1\include\GL\glut.h>
#include <math.h>
#include <Windows.h>
#include <string>
#define  GLUT_WHEEL_UP 3           //定义滚轮操作
#define  GLUT_WHEEL_DOWN 4
using namespace std;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;

//鼠标交互有关的
int mousetate = 0; //鼠标当前的状态
GLfloat Oldx = 0.0; // 点击之前的位置
GLfloat Oldy = 0.0;
GLuint texture;
//与实现角度大小相关的参数,只需要两个就可以完成
float xRotate = 0.0f;   //旋转
float yRotate = 0.0f;
float ty = 0.0f;
float tx = 0.0f;
float scale = 0.004;

//文件读取有关的
MyMesh mesh;  //mesh把文件读取了,封装在mesh对象中
//"dinosaur.obj";
const string  file = "E:\\lab\\objdata\\";
const string file_1 = file + "cow.obj";
const string file_2 = file + "bunny.obj";
const string file_3 = file + "dinosaur.obj";
const string file_4 = file + "mba1.obj";
const string file_5 = file + "monkey.obj";
const string file_6 = file + "porsche.obj";
//const string file_7 = "teddy.obj";
const string file_7 = file + "huangfeng.obj";
const string file_8 = file + "file.obj";
const string file_9 = file + "face.sur";
int currentfile = 1;

GLuint showFaceList, showWireList;
int showstate = 1;
bool showFace = true;
bool showWire = false;
bool showFlatlines = false;



void setLightRes() {
    //GLfloat lightPosition[] = { 0.0f, 0.0f, 1.0f, 0.0f };
    GLfloat lightPosition[] = { 0.0f, 1.0f, 0.0f, 0.0f }; // 平行光源, GL_POSITION属性的最后一个参数为0


    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
    glEnable(GL_LIGHTING); //启用光源
    glEnable(GL_LIGHT0);   //使用指定灯光
}
void SetupRC()
{
    //当你想剔除背面的时候,你只需要调用glEnable(GL_CULL_FACE)就可以了,OPENGL状态机会自动按照默认值进行CULL_FACE,
    //默认是glFrontFace(GL_CCW)  GL_CCW逆时针为正,GL_CW顺时针
    glEnable(GL_DEPTH_TEST);
    glFrontFace(GL_CCW);
    glEnable(GL_CULL_FACE);
    // 启用光照计算
    glEnable(GL_LIGHTING);
    // 指定环境光强度(RGBA)  此时可以控制模型的显示颜色
    GLfloat ambientLight[] = { 1.0f, 0.0f, 0.0f, 0.0f };
    // 设置光照模型,将ambientLight所指定的RGBA强度值应用到环境光
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
    // 启用颜色追踪
    //GL_COLOR_MATERIAL使我们可以用颜色来贴物体。如果没有这行代码,纹理将始终保持原来的颜色,glColor3f(r,g,b)就没有用了
    glEnable(GL_COLOR_MATERIAL);
    // 设置多边形正面的环境光和散射光材料属性,追踪glColor
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    //glClearColor(0.0f, 0.0f, 0.5f, 1.0f);
    //GL_AMBIENT表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度(颜色)。
    //GL_DIFFUSE表示光线照射到该材质上,经过漫反射后形成的光线强度(颜色)。
    //GL_SPECULAR表示光线照射到该材质上,经过镜面反射后形成的光线强度(颜色)。
    //通常,GL_AMBIENT和GL_DIFFUSE都取相同的值,可以达到比较真实的效果。
    //使用GL_AMBIENT_AND_DIFFUSE可以同时设置GL_AMBIENT和GL_DIFFUSE属性。
}

//初始化顶点和面   
void initGL()
{
    //实用显示列表
    glClearColor(0.0, 0.0, 0.0, 0.0);

    //glClearDepth, 它给深度缓冲指定了一个初始值,缓冲中的每个像素的深度值都是这个, 
    //比如1,这个时候你往里面画一个物体, 由于物体的每个像素的深度值都小于等于1, 
    //所以整个物体都被显示了出来。 如果初始值指定为0, 物体的每个像素的深度值都大于等于0,
    //所以整个物体都不可见。 如果初始值指定为0.5, 那么物体就只有深度小于0.5的那部分才是可见的
    glClearDepth(2.0);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST); //用来开启深度缓冲区的功能,启动后OPengl就可以跟踪Z轴上的像素,那么它只有在前面没有东西的情况下才会绘制这个像素,在绘制3d时,最好启用,视觉效果会比较真实
    //glEnable(GL_TEXTURE_2D);
        // ------------------- Lighting  
    //glEnable(GL_LIGHTING); // 如果enbale那么就使用当前的光照参数去推导顶点的颜色
    //glEnable(GL_LIGHT0); //第一个光源,而GL_LIGHT1表示第二个光源
                     // ------------------- Display List  
    setLightRes();//启用指定光源
    SetupRC();//设置环境光
    showFaceList = glGenLists(1);//创建分配一个显示列表
    showWireList = glGenLists(1);
    //int temp = mesh.n_edges();

    //下面都是绘制编译  等待 callList调用显示列表来进行绘制显示
    // 绘制 wire 
    glNewList(showWireList, GL_COMPILE);
    glDisable(GL_LIGHTING);
    glLineWidth(1.0f);
    glColor3f(0.5f, 0.5f, 0.5f);//灰色
    glBegin(GL_LINES);
    //边线三维图绘制
    for (MyMesh::HalfedgeIter he_it = mesh.halfedges_begin(); he_it != mesh.halfedges_end(); ++he_it) {
        //链接这个有向边的起点和终点
        glVertex3fv(mesh.point(mesh.from_vertex_handle(*he_it)).data());
        glVertex3fv(mesh.point(mesh.to_vertex_handle(*he_it)).data());
    }
    glEnd();
    glEnable(GL_LIGHTING);
    glEndList();

    // 绘制flat
    glNewList(showFaceList, GL_COMPILE);
    //三角面图绘制
    for (MyMesh::FaceIter f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
        glBegin(GL_TRIANGLES);
        for (MyMesh::FaceVertexIter fv_it = mesh.fv_iter(*f_it); fv_it.is_valid(); ++fv_it) {
            glNormal3fv(mesh.normal(*fv_it).data());  //为每个顶点都指定法线向量,使得成像更立体
            glVertex3fv(mesh.point(*fv_it).data());
        }
        glEnd();
    }
    glEndList();
}




// 当窗体改变大小的时候,改变窗口大小时保持图形比例
void myReshape(GLint w, GLint h)
{
    glViewport(0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h));//跨平台进行强制类型转换 在c++下无需转换
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w > h)
        glOrtho(-static_cast<GLdouble>(w) / h, static_cast<GLdouble>(w) / h, -1.0, 1.0, -100.0, 100.0);
    else
        glOrtho(-1.0, 1.0, -static_cast<GLdouble>(h) / w, static_cast<GLdouble>(h) / w, -100.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


// 读取文件的函数
void readfile(string file) {
    // 请求顶点法线 vertex normals
    mesh.request_vertex_normals();
    //如果不存在顶点法线,则报错 
    if (!mesh.has_vertex_normals())
    {
        cout << "错误:标准定点属性 “法线”不存在" << endl;
        return;
    }
    // 如果有顶点法线则读取文件,读入到mesh对象中
    OpenMesh::IO::Options opt;
    if (!OpenMesh::IO::read_mesh(mesh, file, opt))
    {
        cout << "无法读取文件:" << file << endl;
        return;
    }
    else cout << "成功读取文件:" << file << endl;
    cout << endl; // 为了ui显示好看一些
    //obj文件中有的有法线有的没有 没有的话我们计算面法线来替代
                  //如果不存在顶点法线,则计算出
    if (!opt.check(OpenMesh::IO::Options::VertexNormal))
    {
        // 通过面法线计算顶点法线
        mesh.request_face_normals();
        // mesh计算出顶点法线
        mesh.update_normals();
        // 释放面法线
        mesh.release_face_normals();
    }
}

//  键盘交互 1. 切换文件 2.切换显示
void mySpecial(int key, int x, int y) {
    switch (key) {
    case GLUT_KEY_F1:
        cout << "读取文件:" << file_1 << " 中......" << endl;
        readfile(file_1);
        scale = 0.004;
        currentfile = 1;
        initGL();
        break;
    case GLUT_KEY_F2:
        cout << "读取文件:" << file_2 << " 中......" << endl;
        readfile(file_2);
        scale = 0.003;
        currentfile = 2;
        initGL();
        break;
    case GLUT_KEY_F3:
        cout << "读取文件:" << file_3 << " 中......" << endl;
        readfile(file_3);
        scale = 0.02;
        currentfile = 3;
        initGL();
        break;
    case GLUT_KEY_F4:
        cout << "读取文件:" << file_4 << " 中......" << endl;
        readfile(file_4);
        scale = 0.005;
        currentfile = 3;
        initGL();
        break;
    case GLUT_KEY_F5:
        cout << "读取文件:" << file_5 << " 中......" << endl;
        readfile(file_5);
        scale = 0.5;
        currentfile = 5;
        initGL();
        break;
    case GLUT_KEY_F6:
        cout << "读取文件:" << file_6 << " 中......" << endl;
        readfile(file_6);
        scale = 0.02;
        currentfile = 3;
        initGL();
        break;
    case GLUT_KEY_F7:
        cout << "读取文件:" << file_7 << " 中......" << endl;
        readfile(file_7);
        scale = 0.04;
        currentfile = 3;
        initGL();
        break;
    case GLUT_KEY_F8:
        cout << "读取文件:" << file_8 << " 中......" << endl;
        readfile(file_8);
        scale = 0.04;
        currentfile = 3;
        initGL();
        break;
    case GLUT_KEY_F9:
        cout << "读取文件:" << file_9 << " 中......" << endl;
        readfile(file_9);
        scale = 0.04;
        currentfile = 3;
        initGL();
        break;
    case GLUT_KEY_INSERT:
        if (showFace == true) {
            showFace = false;
            showWire = true;

            cout << "切换显示模式为:WireFrame" << endl;
        }
        else if (showWire == true)
        {
            showWire = false;
            showFlatlines = true;
            cout << "切换显示模式为:Flatlines" << endl;
        }
        else if (showFlatlines == true) {
            showFlatlines = false;
            showFace = true;
            //DisplaySphere(0.5, "G:\\source\\OpenGL\\Cow\\checkerboard3.bmp");
            cout << "切换显示模式为:Flat" << endl;
        }
        break;
    case GLUT_KEY_LEFT:
        tx -= 0.01;
        break;
    case GLUT_KEY_RIGHT:
        tx += 0.01;
        break;
    case GLUT_KEY_UP:
        ty += 0.01;
        break;
    case GLUT_KEY_DOWN:
        ty -= 0.01;
        break;
    default:
        break;
    }
    glutPostRedisplay();
}

// 鼠标交互
void myMouse(int button, int state, int x, int y)
{    //鼠标左键按下或者松开
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
        mousetate = 1;
        Oldx = x;
        Oldy = y;
    }
    if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
        mousetate = 0;
    //滚轮事件
    //scale 增加就是放大 减小就是缩小
    //currentfile 对不同的模型用不用的scale
    if (state == GLUT_UP && button == GLUT_WHEEL_UP) {
        //cout << "hello" << endl; 
        //滑轮向上滑,则scale减小
        if (currentfile == 1)
            scale += 0.0005;
        if (currentfile == 2)
            scale += 0.001;
        if (currentfile == 5) {
            scale += 0.1;
        }
        else
            scale += 0.001;
    }
    if (state == GLUT_UP && button == GLUT_WHEEL_DOWN) {
        //cout << "good" << endl;
        //滑轮向下滑,则scale增加
        if (currentfile == 1)
            scale -= 0.0005;
        if (currentfile == 2)
            scale -= 0.001;
        if (currentfile == 5) {
            scale -= 0.1;
        }
        else
            scale -= 0.001;
    }
    glutPostRedisplay();//促使主程序尽快的重绘窗口
}

// 鼠标运动时
void onMouseMove(int x, int y) {
    //当鼠标状态为按下时进入后续判断
    if (mousetate) {
        //x对应y是因为对应的是法向量
        yRotate += x - Oldx;
        glutPostRedisplay();//标记当前窗口需要重新绘制
        Oldx = x;
        xRotate += y - Oldy;
        glutPostRedisplay();
        Oldy = y;
    }
}

void myDisplay()
{
    //要清除之前的深度缓存
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    //与显示相关的函数
    glRotatef(xRotate, 1.0f, 0.0f, 0.0f); // 让物体旋转的函数 第一个参数是角度大小,后面的参数是旋转的法向量
    glRotatef(yRotate, 0.0f, 1.0f, 0.0f);
    //glTranslatef(0.0f, 0.0f, ty);
    glTranslatef(tx, ty, 0);        //移动
    glScalef(scale, scale, scale); // 缩放 x,y,z分别乘以scale

                                   //每次display都要使用glcalllist回调函数显示想显示的顶点列表
    //用键盘的insert按键控制显示的模式  网格,面,网格面 分别显示
    if (showFace)
        glCallList(showFaceList);
    if (showFlatlines) {
        glCallList(showFaceList);
        glCallList(showWireList);
    }
    if (showWire)
        glCallList(showWireList);

    glutSwapBuffers(); //这是Opengl中用于实现双缓存技术的一个重要函数
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); // GLUT_Double 表示使用双缓存而非单缓存
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(800, 500);
    glutCreateWindow("Mesh Viewer");
    //一开始默认读取文件1
    //readfile(file_1);
    //initGL();
    glutMouseFunc(myMouse);        //鼠标点击处理函数
    glutMotionFunc(onMouseMove); // 鼠标移动的时候的函数
    glutSpecialFunc(&mySpecial);//键盘上下左右响应
    glutReshapeFunc(&myReshape);//自适应窗口大小的改变 使得模型不会太宽 或者太高 若要精确显示模型不建议此操作
    glutDisplayFunc(&myDisplay);

    glutMainLoop();
    return 0;
}

报错

如果报一些说外部符号的错误,一般就是你使用的freeglut的lib和openmesh的lib和你编译测试代码的时候,没有选择x64和release模式,这些一定要一致,如果你实在没办法,看看网络上有没有别人编译好的64位的freeglut和openmesh的64位的lib,你下载下来,然后你引用这些lib,并在编译测试代码的时候选择x64,这样一定能成功的。

有问题联系

qq:892809577

引用代码和截图

截图https://blog.youkuaiyun.com/u012278016/article/details/105576381
代码暂时忘记出处了,如果大佬发现了,请联系我,我删除或者加上引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值