DirectX如何构建一个太阳系
// 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];
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; }}结果如下: