Animation Editor

Started by aZen, November 06, 2012, 05:41:21 PM

Previous topic - Next topic

aZen

Hey there!

I have to admit I'm a bit lost right now, so I'm hoping for some awesome advice!

Here is my situation: I've written a 3D modelling program in JPCT (works really great) and I want to use bone animation to animate the objects that are modeled. The user can already set the initial bone frame of the object and then define key-frames that lead to animations. This is in theory, because I have no idea how to link the "bones" to the actual objects in the world.

What I have right now:
1) Plenty of objects in the world
2) Connected lines that are the bones
3) Different frames for these "bones"

How do I link all the objects in the world to those "bones" (they're just a list of dots and connections right now) and animate them?

Don't get me wrong, I'm not looking for a full fledged solution. Just want a starting point. I browsed through the samples, but couldn't find what I needed.

Thank you very much,
aZen

raft

sorry for late answer, somehow notification mail didnt arrive :/

you can do that in theory. you can programatically create animation and assign that to AnimatedGroup or Animated3D's. CreatePoseAnimationSample does that for pose animation.

here are the steps briefly for skeletal animation
* create a MeshData to define your model
* create a Skeleton which consists of Joint's
* create a SkeletonPose
* create a SkinData to define how skeleton joints effect mesh
* create an Animated3D with MeshData, SkinData and SkeletonPose
* create JointChannel's for Joint's to define movements and rotations of Joint during animation
* create a SkinClip out of that JointChannel's. that's a single animation
* create a SkinClipSequence out of one or more SkinClip's and assign that to Animated3D or AnimatedGroup


aZen

#2
Hey raft!

Thank you for the reply. I will start working on this today and see how far I get.

**Will edit this post when I have something to show

Regards,
aZen

_______________________________
***Update***

I'm now trying to put everything together. However I have a lot of questions:

1)
Could you please explain what variables the MeshData constructor requires? It is not explained in the JavaDocs. How would you generate this information from the World or the World objects? Or is that not possible?

Reference: http://aptalkarga.com/bones/api/raft/jpct/bones/MeshData.html

2)
To contruct Skeleton, we need to create a Joint array. Could you please explain what is expected for the first argument in the Joint constructor (Matrix)?

Reference: http://aptalkarga.com/bones/api/raft/jpct/bones/Joint.html

3)
As far as I understand the SkeletonPose is a wrapper for Skeleton. I thought I need to define one SkeletonPose for each key frame of the animation (while using the same Skeleton). But that wouldn't make sense with what I gathered below. Could you please explain what SkeletonPose is used for? Is it just a wrapper for "internal things"?

Reference: http://aptalkarga.com/bones/api/raft/jpct/bones/SkeletonPose.html

4)
What do the parameters look like for the SkinData? I can think of multiple ways and would prefere not to use try and error :)

Reference: http://aptalkarga.com/bones/api/raft/jpct/bones/SkinData.html

5)
All right, let's assume I have created the Animated3D. As I understand I just need to create this once. If I have different animations (e.g. walking, jumping, crawling, etc), I just attach different SkinClipSequence to the Animated3D. Can I attach several at once and then change between them?
In the java doc it is written that Animated3D is an Object3D. So I don't need to add anything else to the world to display it? But then how do I color it or add textures?
I have currently a lot of objects with different texture in the world that I want to animate as a whole. Can I make things simpler with using AnimatedGroup?

References:
http://aptalkarga.com/bones/api/raft/jpct/bones/Animated3D.html
http://aptalkarga.com/bones/api/raft/jpct/bones/AnimatedGroup.html

6)
Just making sure I understand correctly: I define a JointChannel for each Joint. This defines how the joint changes from state A to state B. And those JointChannel are then summarized in the SkinClip, which defines the transition from one key frame to another. These transitions are summerized in SkinClipSequence (an animation, e.g. "attack", for our object), which itself can be attached to the Animated3D object.

References:
http://aptalkarga.com/bones/api/raft/jpct/bones/SkinClipSequence.html
http://aptalkarga.com/bones/api/raft/jpct/bones/SkinClip.html
http://aptalkarga.com/bones/api/raft/jpct/bones/JointChannel.html

7)
When I'm done with all these things, would I be able to export everything easily to a file (Collada or Ogre)?

I'm still learning a lot about these things, so feel free to direct me to any additional material that you think might be helpful!

Thank you,
aZen

raft

please do not edit your post for your questions, i'm not notified of it, just post another message. in this case, I've seen your edit accidentally

a question first: why are you trying to make your own 3D editor instead of using a well known one?

