本文首发于:Vega Prime入门教程12.02:基本开发流程
Vega Prime的API通过模板和继承性的使用使得仿真循环更加简洁而有效,基于STL(标准模板库)和C++
的API显得非常紧凑和灵活。
实时控制包括定义ACF、配置ACF和系统、运行仿真循环以及最后退出仿真循环。
vp::initialize执行如下任务:
需要注意的是:在自己开发的应用中,ACF中的模块不需要初始化。
初始化实例:
vpModule::initializeModule(modulename);
vpModule::initializeModule是告诉你如何初始化你的应用中所添加的模块。初始化所添加模块和用户定制模块需要使用以下句法:
//初始化所有模块
vpModule::initializeModule( "vp" );
vpModule::initializeModule( "vpEnv" );
vpModule::initializeModule( "vpMotion" );
vpModule::initializeModule( "vpLADBM" );
vpModule::initializeModule( "vpFx" );
vpModule::initializeModule( "vpIR" );
vpApp 类用来定义一个典型的VP应用的框架。它的定义在 vpApp.h
中。所有子方法(member methods)都被内嵌了。使用者可以复制和修改 vpApp 类 。
vpApp的主体封装了VP应用中经常用到的vpKernel的功能。vpApp类控制实时功能(包括定义ACF、配置仿真类、仿真循环、更新和退出)。
例子:
// create a vpApp instance
vpApp *app = new vpApp;
从vpApp 类创建一个新类,这是开始的最简单的方法。如果你对C++
很熟悉,你就会明白你现在可以轻松运用vpApp 类了 。
vpApp 类的所有成员都可以多次定制以满足你自己的应用的需求 。
用户可以通过vpApp 类来创建自己的类 。
实例(源于vpApp 的用户定义类 ):
//通过公用 vpApp 定制的自定义类
class myApp:public vpApp
{
public:
myApp() {}; // constructor
~myApp() {}; // destructor
//其它方法
void printMessage(); //prints a message into the console window
/*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~
Method―― 键盘输入
这种方法在vpApp 类中定义
用户可以不考虑这种方法来重新定义键盘输入
默认的键盘采取操作应答,除非你采取自己的命令
所支持/定义的键盘命令如下 :
Esc 键 : //退出应用
TILDE 键 : //切换帧速显示
Backspace 键 : //重置观察者状态矢量
Enter 键 : //重新捕捉观察者状态矢量
c 键 : //将观察者置于屏幕中心点
f 键 : //切换雾的开 /关
l 键 : //切换灯光效果的开 /关
p 键 : //输出观察者绝对位置
t 键 : //切换纹理显示开 /关
T 键 : //切换透明度开 /关
w 键 : //切换线框开 /关
x 键 : //切换运动模式开 /关
~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*/
virtual void onKeyInput(vrWindow::Key key, int mod)
{
switch (key)
{
//按 “ P” 键时 , 打印信息
case vrWindow::KEY_P:
printMessage();
break;
default:
//按 vpApp 定义的执行
vpApp::onKeyInput(key, mod);
break;
}//switch(key)结束
}//无效的 onKeyInput 定制结束
private:
//自定义变量和成员到这里 !
}; //myApp 类定义结束
本例里,当按下大写字母“P”键时,打印出一个信息,从而onKeyInput方法无效。当你在预先定义无效的onKeyInput里定义好默认功能键时,这些键也会失效。
类实例可通过代码创建或通过传递ACF文件给vpKernel::define方法(或vpApp::define,若vpApp已经使用)。ACF文件中的类实例将在VP解析文件时自动创建。
定义语句可以替代ACF执行功能。参数就是用字符串来替代ACF。与以往的Vega不同的是,在VP中,你可以多次定制并且实时调用多个ACF。这个功能顶替
了Vega 的vgScan函数。
//调入 ACF 文件
//假定 argv[1]就是当前的 ACF 文件
if (argv[1])
app->define(argv[1]);
函数定义
define(const char*)
virtual int vpApp::define(const char *filename);
配置从ACF中分解而来,同时将不同的类关联起来。例如,它将系统中定义的pipeline添加给服务管理器,并且为每个类配置相关的联系。configure功能是相互的,通过unconfigure可以将应用配置返回到configure前的状态。configure方法经常被用户反复运用。
//configure my app
app->configure();
仿真循环包括一个函数调用:
void vpApp:run();
run()执行主要的仿真循环。这个功能会持续调用beginFrame(),接下来是endFrame()用来结束循环,当然还可以在循环过程中用breakFrameLoop()来结束循环。接着这项功能会调用unconfigure()
这种方法也经常被用户反复运用于自己定义的应用中。
更新kernel发生在主循环的中间:
vpKernel::update()
这种方法在主循环的中间通过应用来调用。否则它会被vpKernel::endFrame()自动调用,这个过程发生在pKernel::processNonLatencyCritical信息传递给 kernel之前,发生在仿真循环的non-latency-critical 阶段 。
关于帧的准确位置有几点说明。所有仿真对象都由应用程序来定位,要么是通过使用vsTraversalUpdate来自动更新,要么是通过代码来手动更新。因此,应用程序的仿真更新部分大概分为三部分:
依赖于vsTraversalLocate 或者直接获取信息(如vsTransform)的位置查询是保持不变的,它们并不修改或更新场景。因此,通常来说位置查询可能产生不同的结果,这要看位置查询是在场景更新前还是更新后。如果在更新前执行,结果就会和预期的不同;如果在更新后执行,结果就会和预期的一致。因此,建议所有的位置查询都在仿真更新后执行。
vp::shutdown();
vp::shutdown执行如下任务:
#include
int main(int argc, char *argy[])//初始化VP
{
vp::initialize(argc, argv);//创建vpApp实例
vpApp *app = new vpApp;//载入acf文件
if(argc<=1)
app->define("vp_simple.acf");
else
app->define(argy[1]);
//配置应用
app->configure();
//帧循环
app->run();
//取消引用
app->unref();
//关闭,退出VP
vp::shutdown();
return 0;
}
编译运行效果:
同时会提示内存情况
vuAllocTracer Report
Allocator | Leaked Memory (bytes)
------------------------------------------
vuAllocRaw | 0
vuAllocRefBase | 0
vuAllocAligned | 0
vuAllocFrameData | 0
************************************************
* Total leak is: 0 bytes in 0 blocks *
************************************************
在源码目录中会生成可执行文件,可以部署至其他PC中
编译结果文件
C:\Presagis\Suite18\Vega_Prime\resources\samples\vegaprime\vp\vp_simple
中