游戏人生
About Me
  • 你好
  • Math
    • Number
      • Float IEEE754对确定性的影响
      • Pairing Function及其用途
    • Vector and Matrix
      • TRS基础概念
      • LossyScale深入分析
    • Quatenion
      • FromToRotation实现细节
    • Lerp and Curve
      • Slerp球形插值
      • Bezier Curve为什么重要
      • Interpolation和Extrapolation实现细节
  • Programming
    • C#
      • 学习资料
      • C# struct灵魂拷问
      • CIL的世界:call和callvirt
      • .NET装箱拆箱机制
      • .NET垃圾回收机制
    • Go
      • 基础特性
      • 如何正确的判空interface
      • 如何用interface模拟多态
      • 如何定制json序列化
      • 如何安全在循环中删除元素
      • 如何安全关闭channel
      • 如何集成c++库(cgo+swig)
      • 如何性能测试(benchmark, pprof)
    • Lua
      • 基础特性
  • General Game Development
    • Game Engine
      • 学习资料
      • 关于游戏引擎的认知
    • Networking
      • 帧同步
      • 状态同步
      • 物理同步
    • Physics
      • PhysX基本概念
      • PhysX增加Scale支持
      • PhysX场景查询
      • PhysX碰撞检测
      • PhysX刚体动力学
      • PhysX角色控制器
      • PhysX接入项目工程
      • 物理同步
      • 物理破坏
    • Design Pattern
      • 常用设计模式
      • MVP 架构模式
      • ECS 架构模式
  • Unity
    • Runtime
      • Unity拥抱CoreCLR
      • 浅析Mono内存管理
    • UGUI
      • 浅析UGUI渲染机制
      • 浅析UGUI文本优化
      • 介绍若干UGUI实用技巧
    • Resource Management
      • 浅析Unity堆内存的分类和管理方式
      • 深入Unity资源
      • 深入Unity序列化
      • 深入Assetbundle机制
    • Async
      • 深入Unity协程
      • 介绍若干Unity协程实用技巧
      • 异步动作队列
    • Hot Reload
      • Unity+Xlua
      • Xlua Examples学习(一)
      • Xlua Examples学习(二)
    • Editor Extension
    • Performance
      • 浅析Unity Profiler
      • 介绍一个Overdraw分析工具
  • Platform
    • WebGL
  • Real-world Project
    • Souce Engine
    • DOOM3 BFG
Powered by GitBook
On this page
  • PhysX: Scene Query
  • Scene
  • Scene Query
  • Data Structure for traversal
  • Use prefilter and postfilter
  1. General Game Development
  2. Physics

PhysX场景查询

PreviousPhysX增加Scale支持NextPhysX碰撞检测

Last updated 20 days ago

PhysX: Scene Query

本文以PhysX 3.4物理引擎为例,介绍场景查询(Raycast, Sweep, Overlap)的一些内部机制和使用方法。

  • PhysX 3.4

  • PhysX 3.4

Scene

A Scene in PhysX engine is a container of objects in a hierachical manner.

There are only position and rotation in GlobalPose and LocalPose, no "scale". Scale only reflects on geometry's actual size.

Scene Query

Three kinds of scene query:

  • raycast

  • sweep

  • overlap

In general, each SceneQuery traverses a culling structure containing the scene objects, performs a precise test using the GeometryQuery functions, and accumulates the results.

You can customize filtering logic via prefilter and postfilter.

  • Broad phase traverses the global scene spatial partitioning structure to find the candidates for mid and narrow phases.

  • Midphase traverses the triangle mesh and heightfield internal culling structures, to find a smaller subset of the triangles in a mesh reported by the broad phase.

  • Narrow phase performs exact intersection tests

  • Pre-filtering happens before midphase and narrow phase and allows shapes to be efficiently discarded before the potentially expensive exact collision test.

  • Post-filtering happens after the narrow phase test and can therefore use the results of the test (such as PxRaycastHit.position) to determine whether a hit should be discarded or not.

Data Structure for traversal

A scene uses two query structures, one for "static" objects (PxRigidStatic), one for "dynamic" objects (PxRigidBody). Each structure can use different culling algorithms, see PxPruningStructureType.

PxPruningStructureType
Explaination

eNone

Based on grid. Full rebuild when changed.

eDYNAMIC_AABB_TREE

Based on tree. Full rebuild when changed. Only choose this if all static actors in your scene are not modified after initialization.

eSTATIC_AABB_TREE

Based on grid and tree. Incremental rebuild when changed, unless by force. Choose this if frequently add/remove geometry, at the cost of higher memory

