RayCast ObjectID return

SDK supports Prepar3D’s philosophy of an open development architecture and encourages third parties to bring new innovations with improved add-ons and training content.
Post Reply
skeadle6309
Posts: 15
Joined: Mon Feb 12, 2018 9:20 pm

RayCast ObjectID return

Post by skeadle6309 »

I am trying to get the id of different cockpit parts using the interrogateWorldRay function. I have been debugging and can see the XYZ return results are different than the camera input results but I am always returning a object id of 0. If I set the raycast to point directly at the ground it returns the object id 4. The issue I am having is I cannot get different Object Id's for parts in the virtual cockpit view.

//pointer to ray trace manager
CComPtr<IRayTraceManagerV340> RayTraceManager;
CComPtr<ISimObjectManagerV440> ObjectManager;
CComPtr<IBaseObjectV400> ppObject = nullptr;
DXYZ vWorldRadiansFeet;
DXYZ xyzWorldUnitRayDir;
DXYZ xyzWorldRes;
UINT ResObjID = 0;
DWORD interrogRes = 0;
UINT ignoreObj = 0;
LPWSTR title;
float fRayLengthMax = 100.0f;
float fGranularityMin = 0.01f;
...
//on dll start
pPdk->QueryService(SID_SimObjectManager, IID_ISimObjectManagerV440, (void**)& ObjectManager);
...
double X, Y, Z;
mCamera->GetLLA(X, Y, Z);

//mCamera440->GetLLARadians(vWorldRadiansFeet.dZ, vWorldRadiansFeet.dX, vWorldRadiansFeet.dY);
xyzWorldUnitRayDir.dX = X - pointTransform->LLA.Latitude;
xyzWorldUnitRayDir.dY = Y - pointTransform->LLA.Longitude;
xyzWorldUnitRayDir.dZ = Z - pointTransform->LLA.Altitude;

mCamera->GetLLARadians(vWorldRadiansFeet.dZ, vWorldRadiansFeet.dX, vWorldRadiansFeet.dY);

//vWorldRadiansFeet.dX = vWorldRadiansFeet.dX + .000001;
RayTraceManager->InterrogateWorldRay(INTEROGATIONTYPE_OBJECTS, ignoreObj, vWorldRadiansFeet, xyzWorldUnitRayDir, fRayLengthMax, fGranularityMin, &ResObjID, &xyzWorldRes, interrogRes);


//this line here takes the UINT ResObjId and returns the ObjectId;
ObjectManager->GetObject(100, &ppObject);
if(ppObject != nullptr) {
ppObject->GetTitle(title, 50);
}
Thanks
Seth
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: RayCast ObjectID return

Post by Beau Hollis »

I don't believe that function supports getting VC getting VC part information. You can get some information via mouse or custom pick requests. As of 4.4, you can get tool tip text from the window using the PDK (ICameraSystemV440::GetToolTipText()). You can also get the pick result from the mouse using pick id 0. This gives you the on-screen location, the texture UV, and (if available) an IWindowV400 pointer to the window that backs the texture they hit. You can convert to/from ScreenCoord and LLA using the Camera interface. You could get the window name to figure out which vc panel texture they are interacting with. Example:

//Get the current pick results.
P3D::PickResult pickResults;
LLADegreesMeters LLA;
pCamera->GetPickResult(0, pickResults);
pCamera->GetWorldCoord(pickResults.Location, LLA);
if (pickResults.pWindow != nullptr)
{
LPCWSTR szWindowName = pickResults.pWindow->GetWindowName();
}

Thanks
Beau Hollis
Prepar3D Software Architect
skeadle6309
Posts: 15
Joined: Mon Feb 12, 2018 9:20 pm

Re: RayCast ObjectID return

Post by skeadle6309 »

Hello Beau,

With the texture UV can I get panel names? such as "Comm pannel"

Thanks Seth
virtuali
Posts: 598
Joined: Tue Sep 27, 2011 12:51 pm

