CHAI3D的学习
-
一、CHAI3D 的一些介绍
CHAI3D 是一个C++库,它本身就是一个C++项目,官网里有它详细的英文介绍CHAI3D官网,这里关于它的特点不做赘述。这里只是用直白的语言来帮助刚接触CAHI3D的人更快的了解,CHIA3D项目里面包含了18个模块(就是文件),
每个模块里的包含一些.h和.cpp文件,上面封装了一个个类。最新的3.2.0版本将所有的相关类都放到名为chai3d 的命名域,格式如下:
using namespace std; namespace chai3d { cAudioBuffer::cAudioBuffer() { public:... } }
CHAI3D还包含了GEL(形变模型),BULLET(刚体模型),ODE(也是刚体模型),OCULUS(Oculus Rift头戴式显示器)四个第三方模块,也是对CHAI3D基本项目的补充。
CHAI3D的配置非常简单,不用配置环境变量,主要是在新建项目的配置的链接器的附加依赖项里添加chai3d.lib,OpenGL32.lib,glu32.lib,glfw.lib四个静态链接库,并在附加库目录里添加对应的相对路径,如果添加第三方模块,也要添加相应的lib文件。
当然,你也可以不用新建项目配置,直接在下载的例程上编写就好。
官方提供的3.2.0版本的CHAI3D文件解压后如下图所示,
直接打开sln文件,
在CAHI3D文件加下有31个例程,GEL文件夹下有三个例程,BULLET,OCULUS,ODE文件夹下有7个例程,每个例程已经提前配置好了,直接可以运行,同时可以通过研究这些例程来学习CHAI3D。在最下面还有一个EXTRA文件夹,里面是窗口管理的第三方库GLFW,窗口管理除了这个,CHAI3D中还有freeglut,SDL2。
-
二、利用CAHI3D编写应用的一般结构
一个CAHI3D程序,一般包括几个模块(模块这个词当然是我说的,只是因为看着高大上而已,实质你明白就是编写几个函数,然后依次放到main函数里),那么首先说必须有的几个函数吧。
其一 初始化glfw库 ,就是调用glfw库(也可以是上面说的其他的库)创建窗口,这个每个例程里都一样,你直接拿过来用就可以了,注意设置一下窗口的一些参数就可以了。
-
其二 创建虚拟世界,说的好像很高大上, 不懂,来,简单点告诉你,就是实例化几个类指针。在上文所说的18个模块(不懂,往上看)里,有一个World模块,里面封装了一个cWorld类,还有盒子、球、圆柱等基元(就是最基础的)形状模型和网格模型。还有Camera模块和Lighting Properties模块,每个虚拟世界里都必须添加至少一个摄像头和一个灯光来渲染场景,当然,摄像头和灯光的有许多属性可以设置,下面只是简单添加:
// a world that contains all objects of the virtual environment cWorld* world; // create a new world. world = new cWorld(); // create a camera and insert it into the virtual world camera = new cCamera(world); world->addChild(camera); // create a directional light source light = new cDirectionalLight(world); // insert light source inside world world->addChild(light);
-
其三 连接设备,这里,也有一点讲究, 18个模块里有一个Device模块 封装了CAHI3D支持的所有设备的信息,还有一个Handler模块调用Device模块里的信息,接下来有两种方式操作它,一种直接连接设备,输入输出设备信息,另一种是通过一个代理工具(18个模块里有一个Haptic Tools模块),
// create a haptic device handler handler = new cHapticDeviceHandler(); // get a handle to the first haptic device handler->getDevice(hapticDevice, 0); //(1)直接连接设备 // open a connection to haptic device hapticDevice->open(); // calibrate device (if necessary) hapticDevice->calibrate(); //(2)通过tool工具连接,tool类直接内置了直接连接社别的程序 // a virtual tool representing the haptic device in the scene cToolCursor* tool; // create a 3D tool and add it to the world tool = new cToolCursor(world);
-
其四 创建物体,这一部分,其实可以算作创建虚拟世界里面,但是它又不是必须的, 没有它程序也可以运行,它又是最重要的,因为我们开发的时候就是在这块发挥所有的想象力。下面简单创建一个球体:
// create a sphere sphere = new cShapeSphere(0.01); // insert sphere inside world world->addChild(sphere);
-
其五 图像渲染,渲染摄像头看到的场景,先渲染后层,再渲染前层。很多时候,我们也在摄像头上添加一些文本,图像等,然后在这里设置位置大小,这样可以实时动态显示一些值或者图像。
// update position data labelHapticDevicePosition->setText(hapticDevicePosition.str(3)); // update haptic and graphic rate data labelRates->setText(cStr(freqCounterGraphics.getFrequency(), 0) + " Hz / " + cStr(freqCounterHaptics.getFrequency(), 0) + " Hz"); // update position of label labelRates->setLocalPos((int)(0.5 * (width - labelRates->getWidth())), 15); ///////////////////////////////////////////////////////////////////// // RENDER SCENE ///////////////////////////////////////////////////////////////////// // update shadow maps (if any) world->updateShadowMaps(false, mirroredDisplay); // render world camera->renderView(width, height); // wait until all OpenGL commands are completed glFinish(); // check for any OpenGL errors GLenum err; err = glGetError(); if (err != GL_NO_ERROR) cout << "Error: %s\n" << gluErrorString(err);
-
其六 触觉渲染,这一模块作为子进程,很重要的一部分,这里要与设备进行交互。如果是没有用tools工具的,需要自己写交互程序,反之,这块特别简单,tools工具早已内置了所有的算法和力的碰撞,它会自动计算你在创建物体模块里添加的所有力的属性。函数如下:
void updateHaptics(void) { // simulation in now running simulationRunning = true; simulationFinished = false; // main haptic simulation loop while(simulationRunning) { // compute global reference frames for each object world->computeGlobalPositions(true); // update position and orientation of tool tool->updateFromDevice(); // compute interaction forces tool->computeInteractionForces(); // send forces to haptic device tool->applyToDevice(); // signal frequency counter freqCounterHaptics.signal(1); } // exit haptics thread simulationFinished = true; }
-
其七 添加进程 ,当编写完图像渲染模块和触觉渲染模块后,需要把他们两个组合到一块,这里有一个System模块里的cThread类,将触觉触觉渲染模块添加到子进程,然后在一个循环里添加图像渲染模块,函数如下:
// create a thread which starts the main haptics rendering loop hapticsThread = new cThread(); hapticsThread->start(updateHaptics, CTHREAD_PRIORITY_HAPTICS); // setup callback when application exits atexit(close); //-------------------------------------------------------------------------- // MAIN GRAPHIC LOOP //-------------------------------------------------------------------------- // call window size callback at initialization windowSizeCallback(window, width, height); // main graphic loop while (!glfwWindowShouldClose(window)) { // get width and height of window glfwGetWindowSize(window, &width, &height); // render graphics updateGraphics(); // swap buffers glfwSwapBuffers(window); // process events glfwPollEvents(); // signal frequency counter freqCounterGraphics.signal(1); } // close window glfwDestroyWindow(window); // terminate GLFW library glfwTerminate();
其八 中断函数,基于GLFW的包括按键中断,鼠标中断,这个都是辅助功能,例程中都有模板,你可以直接在程序里面添加你想实现的功能,不多做介绍(懒得写了)。
最后,把这些模块放到main函数里面就可以了,一个CHAI3D程序就写好了,看着多,其实大部分都是模板上的,如果想自己实现又高又大又上的功能,那得在模板之外自己再琢磨琢磨,CHAI3D提供的各种类,各种功能函数已经足够多,老实说那些例程真的只是用了很少一部分,骚年们(我也是)想要真正学好学精,个人感觉要除了精通例程,还要举一反三,多转几下定义,开动小脑筋,一直添加功能(与君共勉)。
-
三、自定义类,实现多个界面转换
这个是我的毕设就是这么搞的,太烦了,不想写了,等下次想写的时候再说吧