//----------------------------------------------------------------------- void BaseInstanceBatchVTF::createVertexTexture( const SubMesh* baseSubMesh ) { /* TODO: Find a way to retrieve max texture resolution, http://www.ogre3d.org/forums/viewtopic.php?t=38305 Currently assuming it's 4096x4096, which is a safe bet for any hardware with decent VTF*/ size_t uniqueAnimations = mInstancesPerBatch; if (useBoneMatrixLookup()) { uniqueAnimations = std::min<size_t>(getMaxLookupTableInstances(), uniqueAnimations); } mMatricesPerInstance = std::max<size_t>( 1, baseSubMesh->blendIndexToBoneIndexMap.size() ); if(mUseBoneDualQuaternions && !mTempTransformsArray3x4) { mTempTransformsArray3x4 = OGRE_ALLOC_T(float, mMatricesPerInstance * 3 * 4, MEMCATEGORY_GENERAL); }
//----------------------------------------------------------------------- size_t InstanceBatchHW_VTF::calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const { size_t retVal = 0; RenderSystem *renderSystem = Root::getSingleton().getRenderSystem(); const RenderSystemCapabilities *capabilities = renderSystem->getCapabilities(); //VTF & HW Instancing must be supported if( capabilities->hasCapability( RSC_VERTEX_BUFFER_INSTANCE_DATA ) && capabilities->hasCapability( RSC_VERTEX_TEXTURE_FETCH ) ) { //TODO: Check PF_FLOAT32_RGBA is supported (should be, since it was the 1st one) const size_t numBones = std::max<size_t>( 1, baseSubMesh->blendIndexToBoneIndexMap.size() ); const size_t maxUsableWidth = c_maxTexWidthHW - (c_maxTexWidthHW % (numBones * mRowLength)); //See InstanceBatchHW::calculateMaxNumInstances for the 65535 retVal = std::min<size_t>( 65535, maxUsableWidth * c_maxTexHeightHW / mRowLength / numBones ); if( flags & IM_VTFBESTFIT ) { size_t numUsedSkeletons = mInstancesPerBatch; if (flags & IM_VTFBONEMATRIXLOOKUP) numUsedSkeletons = std::min<size_t>(getMaxLookupTableInstances(), numUsedSkeletons); const size_t instancesPerBatch = std::min( retVal, numUsedSkeletons ); //Do the same as in createVertexTexture(), but changing c_maxTexWidthHW for maxUsableWidth const size_t numWorldMatrices = instancesPerBatch * numBones; size_t texWidth = std::min<size_t>( numWorldMatrices * mRowLength, maxUsableWidth ); size_t texHeight = numWorldMatrices * mRowLength / maxUsableWidth; const size_t remainder = (numWorldMatrices * mRowLength) % maxUsableWidth; if( remainder && texHeight > 0 ) retVal = static_cast<size_t>(texWidth * texHeight / (float)mRowLength / (float)(numBones)); } } return retVal; }
//----------------------------------------------------------------------- size_t InstanceBatchHW_VTF::updateVertexTexture( Camera *camera, const Camera *lodCamera ) { MovableObjectArray *visibleObjects = 0; if( mManager->getInstancingThreadedCullingMethod() == INSTANCING_CULLING_SINGLETHREAD ) { //Perform the culling now ObjectData objData; const size_t numObjs = mLocalObjectMemoryManager.getFirstObjectData( objData, 0 ); visibleObjects = &mManager->_getTmpVisibleObjectsList()[0][mRenderQueueID]; visibleObjects->clear(); //TODO: Static batches aren't yet supported (camera ptr will be null and crash) MovableObject::cullFrustum( numObjs, objData, camera, camera->getLastViewport()->getVisibilityMask()&mManager->getVisibilityMask(), *visibleObjects, lodCamera ); } else { //Get the results from the time the threaded version ran. visibleObjects = &mCulledInstances; } bool useMatrixLookup = useBoneMatrixLookup(); if (useMatrixLookup) { //if we are using bone matrix look up we have to update the instance buffer for the //vertex texture to be relevant fillVertexBufferLUT( visibleObjects ); } //Now lock the texture and copy the 4x3 matrices! size_t floatsPerEntity = mMatricesPerInstance * mRowLength * 4; size_t entitiesPerPadding = (size_t)(mMaxFloatsPerLine / floatsPerEntity); mMatrixTexture->getBuffer()->lock( HardwareBuffer::HBL_DISCARD ); const PixelBox &pixelBox = mMatrixTexture->getBuffer()->getCurrentLock(); float *pDest = static_cast<float*>(pixelBox.data); if( mMeshReference->getSkeleton().isNull() ) { //No animations, no anything (perhaps HW Basic is a better technique for this case) std::for_each( visibleObjects->begin(), visibleObjects->end(), SendAllSingleTransformsToTexture( pDest, floatsPerEntity, entitiesPerPadding, mWidthFloatsPadding ) ); } else { if( !useMatrixLookup && !mUseBoneDualQuaternions ) { // Animations, normal std::for_each( visibleObjects->begin(), visibleObjects->end(), SendAllAnimatedTransformsToTexture( pDest, floatsPerEntity, entitiesPerPadding, mWidthFloatsPadding, mIndexToBoneMap ) ); } else if( mUseBoneDualQuaternions ) { // Animations, Dual Quaternion Skinning std::for_each( visibleObjects->begin(), visibleObjects->end(), SendAllDualQuatTexture( pDest, floatsPerEntity, entitiesPerPadding, mWidthFloatsPadding, mIndexToBoneMap ) ); } else { // Animations, LUT (lookup table) std::for_each( visibleObjects->begin(), visibleObjects->end(), SendAllLUTToTexture( pDest, floatsPerEntity, entitiesPerPadding, mWidthFloatsPadding, mIndexToBoneMap, getMaxLookupTableInstances() ) ); } } mMatrixTexture->getBuffer()->unlock(); return visibleObjects->size(); }