Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 2 of 2

Thread: Skeletal Animation problem

  1. #1
    Intern Contributor
    Join Date
    Apr 2015
    Posts
    75

    Question Skeletal Animation problem

    Hello, i am having a really annoying problem with my skeletal animation implementation. First here is the situation. I have implemented COMPLETELY the very same skeletal animation in a C++ engine of mine i created a few months ago. Now i decided to redo the engine in Java. But since some libraries are missing for java i decided to actually make a "loader" inside my C++ engine and export the data for several models as a flat bin file with data, containing vertices, normals, uv etc. So far everything is working fine , OBJ and Collada files can be read from the file and displayed. My problems come with the animation. I am able to read the vertex information from the file (for the animated file), it contains standard per vertex data and boneIndex and boneWeight (also per vertex). The second file is the animation itself - a bunch of pre-calculated matrices
    The vertex information and the animation information are properly imported in Java (tripple checked). The model is rendering fine if i do not apply any animations to it.

    Here is the shader i am testing with (working fine in my old engine). If i flag the isAnimatedModel as false , the model is rendered as expected, without any animation applied and static. Which leads me to the conclusion that every bit of data up until the BoneID and BoneWeight is working fine. The problem that is occuring is comming either from gBones , BoneID or BoneWeight. My assumption is that the BoneID(which is an index data) is corrupted , screenshot below ! BoneID is a int[4] currently so ivec4 covers it
    Code :
     
    layout (location = 0) in vec3 Position; 
    layout (location = 1) in vec3 Normal;                                              
    layout (location = 2) in vec2 TexCoord;
    layout (location = 3) in vec3 Tangent;
    layout (location = 4) in float Tid; 
    layout (location = 5) in float Mid;  
    layout (location = 6) in ivec4 BoneIDs;
    layout (location = 7) in vec4 Weights;
     
    #include "Shaders/UtilityShaders/Consts.txt"
    #include "Shaders/UtilityShaders/Uniforms.txt"
    #include "Shaders/UtilityShaders/Shadow/vShadow.txt"
    #include "Shaders/UtilityShaders/Light/vLight.txt"
    #include "Shaders/UtilityShaders/Fog/vFog.txt"
     
    uniform float isAnimatedModel;
    uniform mat4 gBones[MAX_BONES];
     
    void main()
    {       
    	vec4 PosL = vec4(0.0);
    	vec4 NormalL = vec4(0.0);
    	mat4 gWorld = mTranslate;
    	mat4 gWVP = mProjection*mView;
     
    	if(isAnimatedModel > 0.5)
    	{
    		//ivec4 boneIDs = ivec4(int(BoneIDs[0] + 0.5),int(BoneIDs[1] + 0.5),int(BoneIDs[2] + 0.5),int(BoneIDs[3] + 0.5));
    		mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
    		BoneTransform     += gBones[BoneIDs[1]] * Weights[1];
    		BoneTransform     += gBones[BoneIDs[2]] * Weights[2];
    		BoneTransform     += gBones[BoneIDs[3]] * Weights[3];
    		PosL    = BoneTransform * vec4(Position, 1.0);
    		NormalL = BoneTransform * vec4(Normal, 0.0);
    	}
    	else {
    		PosL = vec4(Position, 1.0);
    		NormalL = vec4(Normal, 0.0);
    	}
    	vec4 worldPosition = gWorld * PosL;
        gl_Position  =  gWVP * worldPosition;

    The actual code from Java. The convert functions just take the contents of the List<DATA> and converts it to FloatBuffer or IntBuffer (for the BoneID).
    Code :
                    //Index Buffer stuff here
     
                    //VertexArrayObject (VAO class)
                    vertexArray.bindBuffer();
     
                    //All vertex data compacted in the vertexBuffer (VBO class)
                    vertexBuffer.bindBuffer();
     
                    //Load the VertexAttrixPointer offsets and all
    		loadToVertexPointer();
     
                    //Load the data from the vertexData to a float buffer
    		vertexBuffer.setBufferData(VertexData.convert(vertexData));
    		vertexBuffer.unbindBuffer();
     
                    //All BoneIndex and BoneWeight compacted in the boneBuffer (VBO class)
                    // At first i used only ONE buffer but i decided to divide the information
                    //since the BoneID is INT and BoneWeight is FLOAT
     
     
                    boneId.bindBuffer();
    		VertexPointer.enable(Constants.ATTRIB_LOCATION_BONEID);
     
                    //Set vertex attrib pointer as !! VertexAttribIPointer !! (here is where i assume is the problem) . 
                    //The odd thing is that in my C++ version it works standard (float)  VertexAttribPointer
    		VertexPointer.seti(Constants.ATTRIB_LOCATION_BONEID, 4, 16, 0);
     
    		int[] ids = BoneData.convertId(bonesData);
    		boneId.setBufferData(ids);
    		boneId.unbindBuffer();
     
    		boneWt.bindBuffer();
    		VertexPointer.enable(Constants.ATTRIB_LOCATION_WEIGHT);
     
                    //Standard (float)  VertexAttribPointer
    		VertexPointer.setf(Constants.ATTRIB_LOCATION_WEIGHT, 4, 16, 0);
     
    		float[] wts = BoneData.convertWt(bonesData);
    		boneWt.setBufferData(wts);
    		boneWt.unbindBuffer();
     
                    vertexArray.unbindBuffer();

    From my C++ version how this looks. Bone and Vertex states are just the VertexArrayPointer states

    Code :
            ibo->IBO_Bind();
    	ibo->IBO_BufferData(Indices.size(), Indices);
    	ibo->IBO_Unbind();
     
    	vao->VAO_Bind();
    	vertex_vbo->VBO_Bind();
    	vertex_vbo->VBO_BufferData(modeldata);
    	VertexState();
    	vertex_vbo->VBO_Unbind();
     
    	bone_vbo->VBO_Bind();
    	bone_vbo->VBO_BufferData(Bones);
    	BoneState();
    	bone_vbo->VBO_Unbind();
    	vao->VAO_Unbind();

    Animating the model. I am using a 3d array of matrices to store the animation.
    Matrix data -> [number_animations][animation_matrices_per_animation][bone_matrices]

    Code :
     
    private void shaderLoadAnimationBones() {
     
    		for (int i = 0; i < animationStack[index].length; i++) {
    			modelShader.loadUniformMat4f(animationStack[index][i], modelShader.getUniformId("gBones", i));
    		}
    	}
     
    	@Override
    	public void animate() {
    		// TODO Auto-generated method stub
    		if (!isAnimated) {
    			return;
    		}
     
    		if (currAnimation != prevAnimation) {
    			animationStack = ((ColladaData) modelData).getAnimationData()[currAnimation];
    		}
     
    		int size = animationStack.length;
    		runningTime += DisplayManager.getElapsedTime();
    		double timeInTicks = runningTime * Constants.TICKS_PER_SECOND;
    		double animationTime = timeInTicks % (size - 1);
    		index = (int) animationTime;
    	}

    The convert functions which i made to actually divide the data so i can load the boneIDs as IntBuffer and the boneWeights as FloatBuffer

    Code :
     
    private static void arrayToArray(float[] array, int[] src, MInteger startIndex) {
    		for (int i = 0; i < src.length; i++) {
    			array[startIndex.value++] = src[i];
    		}
    	}
     
    	private static void arrayToArray(int[] array, int[] src, MInteger startIndex) {
    		for (int i = 0; i < src.length; i++) {
    			array[startIndex.value++] = src[i];
    		}
    	}
    public static int[] convertId(List<BoneData> boneData) {
    		MInteger index = new MInteger();
    		int[] vertexDataResult = new int[Constants.NUM_BONES_PER_VEREX * boneData.size()];
     
    		for (BoneData vertex : boneData) {
    			arrayToArray(vertexDataResult, vertex.boneId, index);
    		}
    		return vertexDataResult;
    	}
     
    	public static float[] convertWt(List<BoneData> boneData) {
    		MInteger index = new MInteger();
    		float[] vertexDataResult = new float[Constants.NUM_BONES_PER_VEREX * boneData.size()];
     
    		for (BoneData vertex : boneData) {
    			arrayToArray(vertexDataResult, vertex.boneWeight, index);
    		}
    		return vertexDataResult;
    	}


    Last edited by Asmodeus; 12-29-2015 at 08:49 AM.

  2. #2
    Intern Contributor
    Join Date
    Apr 2015
    Posts
    75
    Short after this i just went and did this small change:
    From this: modelShader.loadUniform4f(animationStack[index][i], modelShader.getUniformId("gBones", i));
    To that: modelShader.loadUniform4fTransposed(animationStack[index][i], modelShader.getUniformId("gBones", i));

    Turns out that for some reason Assimp4x4Matrix (which i was using) are reversed major , i have no idea why this would work in my old engine as normal (non-trasposed matrix) I am actually confused here ! The animation works fine now ....

    http://gamedev.stackexchange.com/que...inning-problem

    Here is the man , who has only 1 vote and saved my day, thank you!

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •