World of Warcraft Model Viewer

So I've started working on a model viewer for viewing WoW Models (from M2 files).  Several caveats here.  First, I'm fairly new at 3D modeling, and very new at using jMonkeyEngine.  Second, this project is very new.  I've done as good as I can to get it to where I'm at now, but don't expect much.  I've posted the project on Google Code here:



http://code.google.com/p/jwowmodelview



So why did I do this?  Well, contrary to what some might say, I didn't do it to use Blizzard's models in some project I'm doing.  I did it for several reasons, not the least being trying to understand how a successful company implements their models inside of a graphics engine.  As I mentioned above, I'm quite new to 3D graphics although I am an extremely seasoned Java engineer.



"Most" of the code is mine and mine alone, though I've borrowed some code pertaining to decoding the BLP files.  I've reworked most of it to be better documented, and have chosen to make it more readable as opposed to making it more efficient.  I figure efficiency can come later.



So with that out of the way, I've reached a point where I'm banging my head against the wall.  My test application that I've written loads a model successfully, creates the bone structure, attaches it and transforms the model according to the animation.  I've made the + and - keys tied to moving forward in the animation or moving backward in the animation.  Despite my best efforts, once the model is displayed the first time (at ANY time in the animation sequence) it deforms horribly.  Again, it displays the desired frame CORRECTLY.  It is only after that point that the model distorts depending on the animation frame sequence.



With that said, if anyone is interested in seeing the code it's posted at the above URL.  Beyond that, if someone has a solution to the problem I'm describing please let me know.  I've invested a lot of time into understanding how skeletal animation works, diving into the Blizzard file formats, contributing to the WoW dev wiki about what I've found, etc.  Getting the application running could be tricky, but I've posted a Wiki page at the Google Code repository describing the process.  I'd say the hardest part is simply extracting the files from the necessary MPQ archive, but once you've done that it should be fairly explanatory.

Here is an example of what the deer looks like after it loads.  I've turned on bone debugging, and, they look wrong but the deer renders perfectly with one leg slightly lifted off the ground (which is where time=0 puts it).

And here is what the deer looks like at time=1.  Say hello to "Mutant Deer."

? is there a wrong scaling when the joint animates ??

I'll check.  I'm pretty sure the scale is 1.0f the entire time as I don't think that scaling is used in this particular model.  Again, looking at the bones themselves, they "seem" odd looking, though, as I mentioned above, I can choose any start time frame and it will render the model correctly for that single frame.  I've compared what the model looks like to another model viewer and I can freeze that viewer and compare the models.  That's what is really strange.



EDIT

I actually forced the scaling to 1.0f and it still messes up.  Here's something else that is odd.  As mentioned multiple times, the initial rendering works perfectly.  However, even if I do NOT change the time (i.e. render the same frame over and over again) it still distorts.  It's almost like the bones, or the mesh/skin attached to the bones, is in a different state after the first frame is rendered.  Is there something I need to do to reset the bone/skin before doing the transformation?

Btw, this is the code that does the transformations:



   protected void updateBones (int animationSequence, int time) {
      for (int i = 0; i < theModel.getBones ().size (); i++) {
         M2Bone bone = theModel.getBones ().get (i);
         Bone jmeBone = jmeBoneList.get (i);

         javax.vecmath.Matrix4f mat = bone.calculateMatrix (animationSequence, time);
         if (mat != null) {
            javax.vecmath.Quat4f rot = new Quat4f ();
            javax.vecmath.Vector3f trans = new javax.vecmath.Vector3f ();
            mat.get (rot);
            mat.get (trans);
            jmeBone.setLocalRotation (new Quaternion (rot.getX (), rot.getY (), rot.getZ (), rot.getW ()));
            jmeBone.setLocalTranslation (trans.getX (), trans.getY (), trans.getZ ());
            jmeBone.setLocalScale (mat.getScale ());
         }
      }
   }

Actually, I think the issue may be in that method.  I'll investigate it further and post something if I locate it.

