|
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];
};


|