void RPG_Explosion::CreateAabb( hkAabb &aabb ) { hkVector4 centerHk, directionHk; vHavokConversionUtils::VisVecToPhysVecLocal(m_center, centerHk); vHavokConversionUtils::VisVecToPhysVecLocal(m_direction, directionHk); switch(m_type) { case ET_Sphere: { aabb.setFromCenterRadius(centerHk, VIS2HK_FLOAT_SCALED(m_radius)); } break; case ET_HerringBone: { hkVector4 endPointHk; endPointHk.setAddMul(centerHk, directionHk, VIS2HK_FLOAT_SCALED(m_length)); aabb.setFromLine(centerHk, endPointHk); aabb.expandBy(VIS2HK_FLOAT_SCALED(m_radius)); } break; case ET_None: case ET_Count: default: { VASSERT_MSG(false, "Please specify a valid RPG_ExplosionType_e.") } break; } }
static bool _ComputePath(const hkaiWorld* aiWorld, hkvVec3* startPoint, hkvVec3* endPoint, float radius, hkaiPathfindingUtil::FindPathInput& input, hkaiPathfindingUtil::FindPathOutput& output) { VASSERT(input.m_goalPoints.getSize() == 1); vHavokConversionUtils::VisVecToPhysVecWorld((*startPoint), input.m_startPoint); vHavokConversionUtils::VisVecToPhysVecWorld((*endPoint), input.m_goalPoints[0]); input.m_startFaceKey = HKAI_INVALID_PACKED_KEY; input.m_goalFaceKeys[0] = HKAI_INVALID_PACKED_KEY; bool foundPath = false; const hkaiNavMeshQueryMediator* mediator = aiWorld ? aiWorld->getDynamicQueryMediator() : HK_NULL; if (mediator) { hkVector4 closestPoint; input.m_startFaceKey = mediator->getClosestPoint(input.m_startPoint, 3.f, closestPoint); if (input.m_startFaceKey != HKAI_INVALID_PACKED_KEY) input.m_startPoint = closestPoint; input.m_goalFaceKeys[0] = mediator->getClosestPoint(input.m_goalPoints[0], 3.f, closestPoint); if (input.m_goalFaceKeys[0] != HKAI_INVALID_PACKED_KEY) input.m_goalPoints[0] = closestPoint; if (input.m_startFaceKey != HKAI_INVALID_PACKED_KEY && input.m_goalFaceKeys[0] != HKAI_INVALID_PACKED_KEY) { input.m_agentInfo.m_diameter = VIS2HK_FLOAT_SCALED(radius*2.f); input.m_searchParameters.m_up.set(0,0,1); hkaiPathfindingUtil::findPath(*aiWorld->getStreamingCollection(), input, output); foundPath = (output.m_outputParameters.m_status == hkaiAstarOutputParameters::SEARCH_SUCCEEDED); } } return foundPath; }
void vHavokVisualDebugger::Step() { // Get the local timers to feed to the stats viewer // reset our VDB stats list if (m_physicsContext) { m_physicsContext->syncTimers(vHavokPhysicsModule::GetInstance()->GetThreadPool()); } hkReal dt = Vision::GetTimer()->GetTimeDifference(); // Step the debugger m_pVisualDebugger->step(dt*hkReal(1000)); // Update camera hkVector4 pos; vHavokConversionUtils::VisVecToPhysVecWorld(Vision::Camera.GetMainCamera()->GetPosition(),pos); hkVector4 dir; vHavokConversionUtils::VisVecToPhysVec_noscale(Vision::Camera.GetMainCamera()->GetDirection(),dir); hkVector4 up; vHavokConversionUtils::VisVecToPhysVec_noscale(Vision::Camera.GetMainCamera()->GetObjDir_Up(), up); hkVector4 lookat; lookat.setAdd(pos,dir); // Havok visual debugger defaults float nearPlane = 0.1f; float farPlane = 500.f; float fovX = 0.f; float fovY = 45.f; VisRenderContext_cl::GetMainRenderContext()->GetClipPlanes(nearPlane, farPlane); VisRenderContext_cl::GetMainRenderContext()->GetFinalFOV(fovX, fovY); // Scale them to Havok space nearPlane = float(VIS2HK_FLOAT_SCALED(nearPlane)); farPlane = float(VIS2HK_FLOAT_SCALED(farPlane)); HK_UPDATE_CAMERA(pos, lookat, up, nearPlane, farPlane, fovY, "Vision"); // Reset internal profiling info for next frame hkMonitorStream::getInstance().reset(); }
hkReal hkvSampledHeightFieldShape::getHeightAtImpl(int x, int z) const { #ifdef SUPPORTS_TERRAIN // Note we flip the sampling of (Havok Z) to be (RES - Vision Y) // See vHavokTerrain::CreateHkRigidBody for explanation (and other alternatives) return VIS2HK_FLOAT_SCALED(m_pSector->GetHeightAt(x, m_zRes-z-1)); #else return 0.0f; #endif }
bool vHavokAiModule::ComputeAndDrawPath(IVRenderInterface *pRenderer, hkvVec3* startPoint, hkvVec3* endPoint, float radius, float height, float displayOffset, unsigned int color) const { hkaiPathfindingUtil::FindPathInput input(1); hkaiPathfindingUtil::FindPathOutput output; bool foundPath = _ComputePath(m_aiWorld, startPoint, endPoint, radius, input, output); if (input.m_startFaceKey != HKAI_INVALID_PACKED_KEY && input.m_goalFaceKeys[0] != HKAI_INVALID_PACKED_KEY) { vHavokAiNavMeshDebugDisplayHandler displayHandler; hkReal displayOffsetHavokScale = VIS2HK_FLOAT_SCALED(displayOffset); hkaiNavMeshDebugUtils::_drawPathWithRadius(input, output, color, hkColor::ORANGE, &displayHandler, 0, displayOffsetHavokScale); } hkvVec3 vStartPos; vHavokConversionUtils::PhysVecToVisVecWorld(input.m_startPoint,vStartPos); hkvVec3 vEndPos; vHavokConversionUtils::PhysVecToVisVecWorld(input.m_goalPoints[0],vEndPos); hkvVec3 vScaledDir ( 0.f, 0.f, height ); VSimpleRenderState_t state(VIS_TRANSP_NONE, RENDERSTATEFLAG_FRONTFACE|RENDERSTATEFLAG_WRITETOZBUFFER); int sd = (input.m_startFaceKey != HKAI_INVALID_PACKED_KEY) ? 1 : 2; int ed = (input.m_goalFaceKeys[0] != HKAI_INVALID_PACKED_KEY) ? 1 : 2; pRenderer->RenderCylinder(vStartPos, vScaledDir, radius, VColorRef(255/sd, 165/sd, 0/sd), state, RENDERSHAPEFLAGS_SOLID|RENDERSHAPEFLAGS_CAP1); pRenderer->RenderCylinder(vEndPos, vScaledDir, radius, VColorRef(0/ed, 128/ed, 0/ed), state, RENDERSHAPEFLAGS_SOLID|RENDERSHAPEFLAGS_CAP1); return foundPath; }
hkpShape* vHavokShapeFactory::CreateShapeFromTerrain(const VTerrainSector& terrain) { // Check if shape is already cached on disk. Only try to load cached shape file outside of vForge, since otherwise the physics // representation will not be updated on terrain editing. const bool bAllowStaticMeshCaching = vHavokPhysicsModule_GetDefaultWorldRuntimeSettings().m_bEnableShapeCaching==TRUE; if (!Vision::Editor.IsInEditor() && bAllowStaticMeshCaching) { hkpShape *pCachedShape = vHavokCachedShape::LoadTerrainSectorShape(&terrain); if (pCachedShape) return pCachedShape; else Vision::Error.Warning("Cached HKT file for %s is missing. Please generate HKT file (see documentation for details).", terrain.GetFilename()); } hkpSampledHeightFieldBaseCinfo ci; ci.m_xRes = terrain.m_Config.m_iHeightSamplesPerSector[0]+1; ci.m_zRes = terrain.m_Config.m_iHeightSamplesPerSector[1]+1; // Overlapping samples into next sectors on all edges (so res-1 is scale) ci.m_scale.set( VIS2HK_FLOAT_SCALED(terrain.m_Config.m_vSectorSize.x/float(ci.m_xRes-1)), 1, VIS2HK_FLOAT_SCALED(terrain.m_Config.m_vSectorSize.y/float(ci.m_zRes-1)) ); ci.m_minHeight = VIS2HK_FLOAT_SCALED(terrain.m_fMinHeightValue); ci.m_maxHeight = VIS2HK_FLOAT_SCALED(terrain.m_fMaxHeightValue); hkvSampledHeightFieldShape* heightFieldShape = new hkvSampledHeightFieldShape(ci, &terrain); const bool bExact = terrain.GetPhysicsType() >= VTerrainSector::VPHYSICSTYPE_PRECISE; const bool bHasHoles = terrain.HasHoles(); if (!bExact && bHasHoles) Vision::Error.Warning("Terrain sector has holes but uses approximated physics representation. Therefore precise physics representation enforced."); // Two choices here.. could use just the heightfield as is, or // wrap it in a tri sampler. The tri sampler will give exact collisions, the heightfield alone will be based on collision spheres. // We *have* to use the accurate version in case the sector has holes if (bExact || bHasHoles) { hkpTriSampledHeightFieldCollection* collection; hkpTriSampledHeightFieldBvTreeShape* bvTree; if (bHasHoles) // use a slightly modified version of hkpTriSampledHeightFieldCollection in case it has holes { collection = new hkvTriSampledHeightFieldCollection(&terrain, heightFieldShape); bvTree = new hkvTriSampledHeightFieldBvTreeShape(collection); } else { collection = new hkpTriSampledHeightFieldCollection(heightFieldShape); bvTree = new hkpTriSampledHeightFieldBvTreeShape(collection); } // Winding must be set to WELDING_TYPE_ANTICLOCKWISE (see hkpTriSampledHeightFieldCollection::initWeldingInfo()). if (terrain.GetPhysicsType() == VTerrainSector::VPHYSICSTYPE_PRECISE_OFFLINE_WELDING) hkpMeshWeldingUtility::computeWeldingInfo(collection, bvTree, hkpWeldingUtility::WELDING_TYPE_ANTICLOCKWISE); collection->removeReference(); heightFieldShape->removeReference(); return bvTree; } else { return heightFieldShape; } }