So no, what I thought might be the problem was not.  I created a "pair" object that maps the JME bone to the Bone coming in from the M2 file.  That way, I could iterate over the JME bones and then get the transformation matrix without having to perform another lookup.  Here's what the method looks like now:



   protected void updateBones (int animationSequence, int time) {
      //
      // Iterate over the skeleton's bone list and set the transformation for the
      // given animation sequence and time frame.
      //
      for (BonePair bonePair : this.jmeBoneList) {
         //
         // Get the transformation matrix for this bone.  This matrix comes from
         // the model's bone transformation.
         //
         javax.vecmath.Matrix4f mat = bonePair.m2Bone.calculateMatrix (animationSequence, time);
         if (mat != null) {
            //
            // Set the transformation for the given bone.
            //
            Bone jmeBone = bonePair.jmeBone;
            javax.vecmath.Quat4f rot = new Quat4f ();
            javax.vecmath.Vector3f trans = new javax.vecmath.Vector3f ();
            mat.get (rot);
            mat.get (trans);
            jmeBone.setLocalRotation (new Quaternion (rot.getX (), rot.getY (), rot.getZ (), rot.getW ()));
            jmeBone.setLocalTranslation (trans.getX (), trans.getY (), trans.getZ ());
            jmeBone.setLocalScale (mat.getScale ());
         }
      }
   }

Ok, so I found the bug in my code at the calcMatrix() code.  It was changing the pivot point of the bone.  I think it's close now, but after I set the bone's transformation, the model isn't updating.  This leads me to believe that it's probably something simple now related to calling some JME method to update the model after I've set the bone transformations.  More information when I have it…

Animation is working now!  By holding down the numpad + and - keys I can cycle through the animation successfully!  The next step is to do the animation interpolation between frames and it should be done.  The code is checked into Google Code if people want to see it.

Good work! Will this also incorporate blending between two animations?

Very nice work m8 :slight_smile:

There's no reason it couldn't move between animation sequences.  All of the necessary information is in the classes in my code, including how the animations go together.  My current task, though is to work through the interpolations so that the animation is smooth and fluid, and not jerky.

I totally agree with your reasons for making this, dont know how many times its been asked - how can i switch weapons, change colour of hair etc



Btw, where are the .m2 files ??

You need to extract your common.mpq file (check the wiki I put up on the google code site).  I didn't feel like writing my own MPQ decryptor though, I suppose I could have used the JNI wrapper to libmpq.  I wanted to get into the modeling part fast so I put that off.  Anyhow, once you extract the common.mpq file (or some other MPQ file), you'll find the m2 files inside of the folders.



Btw, there's still a glitch in the animation that I'm trying to track down.  It is still working "most" of the time.



EDIT

I think that my calculation of the bone transformation is causing the glitch.  I'm looking through some of the other model viewers to see if I can figure it out.  It "may" be that bone transformations are affected by the parent bone's transformation.  If anyone has any suggestions, please PM me or email me at squid6972@gmail.com.

Btw, in the jwmv.properties file there are several models commented out that I use for testing things.  Frog, deer, bombers, etc.  Feel free to play with that file to see what things look like.  I'm still trying to figure out why some animations are not completely correct.

It seems that when I have an animation frame with rotation only (i.e. no translation and no scaling) the returned matrix is in a state where getting the rotation quaternion out of it gives a quaternion where all values of the quaternion are NaN.  Has anyone ever seen this or does anyone have any idea why this might occur?  Thanks in advance.

Curious to what you have discovered from making this importer ??



Any reason to using java3d matrices and Quats


I actually removed that dependency.  It uses only the JME stuff now.

maybe have a look to our project …



http://taliis.blogpsot.com http://taliis.blogspot.com



we have a strong set of java classes for the file IO including an editor with easy to use plugin interface.

i would like to get in touch with you in order to maybe implement the m2 viewer somehow. maybe have a m2 viewer plugin as well :slight_smile: