• Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By Jiraya
      For a 2D game, does using a float2 for position increases performance in any way?
      I know that in the end the vertex shader will have to return a float4 anyway, but does using a float2 decreases the amount of data that will have to be sent from the CPU to the GPU?
       
    • By ucfchuck
      I am feeding in 16 bit unsigned integer data to process in a compute shader and i need to get a standard deviation.
      So I read in a series of samples and push them into float arrays
      float vals1[9], vals2[9], vals3[9], vals4[9]; int x = 0,y=0; for ( x = 0; x < 3; x++) { for (y = 0; y < 3; y++) { vals1[3 * x + y] = (float) (asuint(Input1[threadID.xy + int2(x - 1, y - 1)].x)); vals2[3 * x + y] = (float) (asuint(Input2[threadID.xy + int2(x - 1, y - 1)].x)); vals3[3 * x + y] = (float) (asuint(Input3[threadID.xy + int2(x - 1, y - 1)].x)); vals4[3 * x + y] = (float) (asuint(Input4[threadID.xy + int2(x - 1, y - 1)].x)); } } I can send these values out directly and the data is as expected

                             
      Output1[threadID.xy] = (uint) (vals1[4] ); Output2[threadID.xy] = (uint) (vals2[4] ); Output3[threadID.xy] = (uint) (vals3[4] ); Output4[threadID.xy] = (uint) (vals4[4] ); however if i do anything to that data it is destroyed.
      If i add a
      vals1[4] = vals1[4]/2; 
      or a
      vals1[4] = vals[1]-vals[4];
      the data is gone and everything comes back 0.
       
       
      How does one go about converting a uint to a float and performing operations on it and then converting back to a rounded uint?
    • By fleissi
      Hey guys!

      I'm new here and I recently started developing my own rendering engine. It's open source, based on OpenGL/DirectX and C++.
      The full source code is hosted on github:
      https://github.com/fleissna/flyEngine

      I would appreciate if people with experience in game development / engine desgin could take a look at my source code. I'm looking for honest, constructive criticism on how to improve the engine.
      I'm currently writing my master's thesis in computer science and in the recent year I've gone through all the basics about graphics programming, learned DirectX and OpenGL, read some articles on Nvidia GPU Gems, read books and integrated some of this stuff step by step into the engine.

      I know about the basics, but I feel like there is some missing link that I didn't get yet to merge all those little pieces together.

      Features I have so far:
      - Dynamic shader generation based on material properties
      - Dynamic sorting of meshes to be renderd based on shader and material
      - Rendering large amounts of static meshes
      - Hierarchical culling (detail + view frustum)
      - Limited support for dynamic (i.e. moving) meshes
      - Normal, Parallax and Relief Mapping implementations
      - Wind animations based on vertex displacement
      - A very basic integration of the Bullet physics engine
      - Procedural Grass generation
      - Some post processing effects (Depth of Field, Light Volumes, Screen Space Reflections, God Rays)
      - Caching mechanisms for textures, shaders, materials and meshes

      Features I would like to have:
      - Global illumination methods
      - Scalable physics
      - Occlusion culling
      - A nice procedural terrain generator
      - Scripting
      - Level Editing
      - Sound system
      - Optimization techniques

      Books I have so far:
      - Real-Time Rendering Third Edition
      - 3D Game Programming with DirectX 11
      - Vulkan Cookbook (not started yet)

      I hope you guys can take a look at my source code and if you're really motivated, feel free to contribute :-)
      There are some videos on youtube that demonstrate some of the features:
      Procedural grass on the GPU
      Procedural Terrain Engine
      Quadtree detail and view frustum culling

      The long term goal is to turn this into a commercial game engine. I'm aware that this is a very ambitious goal, but I'm sure it's possible if you work hard for it.

      Bye,

      Phil
    • By tj8146
      I have attached my project in a .zip file if you wish to run it for yourself.
      I am making a simple 2d top-down game and I am trying to run my code to see if my window creation is working and to see if my timer is also working with it. Every time I run it though I get errors. And when I fix those errors, more come, then the same errors keep appearing. I end up just going round in circles.  Is there anyone who could help with this? 
       
      Errors when I build my code:
      1>Renderer.cpp 1>c:\users\documents\opengl\game\game\renderer.h(15): error C2039: 'string': is not a member of 'std' 1>c:\program files (x86)\windows kits\10\include\10.0.16299.0\ucrt\stddef.h(18): note: see declaration of 'std' 1>c:\users\documents\opengl\game\game\renderer.h(15): error C2061: syntax error: identifier 'string' 1>c:\users\documents\opengl\game\game\renderer.cpp(28): error C2511: 'bool Game::Rendering::initialize(int,int,bool,std::string)': overloaded member function not found in 'Game::Rendering' 1>c:\users\documents\opengl\game\game\renderer.h(9): note: see declaration of 'Game::Rendering' 1>c:\users\documents\opengl\game\game\renderer.cpp(35): error C2597: illegal reference to non-static member 'Game::Rendering::window' 1>c:\users\documents\opengl\game\game\renderer.cpp(36): error C2597: illegal reference to non-static member 'Game::Rendering::window' 1>c:\users\documents\opengl\game\game\renderer.cpp(43): error C2597: illegal reference to non-static member 'Game::Rendering::window' 1>Done building project "Game.vcxproj" -- FAILED. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========  
       
      Renderer.cpp
      #include <GL/glew.h> #include <GLFW/glfw3.h> #include "Renderer.h" #include "Timer.h" #include <iostream> namespace Game { GLFWwindow* window; /* Initialize the library */ Rendering::Rendering() { mClock = new Clock; } Rendering::~Rendering() { shutdown(); } bool Rendering::initialize(uint width, uint height, bool fullscreen, std::string window_title) { if (!glfwInit()) { return -1; } /* Create a windowed mode window and its OpenGL context */ window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL); if (!window) { glfwTerminate(); return -1; } /* Make the window's context current */ glfwMakeContextCurrent(window); glViewport(0, 0, (GLsizei)width, (GLsizei)height); glOrtho(0, (GLsizei)width, (GLsizei)height, 0, 1, -1); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glfwSwapInterval(1); glEnable(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glEnable(GL_TEXTURE_2D); glLoadIdentity(); return true; } bool Rendering::render() { /* Loop until the user closes the window */ if (!glfwWindowShouldClose(window)) return false; /* Render here */ mClock->reset(); glfwPollEvents(); if (mClock->step()) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glfwSwapBuffers(window); mClock->update(); } return true; } void Rendering::shutdown() { glfwDestroyWindow(window); glfwTerminate(); } GLFWwindow* Rendering::getCurrentWindow() { return window; } } Renderer.h
      #pragma once namespace Game { class Clock; class Rendering { public: Rendering(); ~Rendering(); bool initialize(uint width, uint height, bool fullscreen, std::string window_title = "Rendering window"); void shutdown(); bool render(); GLFWwindow* getCurrentWindow(); private: GLFWwindow * window; Clock* mClock; }; } Timer.cpp
      #include <GL/glew.h> #include <GLFW/glfw3.h> #include <time.h> #include "Timer.h" namespace Game { Clock::Clock() : mTicksPerSecond(50), mSkipTics(1000 / mTicksPerSecond), mMaxFrameSkip(10), mLoops(0) { mLastTick = tick(); } Clock::~Clock() { } bool Clock::step() { if (tick() > mLastTick && mLoops < mMaxFrameSkip) return true; return false; } void Clock::reset() { mLoops = 0; } void Clock::update() { mLastTick += mSkipTics; mLoops++; } clock_t Clock::tick() { return clock(); } } TImer.h
      #pragma once #include "Common.h" namespace Game { class Clock { public: Clock(); ~Clock(); void update(); bool step(); void reset(); clock_t tick(); private: uint mTicksPerSecond; ufloat mSkipTics; uint mMaxFrameSkip; uint mLoops; uint mLastTick; }; } Common.h
      #pragma once #include <cstdio> #include <cstdlib> #include <ctime> #include <cstring> #include <cmath> #include <iostream> namespace Game { typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; typedef float ufloat; }  
      Game.zip
    • By Ty Typhoon
      Before read everything i am honest:
      Payment after release you get your percentage lifetime for that project.
       
      Second:
      i dont need your inspirations, ideas, music or designs.
      My head is full with that.
      I need workers who i can trust.
       
       
       
      Please let us talk in discord.
      I got a lot of stuff planned, there is much work to do.
       
      But first my team and me try to start with a small mini game and we need maybe exactly you.
      Planned for more than pc, like ps4, xbox one and mobile - so its very important to us to hopefully welcome a programmer.
       
      The mini game will be part of the planned big game. There will be never before seen guns and gameplay, you will get deeper info if youre a safe part of the team.
       
      I need:
      Programmers
      Animators
      Zbrush pros
       
      Join here please:
      https://discord.gg/YtjE3sV
       
      You find me here:
      Joerg Federmann Composing#2898
       
       
  • Advertisement
  • Advertisement

