learn, think, share, communication
Posts tagged Ogre
Hermite Curve 在绘制轨迹中的应用
May 12th
在3D游戏的粒子系统中,往往可能有这样一类需求——伴随着人的动作,一条光带划过,或者伴随着武器的劈砍动作,一条刀光划过。
如果我们简单的在每次Tick的时候采样当前的位置朝向,并创建一截新的面片,往往会形成类似于如下图的粗陋效果:
之所以会产生一截一截的感觉,是由于在每次进行采样的时候,我们只能得到当前时刻的位置信息。因此尽管在从上一次到本次采样的过程中,轨迹实际经过的路程是一条平滑的曲线,可由于每一帧之间的时间不可能小到足够提供平滑曲线的采样精度,我们所能获得的总是一截截的折线。
怎样才能够通过为数不多的关键点,创造出一条平滑的曲线来呢?
Charles Hermite 提出的Hermite Curve解决了上面的问题。通过一系列的三维空间关键点,可以得到每个点处的切线,再经过Hermite Base Function的多项式计算,则可以得到插值点。
如图:
设P1,P2为平面上的两个点,T1,T2为两点处的切线,由点及点的切线,Hermite Spline就可以给出一个平滑过渡的曲线。
Hermite Base 多项式的参数如下表,其中t是从上一个点到当前点的插值系数。上一个点处为0,当前点为1。
Ogre在其Ogre::SimpleSpline类中实现了HermiteCurve。感兴趣的同学可以做以参考。
expanded
factorized
h00(t)
t3 − 3t2 + 1
1 + 2t)(1 − t)2
h10(t)
t3 − 2t2 + t
t(1 − t)2
h01(t)
− 2t3 + 3t2
t2(3 − 2t)
h11(t)
t3 − t2
t2(t − 1)
事实上,上述做法也不过就是对Hermite Curve类型的样条曲线的利用而已。样条曲线实际上并不陌生,贝塞尔曲线就是一种我们关注最多的样条曲线。尽管其不适用于我们前述的场合——原因是贝塞尔曲线通过控制点计算出的曲线并非一条依次经过控制点的曲线。如下图所示(图片来源于:http://escience.anu.edu.au/lecture/cg/Spline/printCG.en.html):
参考资料:
1. Hermite Curve Interpolation. Hamburg (Germany), the 30th March 1998
2. Cubic Hermite spline
Ogre源码剖析3–可扩展性&插件机制
May 8th
Ogre是一个跨操作系统平台的开源3D引擎,既支持DirectX,也支持使用OpenGL,支持可替换的场景管理算法(BSP, OCT)。为Ogre提供这些灵活可扩展性的基础之一就是其面向插件的设计。
很多常用的软件大都提供了插件接口,用以扩展应用程序设计者最初未想到的功能,比较常见的譬如PhotoShop的滤镜,After Effect中的各种插件(最有名的比如shine),3dMax的插件譬如渲染器,魔兽世界的辅助插件等等。
通常,插件本身通常也需要实现主应用程序所需要的必要接口,从而使得插件可以被应用程序加载执行。此外,插件的实现也需要由主应用程序提供一些接口api,通过这些接口,插件可以对主应用程序的功能进行调用。
插件可以是动态链接库(win32平台上为DLL文件),也可以是以脚本的形式提供的,比如魔兽世界中的插件就是使用lua编写的,插件也可能是某种应用程序自定义的文件,只要该应用程序提供了创建该类文件的方法并实现解析、执行功能即可。(不同的实现形式各有利弊,具体需要参考插件及应用程序所处的运行环境进行取舍)
采用插件的一个巨大的好处,以及很多应用程序中使用插件的主要目的就是,我们可以在不需要改动应用程序本身的情况下扩展应用程序的功能。
在Ogre中,插件被用来提供渲染子系统(RenderSystem),不同类别的图形API被封装在不同的渲染子系统的视线当中,Ogre默认提供了DX和OpenGL的实现,甚至,如果我们乐意,甚至可以只用绘点函数实现一套纯软件的渲染子系统提供给Ogre使用。以此为例,用简单的形式来展示这种实现大概类似于下面这样:
class RenderSystem
{
// … operations that a render system need to support
};
// In DX_RenderSystem.dll (in plugin dx rendersystem )
class DX_RenderSystem : public RenderSystem
{
// … implementation & override of the operations from RenderSystem using DirectX
};
// In GL_RenderSystem.dll (in plugin openGL rendersystem)
class GL_RenderSystem : public RenderSystem
{
// … implementation & override of the operations [...]
Singleton#1——关于单件对象初始化的探讨
Jan 18th
凡是使用C++进行开发的人,大都或是了解,或是直接使用过Singleton模式,但是Singleton的多种实现方式有什么差异?不同的实现细节背后究竟蕴含着什么意义?本文试图列举常见的几种不同的Singleton实现方式,考察这些不同的实现方式中的细节差异,并剖析其好处与缺点,试图对Singleton的实现方式做一个较为完整的总结。
我们在使用C++编写实际项目的时候,往往会有对全局对象/变量的访问需求。对全局变量的不加封装的访问,会导致许多麻烦的问题:譬如在调试中,由于对全局变量的修改被分散在程序的各个角落里,使得我们无法准确判断一个错误是在何时发生的;再比如,在多线程环境下,如果多个线程都需要访问一个变量,则需要做线程同步操作,在没有良好的封装的情况下,这种状况可能会导致完全莫名的coredump。不过本文并不是想说Singleton有什么好处或者有什么作用,仅仅只是想总结Singleton的不同实现方式之间的异同,以及适用场合。
Ogre源码剖析1:任意类型类Any
Dec 21st
有些时候我们可能想做这样一件事:
float f = 1.f;
int n = 2;
std::vector<X> myContainer; // X是一个虚构的用户定义类型
myContainer.pushback(X(f));
myContainer.pushback(X(n));
我们想在一个容器里保存两种乃至多种不同的数据类型。
但是,显然普通的模板参数如std::vector<int>,或者std::vector<float>都无法满足我们的需求。
也可能存在下面这样的情况:
float fVal = 1.f;
X xMsg = fVal;
PushMessage(xMsg); // PushMessage发送了一个异步消息
// 另一个地方(可能是另一个线程),回调函数被调用:
OnMessageXXX(X xMsg)
{
float f = static_cast<float>(xMsg);
// do something with value f
}
针对这种需求,我们想要一种类型,它可以接受任意的类型,并在需要的时候把我们放入的真正的类型取出来,它可以被放置到容器中,可以被拷贝,以及串行化(前提要求被置入其中的类型可以被输出到标准输出流–std::ostream当中)。
如何设计这种类型呢?
一种容易想到的方案如下:
class Any {
public:
enum {
ANYTYPE_INT,
ANYTYPE_FLOAT,
ANYTYPE_LONG,
// … other data types
};
union {
int nIntData;
float fFloatData;
long lLongData;
// … other [...]