Quote
1)
Could you please explain what variables the MeshData constructor requires? It is not explained in the JavaDocs. How would you generate this information from the World or the World objects? Or is that not possible?

those arguments are explained in Object[] constructor, have a look at the "see also" link.

Quote
2)
To contruct Skeleton, we need to create a Joint array. Could you please explain what is expected for the first argument in the Joint constructor (Matrix)?
that's inverse bind pose of joint (bone) as the documents say. that's a fundemental thing in skeletal animation, google for it

Quote
3)
As far as I understand the SkeletonPose is a wrapper for Skeleton. I thought I need to define one SkeletonPose for each key frame of the animation (while using the same Skeleton). But that wouldn't make sense with what I gathered below. Could you please explain what SkeletonPose is used for? Is it just a wrapper for "internal things"?
SkeletonPose is not really a wrapper. It's a pose of skeleton as its name suggests. animation puts SkeletonPose into a certain position and that's used to deform mesh (apply animation) accordingly. have a look at SkinClip.applyTo(..)  and Animated3D.applySkeletonPose(). Animated3D.animateSkin(..) does both of them behind the scenes.

Quote
4)
What do the parameters look like for the SkinData? I can think of multiple ways and would prefere not to use try and error :)
a vertex can be deformed by up to 4 joints and each joint has a weight for this deformation. ie: how much vertex will be effected from joint's translation and rotation. SkinData defines this: first index in both arguments is vertex index. second index define joint weight and corresponding joint index.

Quote
5)
All right, let's assume I have created the Animated3D. As I understand I just need to create this once. If I have different animations (e.g. walking, jumping, crawling, etc), I just attach different SkinClipSequence to the Animated3D. Can I attach several at once and then change between them?
In the java doc it is written that Animated3D is an Object3D. So I don't need to add anything else to the world to display it? But then how do I color it or add textures?
I have currently a lot of objects with different texture in the world that I want to animate as a whole. Can I make things simpler with using AnimatedGroup?
each SkinClip is a different animation (walk, jump etc) and we put many SkinClip's into a SkinClipSequence. so yes, you can attach several animations at once.

you can set texture via to Animated3D.settexture(..) method (inherited from Object3D). there is no setColor method.

AnimatedGroup is meant to pull multi-mesh objects into a single entity. yes, you can use it for your complete scene.

Quote
6)
Just making sure I understand correctly: I define a JointChannel for each Joint. This defines how the joint changes from state A to state B. And those JointChannel are then summarized in the SkinClip, which defines the transition from one key frame to another. These transitions are summerized in SkinClipSequence (an animation, e.g. "attack", for our object), which itself can be attached to the Animated3D object.
not really. JointChannel defines transitions from keyframe to another for a single joint. SkinClip pulls several JointChannel's together and defines a single animation for all of the joints (whole skeleton). and finally SkinClipSequence is one or more animations (SkinClip's)

Quote
7)
When I'm done with all these things, would I be able to export everything easily to a file (Collada or Ogre)?
Bones does not include any code for exporting. You need to write your own exporter, or use code of an existing one

Quote
I'm still learning a lot about these things, so feel free to direct me to any additional material that you think might be helpful!
skeletal animation is a complex subject, especially the calculations. prepare yourself to hit your head to walls ;) but again, why are you doing this instead of using a well known 3D editor?

aZen

That was a fast response, thank you!

As to why I'm doing this: The 3D editor is actually built for "ease of use", to create a specific art style. Once the company decides to release it to the public, I will post a link here and you will understand much better.

I really appreciate that you are investing this time to help me and will try to keep the stupid questions to a minimum! This should be fun after all.

And yes, I know that skeleton animation is a complex subject, but I have a strong math background and I love challenges. Also my head-to-wall threshold is quite high :)

raft

fair enough. good luck then ;) feel free to ask questions..

aZen

Hey, I'm back :)

So here is what I've got so far (just trying to get a really simple testcase working). Unfortunately I'm not sure how to animate it now (it always crashes when I try to call animate). Could you please have a look at it?

Thank you very much!
aZen

package vitco;

import com.threed.jpct.*;
import raft.jpct.bones.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
* The main class.
*/
public class Main extends WindowAdapter implements MouseMotionListener {

    static FrameBuffer buffer;
    static World world;
    Object3D box;
    JFrame frame;

    Animated3D animated3D;

    public Main() {
        // set up frame
        frame = new JFrame("Hello Animation!");
        frame.setSize(800, 600);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

        // set up world
        world = new World();
        world.setAmbientLight(0, 0, 0);
        world.addLight( new SimpleVector( 500,-500,500),new Color(20,20,20) );
        Config.fadeoutLight = false;

        // ==========================

        // 1) create mesh data
        MeshData meshData = new MeshData(
                        // coordinates of the vertices
                        new float[] {10, 0, 0, 0, 10, 0, 0, 0, 10},
                        // uv texture coordinates of the vertices
                        new float[] {0, 0, 1, 0, 0, 1},
                        // assigned indices to identify the vertices
                        new int[] {0, 1, 2});

        // 2) create a Skeleton which consists of Joint's
        Matrix matrix = new Matrix();
        matrix.rotateX((float) (Math.PI/2));
        matrix = matrix.invert();
        Skeleton skeleton = new Skeleton(
                new Joint[]{
                        // Note: # is joint index (not vertex index!)
                        // matrix, id, parent joint, name
                        new Joint(matrix, 0, Joint.NO_PARENT, null),
                        new Joint(matrix, 1, Joint.NO_PARENT, null),
                        new Joint(matrix, 2, Joint.NO_PARENT, null),
                }
        );

        // 3) create a SkeletonPose
        SkeletonPose skeletonPos = new SkeletonPose(skeleton);

        // 4) create a SkinData to define how skeleton joints effect mesh
        SkinData skin = new SkinData(
                new float[][] {
                        // vertex index -> weight
                        new float[]{0.5f,0.5f},
                        new float[]{1f},
                        new float[]{1f}
                },
                new short[][]{
                        // vertex index -> joint index
                        new short[]{0,1},
                        new short[]{1},
                        new short[]{2}
                });

        // 5) create an Animated3D with MeshData, SkinData and SkeletonPose
        animated3D = new Animated3D(meshData, skin, skeletonPos);

        // 6) create JointChannel's for Joint's to define movements and rotations of Joint during animation
        // joint index, times, translation, rotation, scales
        JointChannel jointChannel = new JointChannel(0,
                new float[]{1, 1},
                new SimpleVector[]{new SimpleVector(1,0,0), new SimpleVector(0,1,0)},
                new Quaternion[]{Quaternion.IDENTITY, Quaternion.IDENTITY},
                new SimpleVector[]{new SimpleVector(1, 1, 1), new SimpleVector(1, 1, 1)}
        );

        // 7) create a SkinClip out of that JointChannel's. that's a single animation
        SkinClip skinClip = new SkinClip(skeleton, jointChannel);

        // 8) create a SkinClipSequence out of one or more SkinClip's and assign that to Animated3D or AnimatedGroup
        SkinClipSequence skinClipSequence = new SkinClipSequence(skinClip);
        animated3D.setSkinClipSequence(skinClipSequence);

        animated3D.setAdditionalColor(Color.RED);
        animated3D.setEnvmapped(Object3D.ENVMAP_ENABLED);
        animated3D.setShadingMode(Object3D.SHADING_FAKED_FLAT);
        animated3D.setCulling(false);
        animated3D.rotateY(3f);
        animated3D.build();

        world.addObject(animated3D);

        // ==========================

        // set up camera
        world.getCamera().setPosition(50, -50, -5);
        world.getCamera().lookAt(SimpleVector.ORIGIN);

        // set up frame buffer
        buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_NORMAL);

        // set up event handler
        frame.addMouseMotionListener(this);
        frame.addWindowListener(this);
    }

    @Override
    public void windowClosing(WindowEvent e) {
        // clean up when closing
        buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
        buffer.dispose();
        frame.dispose();
        System.exit(0);
    }

    @Override
    public void mouseDragged(MouseEvent e) {}

    private int value = 0;

    @Override
    public void mouseMoved(MouseEvent e) {
        // animate and redraw
        buffer.clear(Color.LIGHT_GRAY);
        world.renderScene(buffer);
        world.draw(buffer);
        buffer.update();
        buffer.display(frame.getGraphics());
    }

    // constructor
    public static void main (String[] args) {
        new Main();
    }


}

raft

post the exception please..

aZen

Wohoo, I finally got it to work. The problem was that I didn't (don't?) understand how the SkinData constructor is used. Apparently you have to use all four weighted joints (even if the weight on the others is zero).

Will come back with a more structured example (and possible one or the other question)!

Thanks :)

aZen

#9
Things are looking pretty solid!

Only one question so far: When I enable setShadingMode(Object3D.SHADING_FAKED_FLAT), the texture is not drawn (the triangles are just black). Is that by design?

Edit: Nvm, that's related to jpct. See here: http://www.jpct.net/forum2/index.php/topic,3394.0.html

raft

yes, that is not related to Bones ;)