コード例 #1
0
ファイル: animsequence.cpp プロジェクト: wdings23/gl-projects
static void matrixUpdateJob( void* pData )
{
    tMatrixJobData* pMatrixData = (tMatrixJobData *)pData;
    tVector4 const* pScale = pMatrixData->mpScale;
    //tJoint* pJoint = pMatrixData->mpJoint;
    
    // concat for animation matrix
    tMatrix44 posMatrix, scaleMatrix, rotMatrix, posRotMatrix;
    //quaternionToMatrix( &rotMatrix, pMatrixData->mpRotation );
    
    tMatrix44 rotMatZY, rotMatX, rotMatY, rotMatZ;
    Matrix44RotateX( &rotMatX, pMatrixData->mpRotationVec->fX );
    Matrix44RotateY( &rotMatY, pMatrixData->mpRotationVec->fY );
    Matrix44RotateZ( &rotMatZ, pMatrixData->mpRotationVec->fZ );
    
    Matrix44Multiply( &rotMatZY, &rotMatZ, &rotMatY );
    Matrix44Multiply( &rotMatrix, &rotMatZY, &rotMatX );
    
    
    Matrix44Scale( &scaleMatrix, pScale->fX, pScale->fY, pScale->fZ );
    Matrix44Translate( &posMatrix, pMatrixData->mpPosition );
    Matrix44Multiply( &posRotMatrix, &posMatrix, &rotMatrix );
    
    // result
    Matrix44Multiply( pMatrixData->mpResultMat, &posRotMatrix, &scaleMatrix );
    //Matrix44Multiply( pJoint->mpAnimMatrix, &posRotMatrix, &scaleMatrix );
}
コード例 #2
0
ファイル: gamerender.cpp プロジェクト: wdings23/gl-projects
static void updateJointMatricesNoJob( tAnimHierarchy* pAnimHierarchy,
                                      tMatrix44* aAnimMatrices )
{
    // update joint matrices in hierarchy
    // use worker threads
    int iJoint = 0;
    int iLevel = 0;
    for( ;; )
    {
        if( iJoint >= pAnimHierarchy->miNumJoints )
        {
            break;
        }
        
        tJoint* pJoint = &pAnimHierarchy->maJoints[iJoint];
        if( pJoint->miLevel > iLevel )
        {
            // update next level
            ++iLevel;
        }
        
        int iJointIndex = 0;
        int iNumHierarchyJoints = pAnimHierarchy->miNumJoints;
        for( iJointIndex = 0; iJointIndex < iNumHierarchyJoints; iJointIndex++ )
        {
            if( !strcmp( pAnimHierarchy->maJoints[iJointIndex].mszName, pJoint->mszName ) )
            {
                break;
            }
        }
        
        WTFASSERT2( iJointIndex < iNumHierarchyJoints, "can't find joint in hierarchy" );
        
        // transform
        tMatrix44 const* pParentMatrix = &gIdentityMat;
        if( pJoint->mpParent )
        {
            pParentMatrix = pJoint->mpParent->mpTotalMatrix;
        }
        
        // M(total) = M(parent) * M(local) * M(anim)
        tMatrix44 parentLocalMatrix;
        tMatrix44* pTotalMatrix = pJoint->mpTotalMatrix;
        tMatrix44* pSkinMatrix = pJoint->mpSkinMatrix;
        
        Matrix44Multiply( &parentLocalMatrix, pParentMatrix, pJoint->mpLocalMatrix );
        //Matrix44Multiply( pTotalMatrix, &parentLocalMatrix, pJoint->mpAnimMatrix );
        Matrix44Multiply( pTotalMatrix, &parentLocalMatrix, &aAnimMatrices[iJointIndex]);
        
        // M(skin) = M(total) * M(invPose)
        Matrix44Multiply( pJoint->mpSkinMatrix, pTotalMatrix, pJoint->mpInvPoseMatrix );
        
        // M(invTransposeSkin)
        tMatrix44 invSkinMatrix;
        Matrix44Inverse( &invSkinMatrix, pSkinMatrix );
        Matrix44Transpose( pJoint->mpInvTransSkinningMatrix, &invSkinMatrix );
        
        ++iJoint;
    }
}
コード例 #3
0
ファイル: Light.cpp プロジェクト: belzen/RenderLab
void LightList::QueueDraw(Renderer& rRenderer, const Sky& rSky, const Camera& rCamera, const float sceneDepthMin, const float sceneDepthMax,
	RdrLightingMethod lightingMethod, RdrLightResources* pOutResources)
{
	Camera lightCamera;
	int curShadowMapIndex = 0;
	int curShadowCubeMapIndex = 0;
	int shadowMapsThisFrame = 0;

	// Update shadow casting lights and the global light constants
	// todo: Choose shadow lights based on location and dynamic object movement
	GlobalLightData* pGlobalLights = (GlobalLightData*)RdrFrameMem::AllocAligned(sizeof(GlobalLightData), 16);

	// Temporarily add sky light to the light list.
	m_directionalLights.push(rSky.GetSunLight());

	for (uint i = 0, count = m_directionalLights.size(); i < count; ++i)
	{
		DirectionalLight& rDirLight = m_directionalLights[i];
		int remainingShadowMaps = MAX_SHADOW_MAPS - curShadowMapIndex - 1;
		const int kNumCascades = 4;
		if (remainingShadowMaps >= kNumCascades)
		{
			// Directional lights always change because they're based on camera position/rotation
			rDirLight.shadowMapIndex = curShadowMapIndex;

			Rect viewport(0.f, 0.f, (float)s_shadowMapSize, (float)s_shadowMapSize);
			float zMin = sceneDepthMin;
			float zMax = sceneDepthMax;
			float zDiff = (zMax - zMin);

			float nearDepth = zMin;
			float lamda = rSky.GetPssmLambda();

			for (int iPartition = 0; iPartition < kNumCascades; ++iPartition)
			{
				float zUni = zMin + (zDiff / kNumCascades) * (iPartition + 1);
				float zLog = zMin * powf(zMax / zMin, (iPartition + 1) / (float)kNumCascades);
				float farDepth = lamda * zLog + (1.f - lamda) * zUni;

				Vec3 center = rCamera.GetPosition() + rCamera.GetDirection() * ((farDepth + nearDepth) * 0.5f);
				Matrix44 lightViewMtx = getLightViewMatrix(center, rDirLight.direction);

				Quad nearQuad = rCamera.GetFrustumQuad(nearDepth);
				QuadTransform(nearQuad, lightViewMtx);

				Quad farQuad = rCamera.GetFrustumQuad(farDepth);
				QuadTransform(farQuad, lightViewMtx);

				Vec3 boundsMin(FLT_MAX, FLT_MAX, FLT_MAX);
				Vec3 boundsMax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
				accumQuadMinMax(nearQuad, boundsMin, boundsMax);
				accumQuadMinMax(farQuad, boundsMin, boundsMax);

				float height = (boundsMax.y - boundsMin.y);
				float width = (boundsMax.x - boundsMin.x);
				lightCamera.SetAsOrtho(center, rDirLight.direction, std::max(width, height), -500.f, 500.f);

				rRenderer.QueueShadowMapPass(lightCamera, m_shadowMapDepthViews[curShadowMapIndex], viewport);

				Matrix44 mtxView;
				Matrix44 mtxProj;
				lightCamera.GetMatrices(mtxView, mtxProj);
				pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Multiply(mtxView, mtxProj);
				pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Transpose(pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj);
				pGlobalLights->shadowData[curShadowMapIndex].partitionEndZ = (iPartition == kNumCascades - 1) ? FLT_MAX : farDepth;

				++shadowMapsThisFrame;
				++curShadowMapIndex;
				nearDepth = farDepth;
			}
		}
		else
		{
			rDirLight.shadowMapIndex = -1;
		}
	}

	for (uint i = 0, count = m_spotLights.size(); i < count; ++i)
	{
		SpotLight& rSpotLight = m_spotLights[i];
		int remainingShadowMaps = MAX_SHADOW_MAPS - curShadowMapIndex - 1;
		if (remainingShadowMaps)
		{
			Matrix44 mtxView;
			Matrix44 mtxProj;

			float angle = rSpotLight.outerConeAngle + Maths::DegToRad(5.f);
			lightCamera.SetAsPerspective(rSpotLight.position, rSpotLight.direction, angle * 2.f, 1.f, 0.1f, 1000.f);
			lightCamera.GetMatrices(mtxView, mtxProj);

			pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Multiply(mtxView, mtxProj);
			pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Transpose(pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj);

			Rect viewport(0.f, 0.f, (float)s_shadowMapSize, (float)s_shadowMapSize);
			rRenderer.QueueShadowMapPass(lightCamera, m_shadowMapDepthViews[curShadowMapIndex], viewport);

			rSpotLight.shadowMapIndex = curShadowMapIndex;
			++shadowMapsThisFrame;
			++curShadowMapIndex;
		}
		else
		{
			rSpotLight.shadowMapIndex = -1;
		}
	}

	for (uint i = 0, count = m_pointLights.size(); i < count; ++i)
	{
		PointLight& rPointLight = m_pointLights[i];
		int remainingShadowCubeMaps = MAX_SHADOW_CUBEMAPS - curShadowCubeMapIndex - 1;
		if (remainingShadowCubeMaps)
		{
			rPointLight.shadowMapIndex = curShadowCubeMapIndex + MAX_SHADOW_MAPS;

			Rect viewport(0.f, 0.f, (float)s_shadowCubeMapSize, (float)s_shadowCubeMapSize);
#if USE_SINGLEPASS_SHADOW_CUBEMAP
			rRenderer.QueueShadowCubeMapPass(rPointLight, m_shadowCubeMapDepthViews[curShadowCubeMapIndex], viewport);
#else
			for (uint face = 0; face < 6; ++face)
			{
				lightCamera.SetAsCubemapFace(light.position, (CubemapFace)face, 0.1f, light.radius * 2.f);
				rRenderer.QueueShadowMapPass(lightCamera, m_shadowCubeMapDepthViews[curShadowCubeMapIndex * 6 + face], viewport);
			}
#endif
			++shadowMapsThisFrame;
			++curShadowCubeMapIndex;
		}
		else
		{
			rPointLight.shadowMapIndex = -1;
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Apply resource updates
	RdrResourceCommandList* pResCommandList = rRenderer.GetActionCommandList();

	// Update spot lights
	SpotLight* pSpotLights = (SpotLight*)RdrFrameMem::Alloc(sizeof(SpotLight) * m_spotLights.size());
	memcpy(pSpotLights, m_spotLights.getData(), sizeof(SpotLight) * m_spotLights.size());
	if (!m_hSpotLightListRes)
		m_hSpotLightListRes = pResCommandList->CreateStructuredBuffer(pSpotLights, m_spotLights.capacity(), sizeof(SpotLight), RdrResourceUsage::Dynamic);
	else
		pResCommandList->UpdateBuffer(m_hSpotLightListRes, pSpotLights, sizeof(SpotLight) * m_spotLights.size());

	// Update point lights
	PointLight* pPointLights = (PointLight*)RdrFrameMem::Alloc(sizeof(PointLight) * m_pointLights.size());
	memcpy(pPointLights, m_pointLights.getData(), sizeof(PointLight) * m_pointLights.size());
	if (!m_hPointLightListRes)
		m_hPointLightListRes = pResCommandList->CreateStructuredBuffer(pPointLights, m_pointLights.capacity(), sizeof(PointLight), RdrResourceUsage::Dynamic);
	else
		pResCommandList->UpdateBuffer(m_hPointLightListRes, pPointLights, sizeof(PointLight) * m_pointLights.size());

	// Update environment lights
	EnvironmentLight* pEnvironmentLights = (EnvironmentLight*)RdrFrameMem::Alloc(sizeof(EnvironmentLight) * m_environmentLights.size());
	memcpy(pEnvironmentLights, m_environmentLights.getData(), sizeof(EnvironmentLight) * m_environmentLights.size());
	if (!m_hEnvironmentLightListRes)
		m_hEnvironmentLightListRes = pResCommandList->CreateStructuredBuffer(pEnvironmentLights, m_environmentLights.capacity(), sizeof(EnvironmentLight), RdrResourceUsage::Dynamic);
	else
		pResCommandList->UpdateBuffer(m_hEnvironmentLightListRes, pEnvironmentLights, sizeof(EnvironmentLight) * m_environmentLights.size());

	// Light culling
	if (lightingMethod == RdrLightingMethod::Clustered)
	{
		QueueClusteredLightCulling(rRenderer, rCamera);
	}
	else
	{
		QueueTiledLightCulling(rRenderer, rCamera);
	}

	// Update global lights constant buffer last so the light culling data is up to date.
	pGlobalLights->numDirectionalLights = m_directionalLights.size();
	pGlobalLights->globalEnvironmentLight = m_globalEnvironmentLight;
	pGlobalLights->clusterTileSize = m_clusteredLightData.clusterTileSize;
	memcpy(pGlobalLights->directionalLights, m_directionalLights.getData(), sizeof(DirectionalLight) * pGlobalLights->numDirectionalLights);
	m_hGlobalLightsCb = pResCommandList->CreateUpdateConstantBuffer(m_hGlobalLightsCb,
		pGlobalLights, sizeof(GlobalLightData), RdrCpuAccessFlags::Write, RdrResourceUsage::Dynamic);

	// Remove sky light.
	m_directionalLights.pop();


	// Fill out resource params
	pOutResources->hGlobalLightsCb = m_hGlobalLightsCb;
	pOutResources->hSpotLightListRes = m_hSpotLightListRes;
	pOutResources->hPointLightListRes = m_hPointLightListRes;
	pOutResources->hEnvironmentLightListRes = m_hEnvironmentLightListRes;
	pOutResources->hShadowCubeMapTexArray = m_hShadowCubeMapTexArray;
	pOutResources->hShadowMapTexArray = m_hShadowMapTexArray;
	pOutResources->hEnvironmentMapTexArray = m_hEnvironmentMapTexArray;
	pOutResources->hLightIndicesRes = (lightingMethod == RdrLightingMethod::Clustered) ? 
		m_clusteredLightData.hLightIndices : m_tiledLightData.hLightIndices;
}
コード例 #4
0
ファイル: animsequence.cpp プロジェクト: wdings23/gl-projects
void animSequencePlay( tAnimSequence const* pAnimSequence,
                       tAnimHierarchy const* pAnimHierarchy,
                       tVector4* aPositions,
                       tVector4* aScalings,
                       tQuaternion* aRotations,
                       tVector4* aRotationVecs,
                       tMatrix44* aAnimMatrices,
                       float fTime )
{
    float fNumLoops = floorf( fTime / pAnimSequence->mfLastTime );
    float fFrameTime = fTime - fNumLoops * pAnimSequence->mfLastTime;
    
    // key frame for the joints
    int iNumJoints = pAnimSequence->miNumJoints;
    for( int i = 0; i < iNumJoints; i++ )
    {
        int iStart = pAnimSequence->maiStartFrames[i];
        int iEnd = pAnimSequence->maiEndFrames[i];
        
        // no valid animation frame for this joint
        if( iStart < 0 || iEnd < 0 )
        {
            continue;
        }
     
        // find the ending frame
        int iEndFrame = iStart;
        for( iEndFrame = iStart; iEndFrame <= iEnd; iEndFrame++ )
        {
            if( pAnimSequence->mafTime[iEndFrame] > fFrameTime )
            {
                break;
            }
            
        }   // for end frame = start to end
        
        // didn't find end frame
        if( iEndFrame > iEnd )
        {
            iEndFrame = iEnd;
        }
        
        int iStartFrame = iEndFrame - 1;
        if( iStartFrame < 0 )
        {
            iStartFrame = 0;
        }
        
        // just at the start
        if( iStartFrame < iStart )
        {
            iStartFrame = iStart;
        }
        
        WTFASSERT2( iStartFrame >= iStart && iStartFrame <= iEnd, "out of bounds looking for start animation frame" );
        WTFASSERT2( iEndFrame >= iStart && iEndFrame <= iEnd, "out of bounds looking for end animation frame" );
        
        float fTimeDuration = pAnimSequence->mafTime[iEndFrame] - pAnimSequence->mafTime[iStartFrame];
        float fTimeFromStart = fFrameTime - pAnimSequence->mafTime[iStartFrame];
        float fPct = 0.0f;
        
        if( fTimeDuration > 0.0f )
        {
            fPct = fTimeFromStart / fTimeDuration;
        }
        
        // clamp pct
        if( fPct > 1.0f )
        {
            fPct = 1.0f;
        }
        
        Vector4Lerp( &aPositions[i],
                     &pAnimSequence->maPositions[iStartFrame],
                     &pAnimSequence->maPositions[iEndFrame],
                     fPct );
        
        Vector4Lerp( &aScalings[i],
                     &pAnimSequence->maScalings[iStartFrame],
                     &pAnimSequence->maScalings[iEndFrame],
                     fPct );
        
        quaternionSlerp( &aRotations[i],
                         &pAnimSequence->maRotation[iStartFrame],
                         &pAnimSequence->maRotation[iEndFrame],
                         fPct );
        
        Vector4Lerp( &aRotationVecs[i],
                     &pAnimSequence->maRotationVec[iStartFrame],
                     &pAnimSequence->maRotationVec[iEndFrame],
                     fPct );
        
#if 0
        tJoint* pJoint = pAnimSequence->mapJoints[iStart];
        
        tJob job;
        tKeyFrameJobData interpJobData;
        
        interpJobData.mfPct = fPct;
        interpJobData.mpPos0 = &pAnimSequence->maPositions[iStartFrame];
        interpJobData.mpPos1 = &pAnimSequence->maPositions[iEndFrame];
        interpJobData.mpScale0 = &pAnimSequence->maScalings[iStartFrame];
        interpJobData.mpScale1 = &pAnimSequence->maScalings[iEndFrame];
        interpJobData.mpRot0 = &pAnimSequence->maRotation[iStartFrame];
        interpJobData.mpRot1 = &pAnimSequence->maRotation[iEndFrame];
        interpJobData.mpResultPos = &aPositions[i];
        interpJobData.mpResultScale = &aScalings[i];
        interpJobData.mpResultRot = &aRotations[i];
        interpJobData.mpJoint = pJoint;
        
        interpJobData.mpRotVec0 = &pAnimSequence->maRotationVec[iStartFrame];
        interpJobData.mpRotVec1 = &pAnimSequence->maRotationVec[iEndFrame];
        interpJobData.mpResultRotVec = &aRotationVecs[i];
        
        job.mpfnFunc = interpolateJob;
        job.mpData = &interpJobData;
        job.miDataSize = sizeof( tKeyFrameJobData );
        
        jobManagerAddJob( gpJobManager, &job );
#endif // #if 0
    }

#if 0
        tVector4* pScale = &aScalings[i];
        tVector4* pPosition = &aPositions[i];
        
        // interpolate position, scale, and rotation
        Vector4Lerp( pPosition,
                     &pAnimSequence->maPositions[iEndFrame],
                     &pAnimSequence->maPositions[iStartFrame],
                     fPct );
        
        Vector4Lerp( pScale,
                     &pAnimSequence->maScalings[iEndFrame],
                     &pAnimSequence->maScalings[iStartFrame],
                     fPct );
        
        quaternionSlerp( &aRotations[i],
                         &pAnimSequence->maRotation[iEndFrame],
                         &pAnimSequence->maRotation[iStartFrame],
                         fPct );
    
    jobManagerWait( gpJobManager );
#endif // #if 0
    
    for( int i = 0; i < iNumJoints; i++ )
    {
        int iStart = pAnimSequence->maiStartFrames[i];
        int iEnd = pAnimSequence->maiEndFrames[i];
        
        // no valid animation frame for this joint
        if( iStart < 0 || iEnd < 0 )
        {
            continue;
        }
        
#if 0
        tJob job;
        tMatrixJobData matrixJobData;
        matrixJobData.mpPosition = &aPositions[i];
        matrixJobData.mpRotation = &aRotations[i];
        matrixJobData.mpScale = &aScalings[i];
        matrixJobData.mpResultMat = &aAnimMatrices[i];
        matrixJobData.mpJoint = pAnimSequence->mapUniqueJoints[i];
        
        matrixJobData.mpRotationVec = &aRotationVecs[i];
        
        job.mpfnFunc = &matrixUpdateJob;
        job.mpData = &matrixJobData;
        job.miDataSize = sizeof( tMatrixJobData );
        
        jobManagerAddJob( gpJobManager, &job );
#endif // #if 0
        
        tMatrix44 posMatrix, scaleMatrix, rotMatrix, posRotMatrix;
        //quaternionToMatrix( &rotMatrix, pMatrixData->mpRotation );
        
        tMatrix44 rotMatZY, rotMatX, rotMatY, rotMatZ;
        Matrix44RotateX( &rotMatX, aRotationVecs[i].fX );
        Matrix44RotateY( &rotMatY, aRotationVecs[i].fY );
        Matrix44RotateZ( &rotMatZ, aRotationVecs[i].fZ );
        
        Matrix44Multiply( &rotMatZY, &rotMatZ, &rotMatY );
        Matrix44Multiply( &rotMatrix, &rotMatZY, &rotMatX );
        
        
        Matrix44Scale( &scaleMatrix, aScalings[i].fX, aScalings[i].fY, aScalings[i].fZ );
        Matrix44Translate( &posMatrix, &aPositions[i] );
        Matrix44Multiply( &posRotMatrix, &posMatrix, &rotMatrix );
        
        Matrix44Multiply( &aAnimMatrices[i], &posRotMatrix, &scaleMatrix );
        
#if 0
        // concat for animation matrix
        tMatrix44 posMatrix, scaleMatrix, rotMatrix, posRotMatrix;
        quaternionToMatrix( &rotMatrix, &aRotations[i] );
        Matrix44Scale( &scaleMatrix, pScale->fX, pScale->fY, pScale->fZ );
        Matrix44Translate( &posMatrix, pPosition );
        Matrix44Multiply( &posRotMatrix, &posMatrix, &rotMatrix );
        
        tMatrix44* pAnimMatrix = &aAnimMatrices[i];
        Matrix44Multiply( pAnimMatrix, &posRotMatrix, &scaleMatrix );
#endif // #if 0
        
    }   // for i = 0 to num joints
    
    jobManagerWait( gpJobManager );
}
コード例 #5
0
ファイル: animsequence.cpp プロジェクト: wdings23/gl-projects
void animSequenceUpdateAnimMatrices( tAnimSequence const* pAnimSequence,
                                     tAnimHierarchy const* pAnimHierarchy,
                                     tVector4* aPositions,
                                     tVector4* aScalings,
                                     tQuaternion* aRotations,
                                     tVector4* aRotationVecs,
                                     tMatrix44* aAnimMatrices )
{
    int iNumJoints = pAnimSequence->miNumJoints;
    for( int i = 0; i < iNumJoints; i++ )
    {
        int iStart = pAnimSequence->maiStartFrames[i];
        int iEnd = pAnimSequence->maiEndFrames[i];
        
        // no valid animation frame for this joint
        if( iStart < 0 || iEnd < 0 )
        {
            continue;
        }
        
        tJoint* pJoint = pAnimSequence->mapJoints[iStart];
        
        // get corresponding joint index from hierarchy
        int iJointIndex = 0;
        int iNumHierarchyJoints = pAnimHierarchy->miNumJoints;
        for( iJointIndex = 0; iJointIndex < iNumHierarchyJoints; iJointIndex++ )
        {
            if( !strcmp( pAnimHierarchy->maJoints[iJointIndex].mszName, pJoint->mszName ) )
            {
                break;
            }
        }
        
        WTFASSERT2( iJointIndex < iNumHierarchyJoints, "can't find corresponding joint" );
        
        tMatrix44 posMatrix, scaleMatrix, rotMatrix, posRotMatrix;
        //quaternionToMatrix( &rotMatrix, pMatrixData->mpRotation );
        
        tMatrix44 rotMatZY, rotMatX, rotMatY, rotMatZ;
        Matrix44RotateX( &rotMatX, aRotationVecs[i].fX );
        Matrix44RotateY( &rotMatY, aRotationVecs[i].fY );
        Matrix44RotateZ( &rotMatZ, aRotationVecs[i].fZ );
        
        Matrix44Multiply( &rotMatZY, &rotMatZ, &rotMatY );
        Matrix44Multiply( &rotMatrix, &rotMatZY, &rotMatX );
        
        
        Matrix44Scale( &scaleMatrix, aScalings[i].fX, aScalings[i].fY, aScalings[i].fZ );
        Matrix44Translate( &posMatrix, &aPositions[i] );
        Matrix44Multiply( &posRotMatrix, &posMatrix, &rotMatrix );
        
        Matrix44Multiply( &aAnimMatrices[iJointIndex], &posRotMatrix, &scaleMatrix );
        
#if 0
        tJob job;
        tMatrixJobData matrixJobData;
        matrixJobData.mpPosition = &aPositions[i];
        matrixJobData.mpRotation = &aRotations[i];
        matrixJobData.mpScale = &aScalings[i];
        matrixJobData.mpResultMat = &aAnimMatrices[iJointIndex];
        matrixJobData.mpJoint = pAnimSequence->mapUniqueJoints[i];
        
        matrixJobData.mpRotationVec = &aRotationVecs[i];
        
        job.mpfnFunc = &matrixUpdateJob;
        job.mpData = &matrixJobData;
        job.miDataSize = sizeof( tMatrixJobData );
        
        jobManagerAddJob( gpJobManager, &job );
#endif // #if 0
                
    }   // for i = 0 to num joints
}