NVIDIAGameWorks/PhysX

Scene raycast does not trigger filterShader function when setting PxQueryFilterData

lpares12 opened this issue · 5 comments

Hi,

I'm trying to implement scene raycasts, but I can't manage to make it work when PxQueryFilterCallback is set.

Basically I do this:

bool raycast {
    PxRaycastBuffer hits;

    PxHitFlags hit_flags(PxHitFlag::eDEFAULT);
    PxQueryFilterData filter_data = PxQueryFilterData();

    filter_data.flags |= PxQueryFlag::Enum::eDYNAMIC | PxQueryFlag::Enum::eSTATIC;
    filter_data.data.word0 = 0x1; // 0x1
    filter_data.data.word1 = 0x1; // 0x1

    bool ret = px_scene->raycast(origin, direction_normalize, max_distance, hits, hit_flags, filter_data);
}

With this, and according to the documentation, I'd expect the filterShader of the scene to be called whenever the raycast detects a body. But this never happens, as I have added prints in there (and setup a breakpoint in gdb) and those never get triggered. It does get triggered though when there are physical collisions.

Now, if I remove the filter_data argument, then the raycast correctly collisions with some bodies. Note that I have tried different flags and so on, but with the same luck.

For a bit more of context, this is how I setup the scene and the filterShader, which isi similar to the example in the documentation:

void setup_scene() {
    PxSceneDesc sceneDesc(getTolerancesScale());
    sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
    sceneDesc.cpuDispatcher = px_cpu_dispatcher;
    sceneDesc.filterShader = px_filter_shader;
    sceneDesc.flags = sceneDesc.flags
                    | PxSceneFlag::eENABLE_ACTIVE_ACTORS
                    | PxSceneFlag::eEXCLUDE_KINEMATICS_FROM_ACTIVE_ACTORS;
    px_scene = px_physics->createScene(sceneDesc);
}

PxFilterFlags px_filter_shader(PxFilterObjectAttributes attributes0, PxFilterData filter_data0,
        PxFilterObjectAttributes attributes1, PxFilterData filter_data1, PxPairFlags& pair_flags,
        const void* constant_block, uint32_t constant_block_size) {
      
    print_line("Inside!!!");
    if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1)) {
        pair_flags = PxPairFlag::eTRIGGER_DEFAULT;
        return PxFilterFlag::eDEFAULT;
    }

    if(filter_data0.word0 & filter_data1.word1 && filter_data1.word0 & filter_data0.word1) {
        pair_flags = PxPairFlag::eCONTACT_DEFAULT;
        pair_flags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
    } else {
        return PxFilterFlag::eSUPPRESS;
    }
    return PxFilterFlag::eDEFAULT;
}

There are no examples in the snippets using raycasts and PxQueryFilterData so I can't really compare with it, but as per the documentation I think this should be quite straightforward.

I can't manage to make it work when PxQueryFilterCallback is set.

I'd expect the filterShader of the scene to be called

Where is your PxQueryFilterCallback ? The "filterShader of the scene" is a PxSimulationFilterShader, a different object used for simulation but not scene queries.

There are no examples in the snippets using raycasts and PxQueryFilterData

Perhaps you can look at how the character controller uses it:

https://github.com/NVIDIA-Omniverse/PhysX/blob/release/104.2/physx/source/physxcharacterkinematic/src/CctCharacterController.cpp#L2063

The old samples also demonstrated some of that, see e.g:
https://github.com/NVIDIAGameWorks/PhysX/blob/4.1/physx/samples/samplebridges/SampleBridges.h#L63

Hi, thanks for the quick reply!

After your response, I investigated a bit, and I don't seem to need any of the pre and post filters. I just need to configure the "data based filter" from the PxQueryFilterData:

In the PxQueryFilterCallback documentation (https://nvidia-omniverse.github.io/PhysX/physx/5.1.3/_build/physx/latest/class_px_query_filter_callback.html#_CPPv421PxQueryFilterCallback) it says:

Custom filtering logic for scene query intersection candidates. If an intersection candidate object passes the data based filter (see PxQueryFilterData)

For now, I'm just looking to filter the raycast according to the word0 and word1 set in the raycast and shapes. So I think customizing this filter data will do. But I'm not sure how to do that. In the documentation it says:

Whenever the scene query intersects a shape, filtering is performed in the following order:
For non-batched queries only:
If the data field is non-zero, and the bitwise-AND value of data AND the shape’s queryFilterData is zero, the shape is skipped

Is there any way to customize this behavior? Same as I can define the PxSimulationFilterShader of the scene. Something similar for the PxQueryFilterData too? Or the only way is with a post filter?

Also, note that I was missing to call setQueryFilterData(data); for the shapes. Now the raycast is detecting them with the default PxQueryFilter (bitwise-AND). But would like to be able to configure this AND operation.

For now, I'm just looking to filter the raycast according to the word0 and word1 set in the raycast and shapes. So I think customizing this filter data will do. But I'm not sure how to do that.

Is there any way to customize this behavior?

Just set the scene query filter data on the shape, like you did for the simulation filter data. Note that the data for scene queries & simulation can be different (PxShape::setSimulationFilterData vs PxShape::setQueryFilterData).

The data will then be used in a hardcoded filtering equation, in the SQ code:
https://github.com/NVIDIA-Omniverse/PhysX/blob/release/104.2/physx/source/scenequery/src/SqQuery.cpp#L325

It is possible to disable that filtering equation using PxQueryFlag::eBATCH_QUERY_LEGACY_BEHAVIOUR.

If you want to customize the behavior, use a PxQueryFilterCallback and either the pre or post filter callbacks in there.

Great, thank you for the references!