Difference between revisions of "Tutor1 - 构建自己的应用程序框架"

From KlayGE
Jump to: navigation, search
m (1个修订)
(Created page with "大家好,我是Array。3D开发方面的一个热忱爱好者和从业者,主要专注于OpenGL开发,并且是一款开源渲染引擎OpenSceneGraph的主要贡献者和...")
(4 intermediate revisions by 2 users not shown)
Line 5: Line 5:
 
构建KlayGE程序的第一步是从App3DFramework派生出自己的应用程序框架类,一个最简单的框架的头文件引用和类声明如下:
 
构建KlayGE程序的第一步是从App3DFramework派生出自己的应用程序框架类,一个最简单的框架的头文件引用和类声明如下:
  
#include <KlayGE/KlayGE.hpp>
+
''#include <KlayGE/KlayGE.hpp>
#include <KlayGE/App3D.hpp>
+
#include <KlayGE/App3D.hpp>
#include <KlayGE/ResLoader.hpp>
+
#include <KlayGE/ResLoader.hpp>
#include <KlayGE/Context.hpp>
+
#include <KlayGE/Context.hpp>
#include <KlayGE/Font.hpp>
+
#include <KlayGE/Font.hpp>
#include <KlayGE/RenderEngine.hpp>
+
#include <KlayGE/RenderEngine.hpp>
#include <KlayGE/RenderFactory.hpp>
+
#include <KlayGE/RenderFactory.hpp>
#include <KlayGE/UI.hpp>
+
#include <KlayGE/UI.hpp>
+
 
#include <vector>
+
#include <vector>
#include <sstream>
+
#include <sstream>
+
 
class TutorFramework : public KlayGE::App3DFramework
+
class TutorFramework : public KlayGE::App3DFramework
{
+
{
+
public:
public:
+
    TutorFramework();
    TutorFramework();
+
   
   
+
protected:
protected:
+
    virtual void InitObjects();
    virtual void InitObjects();
+
   
   
+
private:
private:
+
    virtual void DoUpdateOverlay();
    virtual void DoUpdateOverlay();
+
    virtual KlayGE::uint32_t DoUpdate(KlayGE::uint32_t pass);
    virtual KlayGE::uint32_t DoUpdate(KlayGE::uint32_t pass);
+
   
   
+
    KlayGE::FontPtr font_;
    KlayGE::FontPtr font_;
+
};''
};
+
  
 
程序主函数中,我们的工作就是建立一个TutorFramework对象,创建它的场景元素,并运行仿真循环:
 
程序主函数中,我们的工作就是建立一个TutorFramework对象,创建它的场景元素,并运行仿真循环:
  
int main(int argc, char** argv)
+
''int main(int argc, char** argv)
{
+
{
    // 将资源文件路径添加到ResLoader中,纹理,字体等资源都会通过ResLoader来读取
+
    // 将资源文件路径添加到ResLoader中,纹理,字体等资源都会通过ResLoader来读取
    // ../media中的各个子目录是自动添加到ResLoader中的,因此其中的字体,纹理和模型数据都可以直接取用
+
    // ../media中的各个子目录是自动添加到ResLoader中的,因此其中的字体,纹理和模型数据都可以直接取用
    // 这里添加了额外的../Samples/media/Common目录
+
    // 这里添加了额外的../Samples/media/Common目录
    KlayGE::ResLoader::Instance().AddPath("../Samples/media/Common");
+
    KlayGE::ResLoader::Instance().AddPath("../Samples/media/Common");
+
    // 从KlayGE.cfg中读取配置信息。各个功能模块,诸如RenderFactory,AudioFactory等都会在这一过程中被初始化
+
    KlayGE::Context::Instance().LoadCfg("KlayGE.cfg");
+
+
    // 自定义的应用程序框架
+
    TutorFramework app;
+
   
+
    // 创建框架中的基本对象,Create()内部将创建显示窗口并依次执行派生类的InitObjects()和OnResize()方法
+
    // 自定义框架类通过重写这些函数来实现场景对象的初始化。Create()本身也可以被重写。
+
    app.Create();
+
   
+
    // 开始执行渲染
+
    app.Run();
+
  
    return 0;
+
    // 从KlayGE.cfg中读取配置信息。各个功能模块,诸如RenderFactory,AudioFactory等都会在这一过程中被初始化
}
+
    KlayGE::Context::Instance().LoadCfg("KlayGE.cfg");
 +
 
 +
    // 自定义的应用程序框架
 +
    TutorFramework app;
 +
   
 +
    // 创建框架中的基本对象,Create()内部将创建显示窗口并依次执行派生类的InitObjects()和OnResize()方法
 +
    // 自定义框架类通过重写这些函数来实现场景对象的初始化。Create()本身也可以被重写。
 +
    app.Create();
 +
   
 +
    // 开始执行渲染
 +
    app.Run();
 +
 
 +
    return 0;
 +
}''
  
 
这之后就是对TutorFramework具体实现的过程:
 