Re: RayCast ObjectID return

Post by virtuali »

Beau Hollis wrote: Tue Jan 29, 2019 3:48 pmYou can convert to/from ScreenCoord and LLA using the Camera interface.

Could you please shed some light on the GetWorldCoord() function ? I can use the GetScreenCoord() function with no issues, and it works as expected, but can't figure out how the inverse GetWorldCoord() works.

It seems that, regardless what I'm passing as screen coords, it always return the same result: the Lat/Lon coordinates of the current camera.

For example, if I'm in default Spot view, and move the view to see the airplane from the right side, GetWorldCoord() returns a point in Lat/Lon which seems to match the position of a camera moved to a place that matches the current view so, it's some meters on the right side of the plane.

If I place the view directly overhead the airplane, or use the default Top Down view, GetWorldCoord() returns exactly the Lat/Lon of the center of the airplane.

But the main issue I don't understand, is that I can pass anything as the first screencoords parameter, but the returned lat/lon it's always the same, as if the first parameter was ignored. For example:

POINT mp; ScreenCoord screenCoords;

GetCursorPos(&mp);
ScreenToClient(hFSWindow, &mp);

screenCoords.XPixels = mp.x;
screenCoords.YPixels = mp.y;
screenCoords.DistanceMeters = 0;

m_pCamera->GetWorldCoord(screenCoords, LLA);

Here, I was hoping to get the lat/lon coordinates of a point after having clicked on it on screen, so I'm passing the mouse coordinates relative to the main program window, but the result is always as described before: the current location in the world of the current camera.

But even passing 0 to all 3 parameters:

screenCoords.XPixels = 0;
screenCoords.YPixels = 0;
screenCoords.DistanceMeters = 0;

m_pCamera->GetWorldCoord(screenCoords, LLA);

Doesn't change anything, same result as passing different mouse coordinates.

So I checked the samples, and the only one that uses this function is MousePicking.

The sample compiles normally, but nothing happens. I ran it through the VS debugger, and I see it's running, it calls the constructor and registers the plugin correctly, it enters in the OnCustomRender function at each frame. However, it doesn't do anything there, since the window pointer it's always 0. From the source code, it looks like in order to start a mouse picking, the RequestPicks() call must be made, and this is done in the PickWindowPlugin::OnPreCameraUpdate(). However, this one is NEVER called, so no picking ever starts. The OnViewChange() function is also never called too. The OnApplicationShutdown() is called normally when exiting the sim so, for some reason, the MousePicking sample doesn't seem to work correctly.

//Get the current pick results.
P3D::PickResult pickResults;
LLADegreesMeters LLA;
pCamera->GetPickResult(0, pickResults);
pCamera->GetWorldCoord(pickResults.Location, LLA);
if (pickResults.pWindow != nullptr)
{
LPCWSTR szWindowName = pickResults.pWindow->GetWindowName();
}
This code doesn't seem right. According to the docs, GetPickResult() takes 3 parameters, an int ID, a bool wasHit and a float distanceToHit, but here it seems it's being called with two LLAs, since both pickResults.Location and LLA are LLADegreesMeters. I thought it was an overload, but it doesn't look like, and it doesn't compile like this.

In any case, my goal would be simply being able to click on the current view, and get the World Lat/Lon coordinates of the clicked point.
Umberto Colapicchioni - VIRTUALI Sagl
http://www.fsdreamteam.com
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: RayCast ObjectID return

Post by Beau Hollis »

The conversion into world space requires distance in meters to be set. The pixel position is used to get a ray direction, and the distance is used to transform the point into the world. When you get pick results, the distance is included with the result if there was a valid hit.

If you just want the location of the mouse, you don't need to submit custom pick requests. You can use ID 0 to get the results of the internal test we do for the mouse.

Try this:

PickResult result;
pCamera->GetPickResult(0, result);
ObjectWorldTransform pickWorldTrans;
pCamera->GetWorldCoord(result.Location, pickWorldTrans.LLA);