C++ FBX SDK - Export Animation

Recommended Posts

Hello,

I have been fighting for sometime now with exporting animations from Maya to my own engine using DirectX 11.
I export the fbx file with all its content in it. 

So the problem i have is that the animation dosnt seem to rotate the joints correctly?

Please see the attached screenshots.
bindpose.png = Frame 1 (first keyframe is at frame 2), the bindpose, no animation applied.
frame30.png = Frame 30, rotation applied to two joints.
engine.png = Frame 30 of animation in engine, rotation != rotation in Maya :( 

I use my custom tool to export data from the fbx file using the fbx sdk.

The following is how i extract the skeleton bind pose and inverse bind pose transforms using fbx sdk:
(Note: freeze transformation have been applied to the mesh, so i ignore the geometry transform since its just an identity)

FbxAMatrix localTransform = p_Node->EvaluateLocalTransform();
joint->m_Location = localTransform.GetT();
joint->m_Scale = localTransform.GetS();
joint->m_Rotation = localTransform.GetQ();

FbxAMatrix inverseBindTransform = p_Node->EvaluateGlobalTransform().Inverse();
joint->m_InverseLocation = inverseBindTransform.GetT();
joint->m_InverseScale = inverseBindTransform.GetS();
joint->m_InverseRotation = inverseBindTransform.GetQ();

Then i extract information about each join for all keyframes, in this example i only sample rotation:

for( int i=0; i<rotationCurve->KeyGetCount(); ++i ) {
	FbxAnimCurveKey key = rotationCurve->KeyGet( i );
	FbxTime time = key.GetTime();
	FbxAMatrix transform = p_Node->EvaluateLocalTransform( time );
	// setup frame
	JointFrame frame;
	frame.m_IsRotation = true;
	frame.m_Frame = time.GetFrameCount( m_AnimFramerate );
	frame.m_Rotation = transform.GetQ();
	joint->m_RotationKeyframes.add( frame );
}

When i look at the rotation values from Maya i see that sometimes the axis of the quaternion is 0,0,0 assuming that the axis is mData[0-2].
So i must be doing something wrong here right?

Thats the fbx part.
Then in my engine i load the resources.

This is how i setup and update the skeleton transforms:
(Note: m_Rotation is a quaternion)

void pmJoint::computeMatrices( pmJoint * p_Parent ) {
	if( m_IsDirty ) {
		pmMath::matrixCreateTransform( &m_LocalTransform, m_Location, m_Scale, m_Rotation );
	}
	if( p_Parent ) {
		if( p_Parent->m_IsDirty || m_IsDirty ) {
			m_WorldTransform = m_LocalTransform * p_Parent->m_WorldTransform;
			m_IsDirty = true;
		}
	} else if( m_IsDirty ) {
		m_WorldTransform = m_LocalTransform;
	}
	for( pmUInt32 i=0; i<m_Children.count(); ++i ) {
		m_Children[ i ]->computeMatrices( this );
	}
}

So as you can see, all bones operate in their localspace using their parents world to update their world.
Then to get the render matrices i call this function:

void pmJoint::computeRenderMatrices() {
	m_RenderTransform = m_InversBindTransform * m_WorldTransform;
	for( pmUInt32 i=0; i<m_Children.count(); ++i ) {
		m_Children[ i ]->computeRenderMatrices();
	}
}

The animation part is simply lerping and slerping.
I get the problem no matter if i interpolate or just show keyframe poses, so i left that code out.
 

Any input, idea or crazy thought is welcome.
Im at a loss here.

bindpose.png

frame30.png

engine.png

Share this post


Link to post
Share on other sites
Advertisement

I really cannot help you with you code but I can paste what I'm using, and it works like a charm so far:

For the bind pose(offset) matrix.

fCluster->GetTransformMatrix(transformMatrix);
fCluster->GetTransformLinkMatrix(transformLinkMatrix);	
FbxAMatrix const globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix;


And then for the keyframes I use:
 

FbxAMatrix const tr = fbxNode->EvaluateLocalTransform(fbxKeyTime);

And then I decompose tr using the functions in FbxAMatrix (GetT, GetR, GetS)

It works with all  the pivots, geometric transfroms, and all that jazzy-stuff.

Share this post


Link to post
Share on other sites

Hey thanks for replying.

Im assuming you get your cluster from the FbxMesh right?
Do you know if there is a difference in going from the deformer instead of getting the node directly from the scene?
What im wondering is if the deformer has other functions or properties that does something that the node does not.

Also for the keyframes, do you use the child nodes from the deformer or how do you access them?
In my exporter im looping through the scene nodes, find a skeleton type node then iterate over all its children.

So what i can see right of the bat is that your are getting the bind pose from the deformer and im using the regular node.
Might be something?

I will have to do some tests when i get back home, thanks for sharing your example :) 

Share this post


Link to post
Share on other sites

 

Quote

Do you know if there is a difference in going from the deformer instead of getting the node directly from the scene?

There should be. Later in my code I obtain the node via the cluster:
 

Quote

fbxsdk::FbxCluster* const fCluster = fSkin->GetCluster(iCluster);
fbxsdk::FbxNode* const fNodeBone = fCluster->GetLink();

And later I extract the keyframes from "fNodeBone" to load the animation.


I do not use any skeletion nodes. I only use clusters to find the vertices, weights and the node that is used to represent the bone.

Edited by ongamex92

Share this post


Link to post
Share on other sites

Okey so now im using the cluster in the same maner you are regarding the inverse bind pose.
Also i now use the node from cluster->GetLink() to retreive the animation frame data.

And the result is the same :(

Rotation in frames is extracted like so:

FbxAMatrix transform = boneNode->EvaluateLocalTransform( time );
frame->m_Rotation = transform.GetQ();

So i dont use GetR but instead GetQ.
Is this a problem?

It must be something super simple. Everything looks right but its just not rotating all the way so to say..

Edit:
Also, i created a new mesh, new rig and new animation with less bones. Same problem. Are there some settings in Maya i need to be aware off maybe?

Edited by Noxil

Share this post


Link to post
Share on other sites

Could you share the model? if so I could try it in my importer and check the results?

 

Quote

So i dont use GetR but instead GetQ.

You should check if your quaternion has the same memory layout and meaning as the one in FBX SDK. I really can't remember why I'm using the euler angles. but here is how i convert the rotations form FBX euler angles to my internal quaterion types:
 

const FbxDouble3 fbxRotationEuler = tr.GetR();
const quatf rotation = quatFromFbx(FbxEuler::eOrderXYZ, fbxRotationEuler); // Hmmm. there is a function that returns the euler angles order, I do not know why I've hardcoded the eXYZ...

const quatf rotation = quatFromFbx(FbxEuler::eOrderXYZ, fbxRotationEuler);

// CAUTION: FBX SDK uses DEGREES this functon expects DEGREES!
// Converts an Euler angle rotation to quaternion.
quatf quatFromFbx(const fbxsdk::FbxEuler::EOrder rotationOrder, const fbxsdk::FbxDouble3& euler)
{
	const auto make_quat = [](int _1, int _2, int _3,  const fbxsdk::FbxDouble3& euler) {
		return
			  quatf::getAxisAngle(vec3f::getAxis(_3), Deg2Rad( (float)euler[_3] ) )
			* quatf::getAxisAngle(vec3f::getAxis(_2), Deg2Rad( (float)euler[_2] ) )
			* quatf::getAxisAngle(vec3f::getAxis(_1), Deg2Rad( (float)euler[_1] ) );
	};

	quatf result = quatf::getIdentity();

	switch(rotationOrder)
	{
		case fbxsdk::FbxEuler::eOrderXYZ : { result = make_quat(0,1,2, euler); } break;
		case fbxsdk::FbxEuler::eOrderXZY : { result = make_quat(0,2,1, euler); } break;
		case fbxsdk::FbxEuler::eOrderYZX : { result = make_quat(1,2,0, euler); } break;
		case fbxsdk::FbxEuler::eOrderYXZ : { result = make_quat(1,0,2, euler); } break;
		case fbxsdk::FbxEuler::eOrderZXY : { result = make_quat(2,0,1, euler); } break;
		case fbxsdk::FbxEuler::eOrderZYX : { result = make_quat(2,1,0, euler); } break;

		default :
		{
			throw FBXParseError("Unknown FBX rotation order!");
		}break;
	}

	return result;
}

 

Share this post


Link to post
Share on other sites

Hi, I post my code here which should be relatively simple and have another look later if you want. Basically I collect all skeleton nodes (bones) and then I read the animation from these nodes. The animation is stored as an array of poses (as opposed to an array of tracks). Another good reference is the Ozz Animation Library. In particular if you need to transform the coordinate system or units. The FBX library can mess things up since it only applies some transformation in the root. 

Quote

void RnAnimation::Read( FbxScene* Scene, FbxAnimStack* AnimStack )
    {
    // Collect nodes
    RnArray< FbxNode* > Nodes;
    Nodes.Reserve( Scene->GetNodeCount() );

    int Count = 0;
    FbxNode* Stack[ STACK_SIZE ];
    Stack[ Count++ ] = Scene->GetRootNode();

    while ( Count > 0 )
        {
        // Pop FBX source node
        FbxNode* Node = Stack[ --Count ];

        // Inspect node attributes
        FbxNodeAttribute* Attribute = Node->GetNodeAttribute();
        if ( Attribute && Attribute->GetAttributeType() == FbxNodeAttribute::eSkeleton )
            {
              Nodes.PushBack( Node );   
            }

        // Recurse
        for ( int Index = Node->GetChildCount() - 1; Index >= 0; --Index )
            {
            RN_ASSERT( Count < STACK_SIZE );
            Stack[ Count++ ] = Node->GetChild( Index );
            }
        }

    mTrackCount = Nodes.Size();
    mTrackNames.Reserve( mTrackCount );

    for ( FbxNode* Node : Nodes )
        {
        RnString NodeName = Node->GetNameOnly();
        mTrackNames.PushBack( NodeName );
        }

    // Process keyframes
    FbxString TakeName = AnimStack->GetName();
    FbxTakeInfo* TakeInfo = Scene->GetTakeInfo( TakeName );
    FbxTime::EMode TimeMode = FbxTime::GetGlobalTimeMode();
    FbxTime Start = TakeInfo->mLocalTimeSpan.GetStart(); 
    FbxLongLong StartFrame = Start.GetFrameCount( TimeMode );
    FbxTime Stop = TakeInfo->mLocalTimeSpan.GetStop();
    FbxLongLong StopFrame = Stop.GetFrameCount( TimeMode );

    FbxLongLong FrameCount = StopFrame - StartFrame;
    mFrameCount = static_cast< int >( FrameCount );
    double FrameRate = FbxTime::GetFrameRate( TimeMode );
    mFrameRate = static_cast< float >( FrameRate );
    
    int KeyCount = ( mFrameCount + 1 ) * mTrackCount;
    mTranslationKeys.Reserve( KeyCount );
    mRotationKeys.Reserve( KeyCount );
    mScaleKeys.Reserve( KeyCount );

    for ( FbxLongLong Frame = Start.GetFrameCount( TimeMode ); Frame <= Stop.GetFrameCount( TimeMode ); ++Frame )
        {
        FbxTime Time;
        Time.SetFrame( Frame, TimeMode );

        for ( FbxNode* Node : Nodes )
            {
            // Evaluate and decompose
            FbxAMatrix Transform = Node->EvaluateLocalTransform( Time );

            RnVector3 Translation( Transform.GetT() );
            mTranslationKeys.PushBack( Translation );
            RnQuaternion Rotation( Transform.GetQ() );
            mRotationKeys.PushBack( Rotation );
            RnVector3 Scale( Transform.GetS() );
            mScaleKeys.PushBack( Scale );
            }
        }
    }

 

Edited by DonDickieD

Share this post


Link to post
Share on other sites

Thank you both for your replies, i will make some tests regarding your posts.
As per request from ongamex92 i have attached the maya file and fbx file.

Edit:
Reuploaded .mlt file, it hade unsaved changes (dont know what they where)

anim_scene.fbx

 

anim_test.mlt

Edited by Noxil

Share this post


Link to post
Share on other sites

So i have tried some euler to quaternion with no success.
I get a another type of rotation, it dosnt rotate from the root bone any more but just slighly bends in the middle instead.
It looks further away from the direction i should be heading if i compare to the quaternion rotation.
But im not quite sure that i got it all right.

I did the quaternion multiplications myself, aswell as to use the DX11 function "XMQuaternionRotationRollPitchYaw".
They both gave the same result.

It feels like the quaternion i get from "GetQ" using "boneNode->EvaluateLocalTransform(time)" is not the correct value or something. 
When i load the frames and extract the quaternion in my engine. If i multiply the w component with 2.0f the animation seems to rotate almost to the point where it should.

Share this post


Link to post
Share on other sites

This is a long shot, but one thing I noticed with XNAMath/DirectXMath is that the quaternion multiplication is reversed. Say you two rotations q1 and q2. In usual quaternion notation q = q2 * q1 would apply q1 first followed by q2. If you are using XNAMath they changed that order to match the matrix multiplication So q = q1 * q2 is how you need to concatenate. E.g. see here for an explanation:

 https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.quaternion.xmquaternionmultiply(v=vs.85).aspx

So if you use the operator overload you might be in trouble. I am sure you know this already. Still I point this out since I have seen this issue before. IIRC the Maya SDK does similar things. Personally I hate this, but I can see what they are trying to do.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Advertisement