这之后就是对TutorFramework具体实现的过程:
  
 
InitObjects()函数将在app.Create()时被调用
 
InitObjects()函数将在app.Create()时被调用
 
+
''void TutorFramework::InitObjects()
void TutorFramework::InitObjects()
+
{
{
+
    // 从文件中创建新的字体,字体必须保存在ResLoader可以找到的路径下
    // 从文件中创建新的字体,字体必须保存在ResLoader可以找到的路径下
+
    font_ = KlayGE::Context::Instance().RenderFactoryInstance().MakeFont("gkai00mp.kfont");
    font_ = KlayGE::Context::Instance().RenderFactoryInstance().MakeFont("gkai00mp.kfont");
+
}''
}
+
  
 
在Run()的过程中,更新覆盖在屏幕最前显示的内容。这部分内容只会在DoUpdate()的参数pass = 0时被渲染一次
 
在Run()的过程中,更新覆盖在屏幕最前显示的内容。这部分内容只会在DoUpdate()的参数pass = 0时被渲染一次
 +
''void TutorFramework::DoUpdateOverlay()
 +
{
 +
    // 将当前的FPS信息输出到字符串中,以备渲染到屏幕上
 +
    std::wostringstream stream;
 +
    stream.precision(2);
 +
    stream << std::fixed << this->FPS() << " FPS";
  
void TutorFramework::DoUpdateOverlay()
+
    // 使用之前构建的新字体来渲染文本信息,RenderText()可以接受的参数包括:
{
+
    // X,Y位置,KlayGE::Color颜色,std::wstring类型的字符串,以及字体大小
    // 将当前的FPS信息输出到字符串中,以备渲染到屏幕上
+
    font_->RenderText(0, 0, KlayGE::Color(1, 1, 0, 1), L"自定义框架例子", 16);
    std::wostringstream stream;
+
    font_->RenderText(0, 18, KlayGE::Color(1, 1, 0, 1), stream.str(), 16);
    stream.precision(2);
+
}''
    stream << std::fixed << this->FPS() << " FPS";
+
+
    // 使用之前构建的新字体来渲染文本信息,RenderText()可以接受的参数包括:
+
    // X,Y位置,KlayGE::Color颜色,std::wstring类型的字符串,以及字体大小
+
    font_->RenderText(0, 0, KlayGE::Color(1, 1, 0, 1), L"自定义框架例子", 16);
+
    font_->RenderText(0, 18, KlayGE::Color(1, 1, 0, 1), stream.str(), 16);
+
}
+
  
 
这里就是本程序每帧要更新的内容,包括清屏,动画,对象状态更新等等。在同一帧当中,DoUpdate()可能被执行多次,从而实现多遍渲染的功能,多次执行DoUpdate()时每次的函数传入参数pass均不同。注意,是否在每帧当中进行多遍渲染是由上一次的函数返回值来决定的:
 
这里就是本程序每帧要更新的内容,包括清屏,动画,对象状态更新等等。在同一帧当中,DoUpdate()可能被执行多次,从而实现多遍渲染的功能,多次执行DoUpdate()时每次的函数传入参数pass均不同。注意,是否在每帧当中进行多遍渲染是由上一次的函数返回值来决定的:
 
URV_Need_Flush:要求将更新的内容送入渲染队列
 
URV_Need_Flush:要求将更新的内容送入渲染队列
 
URV_Finished:这一帧的更新正式结束。没有设置这一标志的话,系统会一直停留在当前帧反复调用DoUpdate()更新
 
URV_Finished:这一帧的更新正式结束。没有设置这一标志的话,系统会一直停留在当前帧反复调用DoUpdate()更新
 