ARGBColor color(128, 255, 200, 200);

RenderFlags flags;
flags.DrawWithVC = true;
flags.DepthReadDisable = true;

PdkServices::GetObjectRenderer()->DrawSphere(pickWorldTrans, 0.05f, color, flags);
This is a simplified version of our VR mouse implementation. It gets the result of pick id 0 and draws a 5cm sphere at the location of intersection.

It sounds link you may not need to do custom pick requests, but in case you do, the sample registers a post process called "MousePickingTest". This was required in the first version of the sample because it used DirectX to render the points. We now use the object rendering service, but the post process is still used enable the pick test behavior for a given view. If you create a custom camera, you should see "MousePickingTest" in the list of post processes. Add that to your custom camera and save it. When you switch to the custom camera, you should see the spheres.

Thanks
Beau Hollis
Prepar3D Software Architect
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: RayCast ObjectID return

Post by Beau Hollis »

More information on the picking sample in the SDK article:
https://www.prepar3d.com/SDKv4/sdk/pdk_ ... ample.html
Beau Hollis
Prepar3D Software Architect
virtuali
Posts: 598
Joined: Tue Sep 27, 2011 12:51 pm

Re: RayCast ObjectID return

Post by virtuali »

Thanks a lot, after reading the article in the help file, I can see the 4 spheres in the sample!

However, I still can't compile this in my code:

PickResult result;
pCamera->GetPickResult(0, result);

The compiler outputs this error:

'P3D::ICameraSystemV400::GetPickResult': function does not take 2 arguments

a reference of type "bool &" (not const-qualified) cannot be initialized with a value of type "P3D::PickResult"


According to the doc and the header file, GetPickResult() takes 3 parameters, an int ID, a bool wasHit and a float distanceToHit.
Umberto Colapicchioni - VIRTUALI Sagl
http://www.fsdreamteam.com
virtuali
Posts: 598
Joined: Tue Sep 27, 2011 12:51 pm

Re: RayCast ObjectID return

Post by virtuali »

Hello,

I managed to compile the code and, the issue was I was still using the V400 camera interface, which only had one overload for GetPickResult. Using the V430 interface added the other overload which works.

However, the result is exactly the same as before: I'm getting the coordinates of the camera, which is not what I wanted, and the wasHit is always False, no matter which view I use or where I click. But the code clearly does something, since if I print on screen the coordinates returned, I can see the change while I move the camera around because, in fact, they are tracking the camera.

My goal was, regardless of the camera used, to be able to click on any window that shows the scenery, and obtain the world lat/lon/alt coordinates of that point.

Nothing to do with camera hits or VC or gauges...is that possible ?
Umberto Colapicchioni - VIRTUALI Sagl
http://www.fsdreamteam.com
virtuali
Posts: 598
Joined: Tue Sep 27, 2011 12:51 pm

Re: RayCast ObjectID return

Post by virtuali »

Any news about this issue ? We had to disable the mouse picking feature, but it would be very nice if we could put it back, because it would made our product GSX a bit easier to use.
Umberto Colapicchioni - VIRTUALI Sagl
http://www.fsdreamteam.com
User avatar
Beau Hollis
Lockheed Martin
Posts: 2452
Joined: Wed Oct 06, 2010 3:25 pm

Re: RayCast ObjectID return

Post by Beau Hollis »

You 'll only get hits on the user aircraft using that pick request interface because its leveraging the picking used for VC interactions. If there isn't a hit, you won'd get a valid distance. You can still use the conversion functions to back and forth from screen to world space but you would have to set a distance in manually. This done the sample below to generate a unit vector casting into the scene by setting distance to 1.0.

You can use IRayTraceManagerV340 to do ray casts for objects and terrain. It's tricky to tie this into the mouse because it uses the coordinate systems of the ISimObject services. We are working on updating the picking sample to do this. Here is a snippet from the new sample:

Code: Select all