Use prefilter and postfilter

To make prefilter works, there are 3 steps.

  • Step 1. Attach data (PxFilterData) for on shape. It has four 32bit words to hold custom data, e.g., use word0 as layer of this shape.

Here is an example:

PxShape* shape = PxRigidActorExt::createExclusiveShape(*pxActor, PxBoxGeometry(extV), *pxMaterial);
PxFilterData queryFilter;
queryFilter.word0 = layer;
shape->setQueryFilterData(queryFilter);
  • Step 2. Define callback function for prefilter. See PxQueryFilterCallback. The logic is totally depend on yourself, just return PxQueryHitType to tell if this shape can pass.

PxQueryHitType
Explanation

eNONE

Shall not pass.

eTOUCH

Pass, but does not stop the raycast or sweep.

eBLOCK

Pass, but stop here.

Here is an realworld example:

class PhysxQueryFilterCallback : public PxQueryFilterCallback
{
public:
	PhysxQueryFilterCallback();
	PhysxQueryFilterCallback(bool isBlocking, bool includeTrigger);
	virtual PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags);
	virtual PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit);

private:
	PxQueryHitType::Enum m_HitType;
	bool m_IncludeTrigger;
};

PxQueryHitType::Enum PhysxQueryFilterCallback::preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags)
{
	bool isTrigger = shape->getFlags() & physx::PxShapeFlag::eTRIGGER_SHAPE;
	if (isTrigger && !m_IncludeTrigger) {
		return PxQueryHitType::eNONE;
	}

	PxFilterData shapefilterData = shape->getQueryFilterData();

	if (shapefilterData.word0 & filterData.word0 || shapefilterData.word1 & filterData.word1)
	{
		return m_HitType;
	}
	return PxQueryHitType::eNONE;
}

PxQueryHitType::Enum PhysxQueryFilterCallback::postFilter(const PxFilterData& filterData, const PxQueryHit& hit) 
{
	const PxLocationHit& impactHit = static_cast<const PxLocationHit&>(hit);
	if (impactHit.distance > 0.0f)
		return m_HitType;

	return PxQueryHitType::eNONE;
}
  • Step 3. Add PxQueryFilterData when query

PxQueryFilterData has two fields:

field
Explaination

PxQueryFlags

Supported flags are in PxQueryFlag::Enums, e.g. raise ePREFILTER means all shapes need to pass prefilter you defined.

PxFilterData

Has four 32bit words for you, e.g. use word0 as the "layermask" of the query.

Here is an realworld example of raycast (return multiple objects):

struct MyRaycastHitResult
{
	PhysXVec3 Position;
	PhysXVec3 Normal;
	float Distance;
	PhysXActor* Collider;
};

typedef PhysXArray<MyRaycastHitResult> MyRaycastHitResults;

bool MyRaycast(MyRaycastHitResults& hitResults, const PhysXVec3& startPos, const PhysXVec3& direction, float distance, unsigned int layerMask, bool includeTrigger)
{

	const PxU32 bufferSize = 256;
	PxRaycastHit hitBuffer[bufferSize];
	PxRaycastBuffer buf(hitBuffer, bufferSize);

	PxQueryFilterData filterData = PxQueryFilterData();
	filterData.flags |= PxQueryFlag::ePREFILTER | PxQueryFlag::ePOSTFILTER;
	filterData.data.word0 = 0;
	filterData.data.word1 = layerMask;
	PhysxQueryFilterCallback filterCallback(false, includeTrigger);

	bool status = m_pxScene->raycast(startPos, direction, distance, buf, PxHitFlag::eDEFAULT, filterData, &filterCallback, NULL);

	if (status)
	{
		hitResults.clear();
		
		for (PxU32 i = 0; i < buf.nbTouches; i++)
		{
			PxRaycastHit touch = buf.touches[i];
			MyRaycastHitResult hitResult;
			hitResult.Position = touch.position;
			hitResult.Normal = touch.normal;
			hitResult.Distance = touch.distance;
			hitResult.Collider = (PhysXActor*)touch.actor->userData;
			hitResults.push_back(hitResult);
		}
		if (buf.hasBlock) {
			MyRaycastHitResult hitResult;
			hitResult.Position = buf.block.position;
			hitResult.Normal = buf.block.normal;
			hitResult.Distance = buf.block.distance;
			hitResult.Collider = (PhysXActor*)buf.block.actor->userData;
			hitResults.push_back(hitResult);
		}
	}
	return status;
}
source code
PhysXGuide.chm