|
2008年10月19日
我选择的是ubuntu8.04 + codeblocks8.02的开发环境。 Ogre用的是1.4.5的版本。 下面是用SDL进行的一个简单的代码.
#include <Ogre.h> #include <iostream> #include <SDL/SDL.h> #include <SDL/SDL_syswm.h> #include <SDL/SDL_events.h>
using namespace std; using namespace Ogre; class AppListener : public FrameListener { public: AppListener( RenderWindow *_win ) : win( _win ) { } public: bool frameStarted(const FrameEvent& evt) { if ( !FrameListener::frameStarted( evt ) ) return false;
SDL_PollEvent( &event ); return true; } bool frameEnded(const FrameEvent& evt) { if ( !FrameListener::frameEnded( evt ) ) return false;
SDL_PollEvent( &event ); if ( event.type == SDL_KEYDOWN ) { if ( event.key.keysym.sym == SDLK_ESCAPE ) return false; } return true; } private: RenderWindow *win; SDL_Event event; }; void parseWindowGeometry( Ogre::ConfigOptionMap& config, unsigned int& width, unsigned int& height, bool& fullscreen ); int main() { Root *root = new Root( "plugins.cfg" ); RenderWindow *win;
if ( !root->showConfigDialog() ) return 0; if ( SDL_WasInit( SDL_INIT_VIDEO ) == 0 ) { unsigned int height = 300, width = 400; bool fullscreen; parseWindowGeometry( root->getRenderSystem()->getConfigOptions(), width, height, fullscreen );
root->initialise( false );
SDL_Init( SDL_INIT_VIDEO ); SDL_SetVideoMode( width, height / 2, 0, 0 ); SDL_WM_SetCaption( "OgreTest", "ogretest" );
SDL_SysWMinfo info; SDL_VERSION(&info.version);
SDL_GetWMInfo(&info);
std::string dsp(&(DisplayString(info.info.x11.display)[1])); std::vector<Ogre::String> tokens = Ogre::StringUtil::split(dsp, ".");
Ogre::NameValuePairList misc; std::string s = Ogre::StringConverter::toString((long)info.info.x11.display); s += ":" + tokens[1] +":"; s += Ogre::StringConverter::toString((long)info.info.x11.window); misc["parentWindowHandle"] = s; win = root->createRenderWindow("ogre", width, height, fullscreen, &misc);
///we need to set the window to be active by ourselves, since GLX by default sets it to false, but then activates it upon recieving some X event (which it will never recieve since we'll use SDL). ///see OgreGLXWindow.cpp win->setActive(true); win->setAutoUpdated(true); } else { win = root->initialise( true ); }
root->addFrameListener( new AppListener( win ) ); root->startRendering(); return 0; }
void parseWindowGeometry( Ogre::ConfigOptionMap& config, unsigned int& width, unsigned int& height, bool& fullscreen ) { Ogre::ConfigOptionMap::iterator opt = config.find( "Video Mode" ); if ( opt != config.end() ) { Ogre::String val = opt->second.currentValue; Ogre::String::size_type pos = val.find( 'x' ); if ( pos != Ogre::String::npos ) { width = Ogre::StringConverter::parseUnsignedInt( val.substr( 0, pos ) ); height = Ogre::StringConverter::parseUnsignedInt( val.substr( pos + 1 ) ); }
opt = config.find( "Full Screen" ); if ( opt != config.end() ) { fullscreen = ( opt->second.currentValue == "Yes" ); } } }
原理很简单。 图:
2008年9月29日
摘要: FreeImage is an Open Source library project for developers who would like to support popular graphics image formats like PNG, BMP, JPEG, TIFF and others as needed by today's multimedia applications. F... 阅读全文
2008年9月28日
午夜时分,分外寂静,喧嚣争客源的场面在这时已叫停,真的很难打到车,更何况我这个带血的伤员? 我使劲地挥手给他们,他们走近看到我流血的手,连招呼都不招呼,利马走人,而你不一样,你不相信迷信。 你没有告诉我你的名字,甚至连姓都没有,因为血正流,你顾不及多说一句话。 将我带到了最近的医院挂了急诊,当我要付钱的时候,你却推辞了。然后连招呼没打就走了,这一切好像都是真的。我真的很难相信这个金钱的社会还会有这样的一位好人。我真的不知道怎么感谢,毕竟我穷学生一个。你挽救的不只是我的一只手,更多的是我的梦想,作为一个程序员要用我的手来创造未来。我现在不能给你物质方面的感谢,也不能为你做些什么。但是我真的发自内心希望你好人一生平安,全家幸福。我一直想办法去感谢您,今天我就通过blog吧。为你祈福!!!
2008年9月27日
OpenGL发展的历史: OpenGL的前身是SGI公司所开发的IRIS GL图形函数库,OpenGL不是一种编程语言,而是一个更像C运行时函数库。OpenGL是一个开放的工业标准,虽然它是由SGI首创,但它的标准不是控制在SGI手中,而是由OpenGL体系结构审核委员会(ARB)掌管。ARB是由SGC、DEC、IBM、Intel和Microsoft等著名公司于1992年创立,后来陆续加了nVidia、ATI等图形芯片领域的巨擎。ARB每4年开一次会,对OpenGL规范进行维护和改善,并出台计划对OpenGL标准进行升级,使OpenGL一直与时代保持同步。 2006年,SGI公司把OpenGL标准的控制从ARB移交给Khronos小组(www.khronos.org)。Khronos是一个由成员提供资金的行业协会,专注于开放媒体标准的创建和维护。目前Khronos负责OpenGL的发展和升级。 如图:
与OpenGL相关的函数库: OpenGL工具函数库(GLU)包含了一些函数,它们利用低层的OpenGL函数来执行一些特定的任务。设定特定的矩阵(gluLookAt等),OpenGL中的GLU必须以glu开头。 对于窗口系统的功能也进行了扩展,如果在linux下使用x窗口的话,使用GLX函数库,而必须以glX开头。对于微软来说,以wgl开头。IBM的os/2而言,PGL是显示管理器与OpenGL之间的接口,以pgl开头。对于Apple,AGL是支持OpenGL的系统接口,所有的AGL函数都以agl开头。 OpenGL实用工具库( GLUT,OpenGL Utility Toolkit )是Mark Kilgrad所编写的一个独立于窗口系统的工具包,它的目的是隐藏不同窗口系统所带来的复杂性。GLUT是下一节的主题,GLUT函数以glut开头。 在OpenGL中,我们常用到轨迹球,下面就对轨迹球来做点东西: 当我们观察三维空间的物体有很多种方法让一个用户来选择一个视点,但是我认为轨迹球是最好的。 轨迹球的基本原理是: 创建一个围绕着物体的球,然后用户单击球上面的一个点,再拖动这个点到一个位置(在屏幕上),让对象跟着这个向量旋转。 寻找鼠标位置: 第一步就是寻找到鼠标的位置,我们可以通过获得视见变换矩阵。 可以通过下面的形式来获得状态矩阵:
GLdouble projection_matrix[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; GLdouble modelview_matrix[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; int viewport_matrix[4] = { 0, 0, 640, 480 };
glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix ); glGetDoublev( GL_MODELVIEW, modelview_matrix ); glGetIntegerv( GL_VIEWPORT, viewport_matrix );
我们获取这些矩阵后面使用,我们可以使用他们来处理鼠标输入,鼠标坐标mouse_x和mouse_y,可以通过gluUnProject来获得鼠标下面场景中的一个点。
GLdouble x, y, z; gluUnProject( mouse_x, mouse_y, modelview_matrix, projection_matrix, viewport_matrix, &x, &y, &z );
一旦场景中的这个点被找到,问题的关键就是建立一个从摄象机位置到这个点的光线,然后寻找这个光线和这个轨迹球的交点。这个光线是E + t * ( P - E )的点集,这里E是眼睛点位置,P是场景中的那个点,t是一个变量,而轨迹球是S的点集,这里S^2 = r,r是轨迹球的半径。如果S = E + t * ( P - E ),那么存在一个点既在轨迹球上,又在光线上,这样,我们可以通过带入法推出:( E + t * ( P - E ) ) ^ 2 = r。我们知道向量E、P以及标量r,所以可以推出来t,这是一个二次方程,如果无解,说明光线和轨迹球无交点。如果有2个解,应当选择最靠近眼睛的那个解。
轨迹球的旋转问题: 如果你单击拖拽轨迹球上的一个点到另一个位置,该如何做呢? 一个简单的方法,做起点到结束点的x乘为旋转轴,然后寻找将要旋转的角度,这个可以通过做点乘得到。
计算旋转矩阵: 我们通过四元数来解决它。四元数是二维复数的扩展,特别适合做旋转。 如果我们有一个单位向量( x, y, z ),我们可以通过乘以旋转角度的正弦的一半获得四元数的x, y, z部分的修正值,w是由旋转角的的余弦的一半决定。大家知道所有的这么值可以被组装进一个旋转矩阵:
w * w + x *x - y * y - z * z, 2 * x * y + 2 * w * z, 2 * x * z - 2 * w * y, 0 2 * x * y - 2 * w * z, w * w - x * x + y * y - z * z, 2 * y * z + 2 * w * x, 0 2 * x * z + 2 * w * y, 2 * y * z - 2 * w * x, w * w - x * x - y * y + z * z, 0 0, 0, 0, w * w + x * x + y * y + z * z
2008年9月24日
最新的Ogre稳定版本是1.6.0RC1[shoggoth],在1.6.0版本中OgreFrameListener.h中的类FrameListener多出了一个叫virtual bool frameRenderingQueued( const FrameEvent& evt ) { return true; }的函数。这个函数和virtual bool frameStarted( const FrameEvent& evt ) { return true; }有明显的区别。 在源代码中对frameStarted的注释是: /** Called when a frame is about to begin rendering. @remarks This event happens before any render targets have begun updating. @return True to go ahead, false to abort rendering and drop out of the rendering loop. */ 大体翻译是: 当一帧将要开始渲染的时候被调用。 这个事件发生在所有渲染目标已经开始更新之前。 而在源代码中对frameRenderingQueued的注释是: /** Called after all render targets have had their rendering commands issued, but before render windows have been asked to flip their buffers over. @remarks The usefulness of this event comes from the fact that rendering commands are queued for the GPU to process. These can take a little while to finish, and so while that is happening the CPU can be doing useful things. Once the request to 'flip buffers' happens, the thread requesting it will block until the GPU is ready, which can waste CPU cycles. Therefore, it is often a good idea to use this callback to perform per-frame processing. Of course because the frame's rendering commands have already been issued, any changes you make will only take effect from the next frame, but in most cases that's not noticeable. @return True to continue rendering, false to drop out of the rendering loop. */ 翻译为: 在所有渲染目标已经传出他们的渲染命令之后,并且在渲染窗口被要求去释放他们的帧之前。 这个事件的用途其实是为了把GPU处理的渲染命令推入队列,这些只花费一点功夫去完成, 而就这一段时间cpu可以被用来处理一些有用的事情。一旦释放帧这个时间发生,这条线程请求将要被 堵塞直到GPU准备好了,这可能浪费了cpu的渲染时间,然而,作为回调函数去逐帧处理也是一个好注意。 当然因为帧的渲染命令已经被放出,任何你做的改变只对下一帧有效,但是大多数情况下这不是很明显的。
加入了这个函数也说明了Ogre1.6.0对gpu重视了。 在ogre自带的例子中,几乎都是用examplelistener来处理游戏循环。这明显不符合比较大点的游戏开发。而如果 你想要在大型游戏中应用这个游戏循环。我感觉首先应该有一个单件的帧监听系统通过游戏主应用程序来初始化。然后就是用设计模式中的Bridge的将声明和执行分开的功能来处理这个方法。 伪代码:
//一个部件的类 class BrilyfWidgets { bool frameRenderingQueued( const FrameEvent& evt ); };
//类的前向声明 class BrilyfApplication;
class BrilyfListenSystem : public Singleton<BrilyfListenSystem>, public FrameListener { bool frameRenderingQueued( const FrameEvent& evt ) { //一些系统缺省的设置 //关键部分 BrilyfApplication::getSingletonPtr()->frameRenderQueued( const FrameEvent& evt ); BrilyfApplication::getSingletonPtr()->frameEnded( const FrameEvent& evt ); } bool frameEnded( const FrameEvent& evt ); };
//所有的其他一些部件的初始化都要通过BrilyfApplication,它就是游戏的主管道,控制着所有部件的生命周期,提供了 //frameRenderingQueued和frameEnded的接口供其他的部件来填充。 class BrilyfApplication : public Singleton<BrilyfApplication> { //一些对于单件初始化的处理 //对应的事件 bool frameRenderingQueued( const FrameEvent& evt ) { for ( int i = 0; i < 16; i++ ) BrilyfWidgets.frameRenderingQueued( ); } bool frameEnded( const FrameEvent& evt );
BrilyfWidgets mWidgets[16]; };
|