// Use an InterrogateWorldRay to find the LLA of the terrain underneath the mouse cursor
ObjectWorldTransform PickHandler::GetLLAUnderMouseCursor()
{
    // '0' is always a pick request for the mouse cursor, we use this to get the Screen Coordinates of the mouse cursor
    ICameraSystemV450* pCamera = static_cast<ICameraSystemV450*>(mWindow->GetCameraSystem());
    P3D::PickResult mMousePick;
    pCamera->GetPickResult(0, mMousePick);

    // Pointers to access ray trace interface
    CComPtr<P3D::IRayTraceManagerV340> spRayTraceManager;
    CComPtr<P3D::IPdk> spPdk;
    CComPtr<P3D::IRayTraceManagerV340> spBaseObject;

    spPdk = PdkServices::GetPdk();

    // Results from the ray cast
    int hit_object_ID = -1;
    P3D::P3DDXYZ hit_location = { 0 };
    ObjectWorldTransform result_location;

    if (FAILED(spPdk->QueryService(P3D::SID_RayTraceManager, P3D::IID_IRayTraceManagerV340, (void**)&spRayTraceManager)))
    {
        return result_location;
    }

    else // Object and Terrain Ray Cast
    {
        ObjectWorldTransform mouseTrans;
        ObjectWorldTransform cameraTrans;
        ObjectLocalTransform offsetToPick;

        // Get LLA of pick point of mouse cursor, 1 meter away from the camera. 
        mMousePick.Location.DistanceMeters = 1.0f;
        pCamera->GetWorldCoord(mMousePick.Location, mouseTrans.LLA);

        // Get World Transform of camera
        pCamera->GetWorldTransform(cameraTrans, CAMERA_REFERENCE_EYE);

        // Create Ray Trace Origin
        P3D::P3DDXYZ vWorldRadiansFeet;
        vWorldRadiansFeet.dZ = DegToRad(cameraTrans.LLA.Latitude);
        vWorldRadiansFeet.dX = DegToRad(cameraTrans.LLA.Longitude);
        vWorldRadiansFeet.dY = MetersToFeet(cameraTrans.LLA.Altitude);

        // Create Ray Trace Orientation (unit vector)
        PBHDegrees zeroPBH;
        mouseTrans.PBH = zeroPBH;
        cameraTrans.PBH = zeroPBH;
        P3D::PdkServices::GetObjectRenderer()->CalculateBodyRelativeOffset(cameraTrans, mouseTrans, offsetToPick);

        P3D::P3DDXYZ xyzWorldUnitRayDir;
        xyzWorldUnitRayDir.dX = offsetToPick.XYZ.X;
        xyzWorldUnitRayDir.dZ = offsetToPick.XYZ.Z;
        xyzWorldUnitRayDir.dY = offsetToPick.XYZ.Y;

        // Hit Test
        UINT uResultObjectId = 0;
        P3D::P3DDXYZ xyzResultWorldRadiansFeet = { 0 };
        DWORD dwInterogationResults = P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_NONE;

        // Interrogate for Objects or Terrain
        if (SUCCEEDED(spRayTraceManager->InterrogateWorldRay(P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_OBJECTS | P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_TERRAIN,
            0, vWorldRadiansFeet, xyzWorldUnitRayDir, 4000, 1,
            &uResultObjectId, &xyzResultWorldRadiansFeet, dwInterogationResults)))
        {
            if ((dwInterogationResults & P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_OBJECTS) != 0)
            {
                hit_object_ID = uResultObjectId;
                hit_location = xyzResultWorldRadiansFeet;
            }
            else if ((dwInterogationResults & P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_TERRAIN) != 0)
            {
                hit_location = xyzResultWorldRadiansFeet;
            }
        }

        // Terrain Pass if no hit detected.
        if (dwInterogationResults == P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_NONE)
        {

            if (SUCCEEDED(spRayTraceManager->InterrogateWorldRay(P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_TERRAIN, 0, vWorldRadiansFeet, xyzWorldUnitRayDir,
                4000, 1, &uResultObjectId, &xyzResultWorldRadiansFeet, dwInterogationResults)))
            {
                if ((dwInterogationResults & P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_TERRAIN) != 0)
                {
                    hit_location = xyzResultWorldRadiansFeet;
                }
            }
        }
    }

    result_location.LLA.Latitude = RadToDeg(hit_location.dZ);
    result_location.LLA.Longitude = RadToDeg(hit_location.dX);
    result_location.LLA.Altitude = FeetToMeters(hit_location.dY);

    return result_location;
}
Beau Hollis
Prepar3D Software Architect
JB3DG
Posts: 609
Joined: Mon Jan 09, 2012 6:44 pm