+
''KlayGE::uint32_t TutorFramework::DoUpdate(KlayGE::uint32_t pass)
KlayGE::uint32_t TutorFramework::DoUpdate(KlayGE::uint32_t pass)
+
{
{
+
    // 获取渲染引擎对象。根据KlayGE.cfg文件的配置内容,它可能通过OpenGL或者D3D11来实现
    // 获取渲染引擎对象。根据KlayGE.cfg文件的配置内容,它可能通过OpenGL或者D3D11来实现
+
    KlayGE::RenderEngine& re = KlayGE::Context::Instance().RenderFactoryInstance().RenderEngineInstance();
    KlayGE::RenderEngine& re = KlayGE::Context::Instance().RenderFactoryInstance().RenderEngineInstance();
+
   
   
+
    // 清除当前帧缓存,Clear()函数需要的参数包括:
    // 清除当前帧缓存,Clear()函数需要的参数包括:
+
    // 缓存类型掩码(可选择清除颜色,深度,模板缓存),清除后颜色,深度,以及模板缓存的初始值
    // 缓存类型掩码(可选择清除颜色,深度,模板缓存),清除后颜色,深度,以及模板缓存的初始值
+
    re.CurFrameBuffer()->Clear(KlayGE::FrameBuffer::CBM_Color | KlayGE::FrameBuffer::CBM_Depth,
    re.CurFrameBuffer()->Clear(KlayGE::FrameBuffer::CBM_Color | KlayGE::FrameBuffer::CBM_Depth,
+
                              KlayGE::Color(0.2f, 0.4f, 0.6f, 1), 1.0f, 0);
                                KlayGE::Color(0.2f, 0.4f, 0.6f, 1), 1.0f, 0);
+
   
   
+
    // Update的返回值决定了系统进行渲染时的行为
    // Update的返回值决定了系统进行渲染时的行为
+
    return KlayGE::App3DFramework::URV_Need_Flush | KlayGE::App3DFramework::URV_Finished;
    return KlayGE::App3DFramework::URV_Need_Flush | KlayGE::App3DFramework::URV_Finished;
+
}''
}
+
  
 
That's it! 这就是我们自己的应用程序框架了,虽然它目前毫无用处,但是谁又能知道襁褓中的婴孩会成长为怎样的巨人呢?请大家拭目以待吧 :-)
 
That's it! 这就是我们自己的应用程序框架了,虽然它目前毫无用处,但是谁又能知道襁褓中的婴孩会成长为怎样的巨人呢?请大家拭目以待吧 :-)
 
[[File:Tutor1.JPG]]
 

Revision as of 05:18, 31 January 2011

大家好,我是Array。3D开发方面的一个热忱爱好者和从业者,主要专注于OpenGL开发,并且是一款开源渲染引擎OpenSceneGraph的主要贡献者和推广人。不过,在KlayGE方面,我的道行只能用微不足道来形容,写这个看起来没什么技术含量的教程的目的,也是为了在枯燥的阅读源代码的学习过程中加深自己的印象,同时将一些可能的问题和思考与更多的朋友分享——共同推动KlayGE这款出色的次世代引擎的发展和完善。

在这个入门级别的教程中,我将试图构建一个属于自己的应用程序框架。一开始的时候,它也许什么也做不了,但是我们将在后继的教程中完善它的功能,并共同学习如何向一个基于KlayGE的程序中添加模型,文字,纹理,动画,种类繁多的效果,以及与用户和窗口系统进行更加丰富的交互操作。我将在每篇教程中使用源代码和注释的方式来诠释将要实现的效果,以及可能需要注意的问题。如果有朋友对于这系列教程有自己的看法,或者发现了概念和代码的错误,也请不吝向我提出,感谢之至。

构建KlayGE程序的第一步是从App3DFramework派生出自己的应用程序框架类,一个最简单的框架的头文件引用和类声明如下:

#include <KlayGE/KlayGE.hpp>

  1. include <KlayGE/App3D.hpp>
  2. include <KlayGE/ResLoader.hpp>
  3. include <KlayGE/Context.hpp>
  4. include <KlayGE/Font.hpp>
  5. include <KlayGE/RenderEngine.hpp>
  6. include <KlayGE/RenderFactory.hpp>
  7. include <KlayGE/UI.hpp>
  1. include <vector>
  2. include <sstream>

class TutorFramework : public KlayGE::App3DFramework { public:

   TutorFramework();
   

protected:

   virtual void InitObjects();
   

private:

   virtual void DoUpdateOverlay();
   virtual KlayGE::uint32_t DoUpdate(KlayGE::uint32_t pass);
   
   KlayGE::FontPtr font_;

};

程序主函数中,我们的工作就是建立一个TutorFramework对象,创建它的场景元素,并运行仿真循环:

int main(int argc, char** argv) {

   // 将资源文件路径添加到ResLoader中,纹理,字体等资源都会通过ResLoader来读取
   // ../media中的各个子目录是自动添加到ResLoader中的,因此其中的字体,纹理和模型数据都可以直接取用
   // 这里添加了额外的../Samples/media/Common目录
   KlayGE::ResLoader::Instance().AddPath("../Samples/media/Common");
   // 从KlayGE.cfg中读取配置信息。各个功能模块,诸如RenderFactory,AudioFactory等都会在这一过程中被初始化
   KlayGE::Context::Instance().LoadCfg("KlayGE.cfg");
   // 自定义的应用程序框架
   TutorFramework app;
   
   // 创建框架中的基本对象,Create()内部将创建显示窗口并依次执行派生类的InitObjects()和OnResize()方法
   // 自定义框架类通过重写这些函数来实现场景对象的初始化。Create()本身也可以被重写。
   app.Create();
   
   // 开始执行渲染
   app.Run();
   return 0;

}

这之后就是对TutorFramework具体实现的过程:

InitObjects()函数将在app.Create()时被调用 void TutorFramework::InitObjects() {

   // 从文件中创建新的字体,字体必须保存在ResLoader可以找到的路径下
   font_ = KlayGE::Context::Instance().RenderFactoryInstance().MakeFont("gkai00mp.kfont");

}

在Run()的过程中,更新覆盖在屏幕最前显示的内容。这部分内容只会在DoUpdate()的参数pass = 0时被渲染一次 void TutorFramework::DoUpdateOverlay() {

   // 将当前的FPS信息输出到字符串中,以备渲染到屏幕上
   std::wostringstream stream;
   stream.precision(2);
   stream << std::fixed << this->FPS() << " FPS";
   // 使用之前构建的新字体来渲染文本信息,RenderText()可以接受的参数包括:
   // X,Y位置,KlayGE::Color颜色,std::wstring类型的字符串,以及字体大小
   font_->RenderText(0, 0, KlayGE::Color(1, 1, 0, 1), L"自定义框架例子", 16);
   font_->RenderText(0, 18, KlayGE::Color(1, 1, 0, 1), stream.str(), 16);

}

这里就是本程序每帧要更新的内容,包括清屏,动画,对象状态更新等等。在同一帧当中,DoUpdate()可能被执行多次,从而实现多遍渲染的功能,多次执行DoUpdate()时每次的函数传入参数pass均不同。注意,是否在每帧当中进行多遍渲染是由上一次的函数返回值来决定的: URV_Need_Flush:要求将更新的内容送入渲染队列 URV_Finished:这一帧的更新正式结束。没有设置这一标志的话,系统会一直停留在当前帧反复调用DoUpdate()更新 KlayGE::uint32_t TutorFramework::DoUpdate(KlayGE::uint32_t pass) {

   // 获取渲染引擎对象。根据KlayGE.cfg文件的配置内容,它可能通过OpenGL或者D3D11来实现
   KlayGE::RenderEngine& re = KlayGE::Context::Instance().RenderFactoryInstance().RenderEngineInstance();
   
   // 清除当前帧缓存,Clear()函数需要的参数包括:
   // 缓存类型掩码(可选择清除颜色,深度,模板缓存),清除后颜色,深度,以及模板缓存的初始值
   re.CurFrameBuffer()->Clear(KlayGE::FrameBuffer::CBM_Color | KlayGE::FrameBuffer::CBM_Depth,
                              KlayGE::Color(0.2f, 0.4f, 0.6f, 1), 1.0f, 0);
   
   // Update的返回值决定了系统进行渲染时的行为
   return KlayGE::App3DFramework::URV_Need_Flush | KlayGE::App3DFramework::URV_Finished;

}

That's it! 这就是我们自己的应用程序框架了,虽然它目前毫无用处,但是谁又能知道襁褓中的婴孩会成长为怎样的巨人呢?请大家拭目以待吧 :-)