hkpShape* vHavokShapeFactory::CreateConvexShapeFromStaticMeshInstances(const VisStaticMeshInstCollection &meshInstances, hkvMat4 &refTransform, bool shrinkByCvxRadius) { VVERIFY_OR_RET_VAL(meshInstances.GetLength()==1, NULL); // Get the collision mesh for the static mesh instance VisStaticMeshInstance_cl *pMeshInstance = meshInstances[0]; VisStaticMesh_cl *pMesh = pMeshInstance->GetMesh(); IVCollisionMesh *pColMesh = pMesh->GetCollisionMesh(true, true); VVERIFY_OR_RET_VAL(pColMesh!=NULL, NULL); // We transform each static mesh into the reference space. hkvMat4 mTransform = refTransform; mTransform = mTransform.multiply (pMeshInstance->GetTransform()); hkGeometry geom; int iNumColMeshes = hkvMath::Max(pColMesh->GetSubmeshCount(), 1); for (int i=0;i<iNumColMeshes;i++) BuildGeomFromCollisionMesh(pColMesh, i, mTransform, false, geom); // Set the build configuration to set planes equations and connectivity automatically hkpConvexVerticesShape::BuildConfig config; config.m_createConnectivity = true; config.m_shrinkByConvexRadius = shrinkByCvxRadius; hkStridedVertices stridedVerts; stridedVerts.m_numVertices = geom.m_vertices.getSize(); stridedVerts.m_striding = sizeof(hkVector4); stridedVerts.m_vertices = (const hkReal*)geom.m_vertices.begin(); // Create convex shape hkvConvexVerticesShape *pConvexShape = new hkvConvexVerticesShape(pColMesh->GetFileTime(), stridedVerts, config); return pConvexShape; }
void VMeshPaintingComponent::MarkOwnerBoundingBoxDirty() { if (g_bComponentsThroughUI) return; VisStaticMeshInstance_cl *pMesh = (VisStaticMeshInstance_cl *)GetOwner(); if (pMesh==NULL) return; m_CurrentBBox = pMesh->GetBoundingBox(); VEditableTerrain::AddDirtyVegetationRangeAllTerrains(m_CurrentBBox); }
void VMeshPaintingComponent::OnOwnerTransformationChanged() { VisStaticMeshInstance_cl *pMesh = (VisStaticMeshInstance_cl *)GetOwner(); if (pMesh==NULL) return; // old and new location is dirty hkvAlignedBBox newBBox = pMesh->GetBoundingBox(); if (newBBox!=m_CurrentBBox) { if (newBBox.isValid()) VEditableTerrain::AddDirtyVegetationRangeAllTerrains(newBBox); if (m_CurrentBBox.isValid()) VEditableTerrain::AddDirtyVegetationRangeAllTerrains(m_CurrentBBox); m_CurrentBBox = newBBox; VEditableTerrain::ForceUpdateDecorationReceiverList(); } }
bool MeshLoader::Load(const VSceneListEntry& entry) { Helper::SetupScene(entry); // load vmesh VisStaticMesh_cl* pRes = VisStaticMesh_cl::GetResourceManager().LoadStaticMeshFile(entry.sScenePath); if (pRes == NULL) return false; // force loading of .colmesh file if it exists if (pRes->GetCollisionMesh(true)) hkvLog::Info("Loaded collision mesh"); else hkvLog::Info("No collision mesh loaded"); // get a instance hkvMat4 mTransform; VisStaticMeshInstance_cl *pInst = pRes->CreateInstance(mTransform); // create the visibility zone const hkvAlignedBBox& bbox = pInst->GetBoundingBox(); int iZones = Vision::GetSceneManager()->GetNumVisibilityZones(); VisVisibilityZone_cl* pVisZone; if (iZones > 0) { pVisZone = Vision::GetSceneManager()->GetVisibilityZone(0); } else { pVisZone = new VisVisibilityZone_cl(bbox); Vision::GetSceneManager()->AddVisibilityZone(pVisZone); } // add submeshes to vis zone for (int i = 0; i < pInst->GetSubmeshInstanceCount(); ++i) { pVisZone->AddStaticGeometryInstance(pInst->GetSubmeshInstance(i)); } Helper::LookAtBox(bbox); return true; }
void vHavokStaticMesh::Init(VisStaticMeshInstance_cl &meshInstance) { // Init may only be called once VVERIFY_OR_RET(m_bInitialized == false); // Add the static mesh instance m_staticMeshes.Append(&meshInstance); meshInstance.SetPhysicsObject(this); m_iNumValidStaticMeshes = 1; m_bInitialized = true; // Build the Havok shape CreateHkRigidBody(); }
void vHavokStaticMesh::UpdateVision2Havok() { VVERIFY_OR_RET(m_staticMeshes.GetLength() >= 1 && m_pRigidBody); int iCount = m_staticMeshes.GetLength(); for (int i=0;i<iCount;i++) { // since collision mesh does not provide a bounding box, use bounding box of render mesh as approximation const hkvAlignedBBox& bbox = m_staticMeshes[i]->GetBoundingBox(); hkVector4 bbox_min; vHavokConversionUtils::VisVecToPhysVec_noscale(bbox.m_vMin, bbox_min); hkVector4 bbox_max; vHavokConversionUtils::VisVecToPhysVec_noscale(bbox.m_vMax, bbox_max); hkVector4 bbox_extent; bbox_extent.setSub(bbox_max,bbox_min); bbox_extent.mul(vHavokConversionUtils::GetVision2HavokScaleSIMD()); hkVector4 meshTol; meshTol.setAll(hkReal(HKVIS_MESH_SHAPE_TOLERANCE)); hkVector4Comparison::Mask largeEnough = bbox_extent.greaterEqual(meshTol).getMask<hkVector4ComparisonMask::MASK_XYZ>(); if (hkMath::countBitsSet(largeEnough) < 2) { Vision::Error.Warning("Attempted to create a vHavokStaticMesh with undersized extents (%.4f, %4f, %.4f)", bbox_extent(0), bbox_extent(1), bbox_extent(2)); return; } } // We use the first static mesh instance as origin reference VisStaticMeshInstance_cl *pMeshInstance = m_staticMeshes[0]; // Get the static mesh instance position and rotation hkMatrix4 mTransform; vHavokConversionUtils::VisMatrixToHkMatrix(pMeshInstance->GetTransform(), mTransform, false, false, true); // Split the rotation into scale and normal matrix hkRotation mRotation; mRotation.setCols(mTransform.getColumn<0>(),mTransform.getColumn<1>(),mTransform.getColumn<2>()); hkVector4 vScale; vScale.set(mRotation.getColumn<0>().normalizeWithLength<3>(), mRotation.getColumn<1>().normalizeWithLength<3>(), mRotation.getColumn<2>().normalizeWithLength<3>(), hkSimdReal_1); bool bUpdateDebugRendering = false; //Check here if we need to recalculate the precomputed collision mesh //should only happen inside the editor //if((vScale.x != m_vScale.x || vScale.y != m_vScale.y || vScale.z != m_vScale.z) && m_pRigidBody != NULL) hkVector4 mvScale; vHavokConversionUtils::VisVecToPhysVec_noscale(m_vScale,mvScale); if (!vScale.allEqual<3>(mvScale, hkSimdReal::fromFloat(HKVMATH_LARGE_EPSILON)) && (m_pRigidBody != NULL)) { // Keep our object alive VSmartPtr<vHavokStaticMesh> keepAlive = this; RemoveHkRigidBody(); //Remove the old collision object CreateHkRigidBody(); //Create a new one (because the scale changed) VASSERT_MSG(m_pRigidBody != NULL, "Creating new rigid body failed"); vHavokConversionUtils::PhysVecToVisVec_noscale(vScale, m_vScale); bUpdateDebugRendering = true; } // Set the transformation in Havok hkTransform hkTfOut; hkTfOut.setRotation(mRotation); hkTfOut.getTranslation().setMul(mTransform.getColumn<3>(),vHavokConversionUtils::GetVision2HavokScaleSIMD()); m_pRigidBody->setTransform(hkTfOut); if (bUpdateDebugRendering) { SetDebugRendering (false); } }
void vHavokStaticMesh::CreateHkRigidBody() { // Create the Havok shape hkpRigidBodyCinfo cInfo; cInfo.m_motionType = hkpMotion::MOTION_FIXED; // We use the first static mesh instance as origin reference VisStaticMeshInstance_cl *pMeshInstance = m_staticMeshes[0]; cInfo.m_collisionFilterInfo = pMeshInstance->GetCollisionBitmask(); if (cInfo.m_collisionFilterInfo & (1<<15)) { cInfo.m_collisionFilterInfo &= ~(1<<15); Vision::Error.Warning("vHavok: Static mesh [%s] has outdated collision information. Please reexport scene.", pMeshInstance->GetMesh()->GetFilename()); } // Get the scaling of the first static mesh which is used as a reference { hkMatrix4 mTransform; vHavokConversionUtils::VisMatrixToHkMatrix(m_staticMeshes[0]->GetTransform(), mTransform, false, false, true); hkVector4 vScale; vScale.set( mTransform.getColumn<0>().lengthSquared<3>(), mTransform.getColumn<1>().lengthSquared<3>(), mTransform.getColumn<2>().lengthSquared<3>(), hkSimdReal_1); vScale.setSqrt(vScale); vHavokConversionUtils::PhysVecToVisVec_noscale(vScale,m_vScale); } // Create the shape. // We can either create the shape from mem, or serialize it in (if cached). // Do not set vHavokShapeFactory::VShapeCreationFlags_SHRINK, so back compat. Better to have as an option. const int iCreationFlags = (pMeshInstance->GetCollisionBehavior()==VisStaticMeshInstance_cl::VIS_COLLISION_BEHAVIOR_FROMFILE) ? vHavokShapeFactory::VShapeCreationFlags_ALLOW_PERTRICOLINFO : 0; hkRefPtr<hkpShape> spShape = vHavokShapeFactory::CreateShapeFromStaticMeshInstances(m_staticMeshes, iCreationFlags, &m_szShapeCacheId); cInfo.m_shape = spShape; // When CollisionBehavior_e::FromFile was selected and there is no collisionFilterInfo available from file (due to old vcolmesh format, convex shape), // a default collisionFilterInfo will be used. if (cInfo.m_collisionFilterInfo==0) { bool bHasMaterialCacheData = false; const hkpShape *pShape = (hkpShape*)spShape.val(); const hkClass *pClass = pShape->getClassType(); if (pClass == &hkvBvCompressedMeshShapeClass) { const hkvBvCompressedMeshShape *pMeshShape = (hkvBvCompressedMeshShape*)(pShape); bHasMaterialCacheData = pMeshShape->m_userData != HK_NULL; } if (!bHasMaterialCacheData) cInfo.m_collisionFilterInfo = vHavokPhysicsModule::HK_LAYER_COLLIDABLE_STATIC; } cInfo.m_numShapeKeysInContactPointProperties = -1; // Ensure shape keys are stored. m_pRigidBody = new hkpRigidBody(cInfo); // Set user data to identify this static mesh during collision detection m_pRigidBody->setUserData((hkUlong)vHavokUserDataPointerPair_t::CombineTypeAndPointer(this, V_USERDATA_STATIC)); // Add our instance to the module UpdateVision2Havok(); m_module.AddStaticMesh(this); }