Re: RayCast ObjectID return

Post by JB3DG »

Out of curiosity, would this system accurately return the lat/lon/alt of say a point on the side of a building if I were to use it for simulating laser range finding?
Jonathan Bleeker
Milviz systems dev

Formerly known as Naruto-kun
virtuali
Posts: 598
Joined: Tue Sep 27, 2011 12:51 pm

Re: RayCast ObjectID return

Post by virtuali »

Hi Beau,

thanks a lot for your code, I tried it, and it seems to work a bit different, but is still not right.

- the mouse picking bWasHit is always false, is this normal ?

- I used the undocumented uMessage to check the mouse click status. It seems to be 512 when no mouse is clicked and 513 after a left click, so I AND-ed to 1 to detect left clicks, and it seems to work.

Could you provide an updated documentation to what all these data fields do ?

- the Lat/Lon coordinates returned in result_location are not very precise.

They are reasonably precise if I am in a Top-Down view with some height but, the lower the height ( zooming in in Top-View view ), the less precise the coordinates are, until after a certain zoom, when they are always basically the same of the user airplane.

If I use a different view, like Spot plane, they are very wrong so, it seems the code works correct only when the view is perpendicular to the user airplane, and the camera is very high from ground.

I use the code almost unmodified, the only difference is that, because the code as posted doesn't compile as it is:

Code: Select all

ICameraSystemV450* pCamera = static_cast<ICameraSystemV450*>(mWindow->GetCameraSystem());

mWindow is not declared anywhere in that piece of code, but I'm getting the camera this way:

Code: Select all


auto pWPluginSystem = PdkServices::GetWindowPluginSystem();
if (pWPluginSystem != nullptr)
{
	m_pWindow = (P3D::IWindow*)pWPluginSystem->GetCurrentWindow();

	if (m_pWindow != nullptr)
	{
		m_pCamera = (P3D::ICameraSystem*)m_pWindow->GetCameraSystem();


So, my camera pointer points to ICameraSystem, which is defined as ICameraSystemV430, because I'm using the 4.3 SDK.

Is this the problem ? Is this code working only with the 4.5 SDK ?
Umberto Colapicchioni - VIRTUALI Sagl
http://www.fsdreamteam.com
MNWinchester
Posts: 3
Joined: Wed Jul 10, 2019 9:13 pm

Re: RayCast ObjectID return

Post by MNWinchester »

virtuali wrote: Wed Jul 10, 2019 1:09 am Hi Beau,

thanks a lot for your code, I tried it, and it seems to work a bit different, but is still not right.

- the mouse picking bWasHit is always false, is this normal ?

- I used the undocumented uMessage to check the mouse click status. It seems to be 512 when no mouse is clicked and 513 after a left click, so I AND-ed to 1 to detect left clicks, and it seems to work.

Could you provide an updated documentation to what all these data fields do ?

- the Lat/Lon coordinates returned in result_location are not very precise.

They are reasonably precise if I am in a Top-Down view with some height but, the lower the height ( zooming in in Top-View view ), the less precise the coordinates are, until after a certain zoom, when they are always basically the same of the user airplane.

If I use a different view, like Spot plane, they are very wrong so, it seems the code works correct only when the view is perpendicular to the user airplane, and the camera is very high from ground.

I use the code almost unmodified, the only difference is that, because the code as posted doesn't compile as it is:

Code: Select all

ICameraSystemV450* pCamera = static_cast<ICameraSystemV450*>(mWindow->GetCameraSystem());

mWindow is not declared anywhere in that piece of code, but I'm getting the camera this way:

Code: Select all


auto pWPluginSystem = PdkServices::GetWindowPluginSystem();
if (pWPluginSystem != nullptr)
{
	m_pWindow = (P3D::IWindow*)pWPluginSystem->GetCurrentWindow();

	if (m_pWindow != nullptr)
	{
		m_pCamera = (P3D::ICameraSystem*)m_pWindow->GetCameraSystem();


So, my camera pointer points to ICameraSystem, which is defined as ICameraSystemV430, because I'm using the 4.3 SDK.

Is this the problem ? Is this code working only with the 4.5 SDK ?

Hi Virtuali,
To follow up on some of your questions:

- the mouse picking bWasHit is always false, is this normal ?
In this case, yes, the pick result is only true if the mouse pick request intersected something 'pickable', and generally, terrain is not pickable. This pick request is retrieved in the code snippet Beau posted only to get the location of the mouse.

- the Lat/Lon coordinates returned in result_location are not very precise.
Interesting find! I will look into that.

- Is this code working only with the 4.5 SDK?
As for your concerns about 4.3 vs 4.5 SDK, since the difference there is how you are getting an IWindow pointer, I'm not sure that is the problem, but I will verify that the LLA results (inaccurate or not) are consistent regardless of SDK version.

I will post an update once I can verify what you're seeing.

Thank you for your feedback!
Matt
MNWinchester
Posts: 3
Joined: Wed Jul 10, 2019 9:13 pm

Re: RayCast ObjectID return

Post by MNWinchester »

Hi again Virtuali,

I did some tests at different altitudes with Top Down views and Locked Spot views, with both ICameraSystemV450/IWindowV450 and ICameraSystemV430/IWindowV430 pointers, and I am getting accurate results, both zoomed in near the aircraft and zoomed very far out.

Could you provide some specific points you are seeing inaccurate results for the latitude and longitude?
Are you referring to the the final "result_location" that comes out of the InterrogateWorldRay? Or the location of the mouse pick result?

If you can provide a complete code snippet of what you are doing, that would be helpful too.

Thanks,
Matt
virtuali
Posts: 598
Joined: Tue Sep 27, 2011 12:51 pm

Re: RayCast ObjectID return

Post by virtuali »

MNWinchester wrote: Thu Jul 11, 2019 7:38 pmIf you can provide a complete code snippet of what you are doing, that would be helpful too.

Hi Matt,

after some debugging, I think I found the problem: it was always picking Simobjects, which is weird, since there weren't any where I clicked so, I fixed it by just removing this whole section:

Code: Select all

        // Interrogate for Objects or Terrain
        if (SUCCEEDED(spRayTraceManager->InterrogateWorldRay(P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_OBJECTS | P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_TERRAIN,
            0, vWorldRadiansFeet, xyzWorldUnitRayDir, 4000, 1,
            &uResultObjectId, &xyzResultWorldRadiansFeet, dwInterogationResults)))
        {
            if ((dwInterogationResults & P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_OBJECTS) != 0)
            {
                hit_object_ID = uResultObjectId;
                hit_location = xyzResultWorldRadiansFeet;
            }
            else if ((dwInterogationResults & P3D::INTEROGATIONTYPE::INTEROGATIONTYPE_TERRAIN) != 0)
            {
                hit_location = xyzResultWorldRadiansFeet;
            }
        }

Which I don't need, since I only need coordinates on ground. Now, it works by doing only the code block after the " // Terrain Pass if no hit detected" comment.
Umberto Colapicchioni - VIRTUALI Sagl
http://www.fsdreamteam.com
Post Reply