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 ); }
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; } }
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; }
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 ); }
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 }