基本上都是之前学过的知识,要运用好!总结运用的知识有:
1 物体移位选择(transformation)
2 树形数据结构管理整个场景的信息
3 根据时间控制恒星旋转
如下效果:
首先设置太阳系各恒星的数据结构
枚举太阳,恒星和月亮三个对象类
// We classify the objects in our scene as one of three types.
enum SolarType
{
SUN,
PLANET,
MOON
};
数据结构保存各个信息:
struct SolarObject
{
void set(SolarType type, D3DXVECTOR3 p, float yRot,
int parentIndex, float s, IDirect3DTexture9* t)
{
typeID = type;
pos = p;
yAngle = yRot;
parent = parentIndex;
size = s;
tex = t;
}
// Note: The root's "parent" frame is the world space.
SolarType typeID;//据此确定是什么类型,好确定相对应的纹理,大小等。
D3DXVECTOR3 pos; // 相对父母节点的位置.
float yAngle; // 相对父母节点的角度.
int parent; // 父母索引根节点为-1
float size; // 大小就是相对于世界坐标的大小了.
IDirect3DTexture9* tex;
D3DXMATRIX toParentXForm;
D3DXMATRIX toWorldXForm;
};
定义一个数组保存三个节点的信息(其中每个节点含三个恒星),含根节点,则需要10个节点,如下:
static const int NUM_OBJECTS = 10;
SolarObject mObject[NUM_OBJECTS];
mObject[j]的父母节点是mObject[mObject[j].parent]。
下面是设置其整个太阳系各个恒星的坐标位置及相关信息的代码:
// Create the textures. HR(D3DXCreateTextureFromFile(gd3dDevice, "sun.dds", &mSunTex)); HR(D3DXCreateTextureFromFile(gd3dDevice, "planet1.dds", &mPlanet1Tex)); HR(D3DXCreateTextureFromFile(gd3dDevice, "planet2.dds", &mPlanet2Tex)); HR(D3DXCreateTextureFromFile(gd3dDevice, "planet3.dds", &mPlanet3Tex)); HR(D3DXCreateTextureFromFile(gd3dDevice, "moon.dds", &mMoonTex)); D3DXVECTOR3 pos[NUM_OBJECTS] = { D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DXVECTOR3(7.0f, 0.0f, 7.0f), D3DXVECTOR3(-9.0f, 0.0f, 0.0f), D3DXVECTOR3(7.0f, 0.0f, -6.0f), D3DXVECTOR3(5.0f, 0.0f, 0.0f), D3DXVECTOR3(-5.0f, 0.0f, 0.0f), D3DXVECTOR3(3.0f, 0.0f, 0.0f), D3DXVECTOR3(2.0f, 0.0f, -2.0f), D3DXVECTOR3(-2.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, 2.0f) }; mObject[0].set(SUN, pos[0], 0.0f, -1, 2.5f, mSunTex); // Sun mObject[1].set(PLANET, pos[1], 0.0f, 0, 1.5f, mPlanet1Tex); // P1 mObject[2].set(PLANET, pos[2], 0.0f, 0, 1.2f, mPlanet2Tex); // P2 mObject[3].set(PLANET, pos[3], 0.0f, 0, 0.8f, mPlanet3Tex); // P3 mObject[4].set(MOON, pos[4], 0.0f, 1, 0.5f, mMoonTex); // M1P1 mObject[5].set(MOON, pos[5], 0.0f, 1, 0.5f, mMoonTex); // M2P1 mObject[6].set(MOON, pos[6], 0.0f, 2, 0.4f, mMoonTex); // M1P2 mObject[7].set(MOON, pos[7], 0.0f, 3, 0.3f, mMoonTex); // M1P3 mObject[8].set(MOON, pos[8], 0.0f, 3, 0.3f, mMoonTex); // M2P3 mObject[9].set(MOON, pos[9], 0.0f, 3, 0.3f, mMoonTex); // M3P3
然后根据这些信息构建好各个对象的转换到世界坐标的矩阵。
void SolarSysDemo::buildObjectWorldTransforms()
{
// First, construct the transformation matrix that transforms
// the ith bone into the coordinate system of its parent.
D3DXMATRIX R, T;
D3DXVECTOR3 p;
for(int i = 0; i < NUM_OBJECTS; ++i)
{
p = mObject[i].pos;
D3DXMatrixRotationY(&R, mObject[i].yAngle);
D3DXMatrixTranslation(&T, p.x, p.y, p.z);
mObject[i].toParentXForm = R * T;
}//构建每个节点到父母节点的坐标
// For each object...
for(int i = 0; i < NUM_OBJECTS; ++i)
{
// 跟节点的矩阵.
D3DXMatrixIdentity(&mObject[i].toWorldXForm);
// 循环计算各个节点转换到世界坐标的矩阵.
int k = i;
while( k != -1 ) //-1作为一个标兵,用好标兵技术很好的.
{
mObject[i].toWorldXForm *= mObject[k].toParentXForm;
k = mObject[k].parent; // Move up the ancestry chain.
}
}
}
让太阳系动起来:
void SolarSysDemo::updateScene(float dt)
{
// dt是时间,各个恒星随时间流逝而转动.
for(int i = 0; i < NUM_OBJECTS; ++i)
{
switch(mObject[i].typeID)
{
case SUN:
mObject[i].yAngle += 1.5f * dt;
break;
case PLANET:
mObject[i].yAngle += 2.0f * dt;
break;
case MOON:
mObject[i].yAngle += 2.5f * dt;
break;
}
// 转到360度就置零.
if(mObject[i].yAngle >= 2.0f*D3DX_PI)
mObject[i].yAngle = 0.0f;
}
}
结果如下: