Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

TranslationCharacterModel.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00002 // Lamp : Open source game middleware
00003 // Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
00004 //
00005 // This library is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 //
00010 // This library is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this library; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 //------------------------------------------------------------------------------
00019 
00020 /** @file
00021  * 変換キャラクタモデル実装
00022  * @author Junpee
00023  */
00024 
00025 #include "System/stdafx.h"
00026 #include "Translator/Model/TranslationCharacterModel.h"
00027 #include "Translator/Model/TranslationBone.h"
00028 #include "Translator/Mesh/TranslationMeshManager.h"
00029 #include "Graphics/Scene/Scene.h"
00030 #include "Graphics/Model/ModelManager.h"
00031 #include "Graphics/Mesh/MeshManager.h"
00032 #include "Animation/System/AnimationManager.h"
00033 #include "Animation/System/AnimationSet.h"
00034 #include "Animation/Model/CharacterModelAnimation.h"
00035 #include "Animation/VectorInterpolator/VectorArrayInterpolator.h"
00036 #include "Animation/RotationInterpolator/EulerArrayInterpolator.h"
00037 
00038 namespace LampForMaya{
00039 
00040 //------------------------------------------------------------------------------
00041 // コンストラクタ
00042 TranslationCharacterModel::TranslationCharacterModel(
00043     const MObject& initializeObject, const String& initializeName,
00044     const MObject& skinClusterObject) :
00045     TranslationModel(initializeObject, initializeName),
00046     skinClusterObject_(skinClusterObject),
00047     transBones_(NULL), transBoneCount_(0), transMeshes_(NULL){
00048     MayaStatusCheck(skinCluster_.setObject(skinClusterObject_));
00049 }
00050 //------------------------------------------------------------------------------
00051 // デストラクタ
00052 TranslationCharacterModel::~TranslationCharacterModel(){
00053     SafeArrayDelete(transBones_);
00054     SafeArrayDelete(transMeshes_);
00055 }
00056 //------------------------------------------------------------------------------
00057 // 分析
00058 bool TranslationCharacterModel::analyze(TranslationMeshManager* meshManager){
00059     // モデルの分析
00060     if(!analyzeModel()){ return false; }
00061     // 複数ジオメトリへのボーン変形は対応しない
00062     if(skinCluster_.numOutputConnections() != 1){
00063         MayaErrorOut(String("TranslationCharacterModel::analyze() ") + 
00064             name_ + "に複数のモデルが接続されています");
00065         return false;
00066     }
00067     // ボーンのアナライズ
00068     if(!analyzeBone()){ return false; }
00069     // メッシュのアナライズ
00070     if(!analyzeMesh(meshManager)){ return false; }
00071     // ウェイトのアナライズ
00072     if(!analyzeWeight()){ return false; }
00073     // メッシュの論理チェック
00074     for(int i = 0; i < meshes_.getCount(); i++){
00075         if(!meshes_.get(i)->logicalCheck()){ return false; }
00076     }
00077     return true;
00078 }
00079 //------------------------------------------------------------------------------
00080 // ボーンのアナライズ
00081 bool TranslationCharacterModel::analyzeBone(){
00082     MStatus result;
00083     String errorMessage;
00084     // ボーン数の調査
00085     MDagPathArray bonePathArray;
00086     transBoneCount_ = skinCluster_.influenceObjects(bonePathArray, &result);
00087     MayaStatusCheck(result);
00088     if(transBoneCount_ > CharacterModel::maxBoneCount){
00089         errorMessage.format("TranslationCharacterModel::analyzeBone() "
00090             "%sのボーン数が多すぎます ( %d / %d )",
00091             name_.getBytes(), transBoneCount_, CharacterModel::maxBoneCount);
00092         MayaErrorOut(errorMessage);
00093         return false;
00094     }else if(transBoneCount_ == 0){
00095         MayaErrorOut(String("TranslationCharacterModel::analyzeBone() ") +
00096             name_ + "にボーンがありません");
00097         return false;
00098     }
00099     // ボーンの構築
00100     transBones_ = new TranslationBone[transBoneCount_];
00101     for(int i = 0; i < transBoneCount_; i++){
00102         transBones_[i].analyze(bonePathArray[i]);
00103     }
00104     // 逆変換行列の算出
00105     transBones_[0].buildModelMatrix(this, Matrix34::unit);
00106     return true;
00107 }
00108 //------------------------------------------------------------------------------
00109 // 変換ボーンの検索
00110 TranslationBone* TranslationCharacterModel::searchBone(const String& boneName){
00111     // とりあえず線形探索。最大で256本なので多分大丈夫。問題があればHashMapにする。
00112     for(int i = 0; i < transBoneCount_; i++){
00113         if(transBones_[i].getName().equals(boneName)){
00114             return &transBones_[i];
00115         }
00116     }
00117     return NULL;
00118 }
00119 //------------------------------------------------------------------------------
00120 // メッシュのアナライズ
00121 bool TranslationCharacterModel::analyzeMesh(TranslationMeshManager* meshManager){
00122     MStatus result;
00123     String errorString;
00124     MFnMesh fnMesh(object_, &result);
00125     MayaStatusCheck(result);
00126 
00127     // UVセット数の取得
00128     MStringArray uvSetNames;
00129     MayaStatusCheck(fnMesh.getUVSetNames(uvSetNames));
00130     int uvSetCount = uvSetNames.length();
00131 
00132     // シェーダ情報の取得
00133     MObjectArray shaders;
00134     MIntArray shaderIndices;
00135     // 常にインスタンス番号0番のモデルデータを使用する
00136     result = fnMesh.getConnectedShaders(0, shaders, shaderIndices);
00137     MayaStatusCheck(result);
00138 
00139     // シェーダが割り当てられていないポリゴンがあればエラー
00140     for(u_int i = 0; i < shaderIndices.length(); i++){
00141         if(shaderIndices[i] == -1){
00142             MIntArray vertexIndex;
00143             MayaStatusCheck(fnMesh.getPolygonVertices(i, vertexIndex));
00144             int vertexCount = vertexIndex.length();
00145             errorString.format("TranslationCharacterModel::analyze() "
00146                 "%sにシェーダの割り当てられいないポリゴンがあります ",
00147                 name_.getBytes());
00148             for(int i = 0; i < vertexCount; i++){
00149                 MPoint position;
00150                 MayaStatusCheck(fnMesh.getPoint(vertexIndex[i], position));
00151                 String temp;
00152                 temp.format(" ( %.3f , %.3f , %.3f)",
00153                     position.x, position.y, position.z);
00154                 errorString += temp;
00155             }
00156             MayaErrorOut(errorString);
00157             return false;
00158         }
00159     }
00160 
00161     // シェーダの数だけメッシュを用意する
00162     transMeshCount_ = shaders.length();
00163     int nameCount = 0;
00164     transMeshes_ = new TranslationCharacterMesh*[transMeshCount_];
00165     for(int i = 0; i < transMeshCount_; i++){
00166         // 重複の無い名前を作成
00167         String meshName;
00168         while(true){
00169             meshName.format("%sM%d", name_.getBytes(), nameCount);
00170             nameCount++;
00171             TranslationMesh* exist = meshManager->search(meshName);
00172             if(exist == NULL){ break; }
00173         }
00174         transMeshes_[i] = meshManager->createCharacterMesh(meshName);
00175         // モデルにメッシュを追加する
00176         meshes_.add(transMeshes_[i]);
00177         // UVセット数を設定する
00178         transMeshes_[i]->setUVSetCount(uvSetCount);
00179         // シェーダ名を設定する
00180         transMeshes_[i]->setMaterialName(getShaderName(shaders[i]));
00181     }
00182 
00183     // ポリゴンはオリジナルメッシュから取得
00184     MObject inputShapeObject = skinCluster_.inputShapeAtIndex(0, &result);
00185     MayaStatusCheck(result);
00186     // ポリゴンをメッシュに割り振る
00187     MItMeshPolygon polygonIterator(inputShapeObject, &result);
00188     MayaStatusCheck(result);
00189     int polygonCount = 0;
00190     for( ; !polygonIterator.isDone(); polygonIterator.next()){
00191         int shaderIndex = shaderIndices[polygonCount];
00192         TranslationCharacterMesh* mesh = transMeshes_[shaderIndex];
00193         polygonCount++;
00194         // 位置
00195         MPointArray positions;
00196         polygonIterator.getPoints(positions, MSpace::kObject, &result);
00197         MayaStatusCheck(result);
00198 // Weightのアナライズとの整合性を取る必要がある
00199 //      bool isSquare = (positions.length() == 4);
00200 //      if((positions.length() != 3) && (!isSquare)){
00201         if(positions.length() != 3){
00202             errorString.format("TranslationStandardModel::analyze() "
00203 //              "%sが三角、四角以外のポリゴン(%d角形)を持っています\n",
00204                 "%sが三角以外のポリゴン(%d角形)を持っています\n",
00205                 name_.getBytes(), positions.length());
00206             for(u_int i = 0; i < positions.length(); i++){
00207                 String temp;
00208                 temp.format(" %d ( %.3f , %.3f , %.3f)",
00209                     i, positions[i].x, positions[i].y, positions[i].z);
00210                 errorString += temp;
00211             }
00212             MayaErrorOut(errorString);
00213             return false;
00214         }
00215         mesh->addPosition(Vector3((float)positions[0].x,
00216             (float)positions[0].y, (float)positions[0].z));
00217         mesh->addPosition(Vector3((float)positions[1].x,
00218             (float)positions[1].y, (float)positions[1].z));
00219         mesh->addPosition(Vector3((float)positions[2].x,
00220             (float)positions[2].y, (float)positions[2].z));
00221 /*
00222         if(isSquare){
00223             mesh->addPosition(Vector3((float)positions[0].x,
00224                 (float)positions[0].y, (float)positions[0].z));
00225             mesh->addPosition(Vector3((float)positions[2].x,
00226                 (float)positions[2].y, (float)positions[2].z));
00227             mesh->addPosition(Vector3((float)positions[3].x,
00228                 (float)positions[3].y, (float)positions[3].z));
00229         }
00230 */
00231 
00232         // 法線
00233         MVectorArray normals;
00234         result = polygonIterator.getNormals(normals, MSpace::kObject);
00235         MayaStatusCheck(result);
00236         mesh->addNormal(Vector3(
00237             (float)normals[0].x, (float)normals[0].y, (float)normals[0].z));
00238         mesh->addNormal(Vector3(
00239             (float)normals[1].x, (float)normals[1].y, (float)normals[1].z));
00240         mesh->addNormal(Vector3(
00241             (float)normals[2].x, (float)normals[2].y, (float)normals[2].z));
00242 /*
00243         if(isSquare){
00244             mesh->addNormal(Vector3(
00245                 (float)normals[0].x, (float)normals[0].y, (float)normals[0].z));
00246             mesh->addNormal(Vector3(
00247                 (float)normals[2].x, (float)normals[2].y, (float)normals[2].z));
00248             mesh->addNormal(Vector3(
00249                 (float)normals[3].x, (float)normals[3].y, (float)normals[3].z));
00250         }
00251 */
00252 
00253         // カラー
00254         bool hasColor = polygonIterator.hasColor(&result);
00255         MayaStatusCheck(result);
00256         if(hasColor){
00257             MColorArray colors;
00258             result = polygonIterator.getColors(colors);
00259             MayaStatusCheck(result);
00260             mesh->addColor(Color4f(
00261                 colors[0].r, colors[0].g, colors[0].b, colors[0].a));
00262             mesh->addColor(Color4f(
00263                 colors[1].r, colors[1].g, colors[1].b, colors[1].a));
00264             mesh->addColor(Color4f(
00265                 colors[2].r, colors[2].g, colors[2].b, colors[2].a));
00266 /*
00267             if(isSquare){
00268                 mesh->addColor(Color4f(
00269                     colors[0].r, colors[0].g, colors[0].b, colors[0].a));
00270                 mesh->addColor(Color4f(
00271                     colors[2].r, colors[2].g, colors[2].b, colors[2].a));
00272                 mesh->addColor(Color4f(
00273                     colors[3].r, colors[3].g, colors[3].b, colors[3].a));
00274             }
00275 */
00276         }
00277 
00278         // UV
00279         MFloatArray uArray, vArray;
00280         for(int i = 0; i < uvSetCount; i++){
00281             MayaStatusCheck(polygonIterator.getUVs(
00282                 uArray, vArray, &uvSetNames[i]));
00283             // V座標を反転する
00284             mesh->addUV(TexCoord2(uArray[0], (vArray[0] - 1.f) * -1.f));
00285             mesh->addUV(TexCoord2(uArray[1], (vArray[1] - 1.f) * -1.f));
00286             mesh->addUV(TexCoord2(uArray[2], (vArray[2] - 1.f) * -1.f));
00287         }
00288 /*
00289         if(isSquare){
00290             for(int i = 0; i < uvSetCount; i++){
00291             MayaStatusCheck(polygonIterator.getUVs(
00292                 uArray, vArray, &uvSetNames[i]));
00293             // V座標を反転する
00294             mesh->addUV(TexCoord2(uArray[0], (vArray[0] - 1.f) * -1.f));
00295             mesh->addUV(TexCoord2(uArray[2], (vArray[2] - 1.f) * -1.f));
00296             mesh->addUV(TexCoord2(uArray[3], (vArray[3] - 1.f) * -1.f));
00297             }
00298         }
00299 */
00300 
00301         // 頂点インデックス
00302         u_int index0 = polygonIterator.vertexIndex(0, &result);
00303         u_int index1 = polygonIterator.vertexIndex(1, &result);
00304         u_int index2 = polygonIterator.vertexIndex(2, &result);
00305         mesh->addIndex(index0);
00306         mesh->addIndex(index1);
00307         mesh->addIndex(index2);
00308 /*
00309         if(isSquare){
00310             u_int index3 = polygonIterator.vertexIndex(3, &result);
00311             mesh->addIndex(index0);
00312             mesh->addIndex(index2);
00313             mesh->addIndex(index3);
00314         }
00315 */
00316 
00317 // ここでWeightを収集できれば四角対応可能
00318 // MItMeshPolygon::polygon()をMFnSkinCluster::getWeights()に突っ込んでなんとかならないか
00319     }
00320     return true;
00321 }
00322 //------------------------------------------------------------------------------
00323 // ウェイトのアナライズ
00324 bool TranslationCharacterModel::analyzeWeight(){
00325     MStatus result;
00326     String errorMessage;
00327     bool returnValue = true;
00328     // ジオメトリイテレータを取得する
00329     u_int index = skinCluster_.indexForOutputConnection(0, &result);
00330     MayaStatusCheck(result);
00331     MDagPath skinPath;
00332     MayaStatusCheck(skinCluster_.getPathAtIndex(index, skinPath));
00333     MItGeometry geometries(skinPath);
00334     // ジオメトリイテレータからコンポーネントを取得し、Weightを入手する
00335     int vertexCount = geometries.count();
00336     float* weights = new float[transBoneCount_ * vertexCount];
00337     int * weightCounts = new int[vertexCount];
00338     u_int vertexCounter = 0;
00339     for( ; !geometries.isDone(); geometries.next(), vertexCounter++){
00340         MObject component = geometries.component(&result);
00341         MayaStatusCheck(result);
00342         MFloatArray weightArray;
00343         u_int boneCount;
00344         MayaStatusCheck(skinCluster_.getWeights(
00345             skinPath, component, weightArray, boneCount));
00346         if(transBoneCount_ != boneCount){
00347             MayaErrorOut(String("TranslationCharacterModel::analyzeWeight() ") + 
00348                 name_ + "の頂点ボーン数と出力ボーン数に違いがあります");
00349             returnValue = false;
00350             break;
00351         }
00352         int offset = vertexCounter * transBoneCount_;
00353         weightCounts[vertexCounter] = 0;
00354         float totalWeight = 0.f;
00355         for(int i = 0; i < transBoneCount_; i++){
00356             weights[offset + i] = weightArray[i];
00357             // 0.1%以下のウェイトは無視する
00358             if(weights[offset + i] < 0.001f){ weights[offset + i] = 0.f; }
00359             if(weights[offset + i] != 0.f){ weightCounts[vertexCounter]++; }
00360             totalWeight += weights[offset + i];
00361         }
00362         // 頂点に対するウェイト数の範囲チェック
00363         if((weightCounts[vertexCounter] > CharacterMesh::maxWeightPerVertex) ||
00364             (weightCounts[vertexCounter] <= 0)){
00365             errorMessage.format("TranslationCharacterModel::analyzeWeight() "
00366                 "%sの%d番目の頂点に%d個のウェイトが割り付けられています",
00367                 name_.getBytes(), vertexCounter, weightCounts[vertexCounter]);
00368             MayaErrorOut(errorMessage);
00369             returnValue = false;
00370             break;
00371         }
00372         // ウェイト合計が1であるかチェック
00373         if(Math::abs(totalWeight - 1.f) > 0.001f){
00374             errorMessage.format("TranslationCharacterModel::analyzeWeight() "
00375                 "%sの%d番目の頂点のウェイト合計が1でありません",
00376                 name_.getBytes(), vertexCounter, totalWeight);
00377             MayaErrorOut(errorMessage);
00378             returnValue = false;
00379             break;
00380         }
00381     }
00382     if(!returnValue){
00383         delete[] weights;
00384         delete[] weightCounts;
00385         return returnValue;
00386     }
00387     // スティッチングフラグの取得
00388     MFnDependencyNode node(object_, &result);
00389     MayaStatusCheck(result);
00390     MObject stitchingAttribute = node.attribute("LampStitching", &result);
00391     bool stitchingFlag = false;
00392     if(result){
00393         MayaStatusCheck(result);
00394         MPlug stitchingPlug(object_, stitchingAttribute);
00395         result = stitchingPlug.getValue(stitchingFlag);
00396         MayaStatusCheck(result);
00397     }
00398     // 強制スティッチング化
00399     if(stitchingFlag){
00400         for(int i = 0; i < vertexCount; i++){
00401             int offset = i * transBoneCount_;
00402             int maxWeightIndex = 0;
00403             float maxWeight = weights[offset];
00404             weights[offset] = 0.f;
00405             for(int j = 1; j < transBoneCount_; j++){
00406                 if(weights[offset + j] > maxWeight){
00407                     maxWeight = weights[offset + j];
00408                     maxWeightIndex = j;
00409                 }
00410                 weights[offset + j] = 0.f;
00411             }
00412             // 最大のWeightのみ1にする
00413             weights[offset + maxWeightIndex] = 1.f;
00414             weightCounts[i] = 1;
00415         }
00416     }
00417     // ウェイトデータの設定
00418     if(returnValue){
00419         for(int i = 0; i < transMeshCount_; i++){
00420             if(!transMeshes_[i]->setWeights(
00421                 transBoneCount_, weights, weightCounts)){
00422                 returnValue = false;
00423                 break;
00424             }
00425         }
00426     }
00427     delete[] weights;
00428     delete[] weightCounts;
00429     return returnValue;
00430 }
00431 //------------------------------------------------------------------------------
00432 // アニメーションの分析
00433 bool TranslationCharacterModel::analyzeAnimation(){
00434     // シーケンスの分析、シーケンスが無ければアニメーション無し
00435     if(!sequence_.analyze(object_)){ return true; }
00436     int startTime = sequence_.getStartTime(0);
00437     int endTime = sequence_.getEndTime(sequence_.getSequenceCount() - 1);
00438     for(int i = 0; i < transBoneCount_; i++){
00439         transBones_[i].analyzeAnimation(startTime, endTime);
00440     }
00441     return true;
00442 }
00443 //------------------------------------------------------------------------------
00444 // Lampへの変換
00445 bool TranslationCharacterModel::convertToLamp(Scene* scene){
00446     ModelManager* modelManager = scene->getModelManager();
00447     CharacterModel* model = modelManager->createCharacterModel(name_);
00448     // 有効、無効フラグ
00449     model->setEnabled(visibility_);
00450     // メッシュとのリンク
00451     MeshManager* meshManager = scene->getMeshManager();
00452     int meshCount = meshes_.getCount();
00453     for(int i = 0; i < meshCount; i++){
00454         String meshName = meshes_.get(i)->getName();
00455         Mesh* mesh = meshManager->search(meshName);
00456         if(mesh == NULL){
00457             MayaErrorOut(String("TranslationCharacterModel::convertToLamp() "
00458                 "メッシュが見つかりません ") + meshName);
00459             return false;
00460         }
00461         model->addMesh(mesh);
00462     }
00463     // ボーンの変換
00464     for(int i = 0; i < transBoneCount_; i++){
00465         if(!transBones_[i].convertToLamp(model)){ return false; }
00466     }
00467     // ボーンのリンク
00468     for(int i = 0; i < transBoneCount_; i++){
00469         if(!transBones_[i].boneLink(model, i)){ return false; }
00470     }
00471     return true;
00472 }
00473 //------------------------------------------------------------------------------
00474 // アニメーションの変換
00475 bool TranslationCharacterModel::convertAnimation(
00476     AnimationManager* animationManager, AnimationSet* animationSet){
00477     // シーケンスが無ければアニメーション無し
00478     if(!sequence_.hasSequence()){ return true; }
00479     CharacterModelAnimation* animation =
00480         animationManager->createCharacterModel(name_);
00481     if(animation->getName() != name_){
00482         MayaErrorOut("TranslationCharacterModel::convertAnimation() " +
00483             name_ + "の名前が重複しています ");
00484         return false;
00485     }
00486     CharacterModelAnimationData* data =
00487         animationManager->createCharacterModelData(name_);
00488     if(data->getName() != name_){
00489         MayaErrorOut("TranslationCharacterModel::convertAnimation() " +
00490             name_ + "の名前が重複しています ");
00491         return false;
00492     }
00493     // アニメーションの設定
00494     animation->setTargetName(name_);
00495     animation->setCharacterModelAnimationData(data);
00496     animation->setBoneCount(transBoneCount_);
00497     for(int i = 0; i < transBoneCount_; i++){
00498         animation->setBoneName(i, transBones_[i].getName());
00499     }
00500     animationSet->addAnimation(animation);
00501     // アニメーションデータの設定
00502     data->setBoneCount(transBoneCount_);
00503     int sequenceCount = sequence_.getSequenceCount();
00504     data->setSequenceCount(sequenceCount);
00505     for(int i = 0; i < sequenceCount; i++){
00506         int startTime = sequence_.getStartTime(i);
00507         int endTime = sequence_.getEndTime(i);
00508         for(int j = 0; j < transBoneCount_; j++){
00509             TranslationBone& bone = transBones_[j];
00510             // スケールアニメーション
00511             VectorInterpolator* scale =
00512                 bone.getScaleAnimation(startTime, endTime);
00513             if(scale != NULL){ data->setScale(i, j, scale); }
00514             // 回転アニメーション
00515             RotationInterpolator* rotation =
00516                 bone.getRotationAnimation(startTime, endTime);
00517             if(rotation != NULL){ data->setRotation(i, j, rotation); }
00518             // 移動アニメーション
00519             VectorInterpolator* translation =
00520                 bone.getTranslationAnimation(startTime, endTime);
00521             if(translation != NULL){ data->setTranslation(i, j, translation); }
00522         }
00523         data->setLooped(i, sequence_.isLooped(i));
00524     }
00525     return true;
00526 }
00527 //------------------------------------------------------------------------------
00528 } // End of namespace LampForMaya
00529 //------------------------------------------------------------------------------

Generated on Wed Mar 16 10:29:55 2005 for LampForMaya by doxygen 1.3.2