X-Plane 12中XPLMProbeTerrainXYZ始终在相机原点命中且地形返回异常
X-Plane 12 地形射线投射问题排查
我尝试在X-Plane 12中使用XPLMProbeTerrainXYZ获取鼠标(或相机方向)下方的3D地形位置,编写了如下C++函数:
bool GetCameraSightIntersection(float* outX, float* outY, float* outZ, float* outNormalX, float* outNormalY, float* outNormalZ, bool* outIsWet) { if (g_terrain_probe == nullptr) { g_terrain_probe = XPLMCreateProbe(xplm_ProbeY); if (g_terrain_probe == nullptr) { return false; } } float cam_x = g_initial_camera_pos.x; float cam_y = g_initial_camera_pos.y; float cam_z = g_initial_camera_pos.z; float cam_heading = g_initial_camera_pos.heading; float cam_pitch = -g_initial_camera_pos.pitch; float heading_rad = cam_heading * M_PI / 180.0f; float pitch_rad = cam_pitch * M_PI / 180.0f; float forward_x = sin(heading_rad) * cos(pitch_rad); float forward_y = sin(pitch_rad); float forward_z = cos(heading_rad) * cos(pitch_rad); const int max_probes = 100; const float probe_distance = 100.0f; const float max_distance = 10000.0f; for (int i = 0; i < max_probes; i++) { float distance = i * probe_distance; if (distance > max_distance) break; float probe_x = cam_x + forward_x * distance; float probe_y = cam_y - forward_y * distance; float probe_z = cam_z - forward_z * distance; XPLMProbeInfo_t probe_info; probe_info.structSize = sizeof(XPLMProbeInfo_t); XPLMProbeResult result = XPLMProbeTerrainXYZ(g_terrain_probe, probe_x, probe_y, probe_z, &probe_info); if (result == xplm_ProbeHitTerrain) { if (outX) *outX = probe_info.locationX; if (outY) *outY = probe_info.locationY; if (outZ) *outZ = probe_info.locationZ; if (outNormalX) *outNormalX = probe_info.normalX; if (outNormalY) *outNormalY = probe_info.normalY; if (outNormalZ) *outNormalZ = probe_info.normalZ; if (outIsWet) *outIsWet = (probe_info.is_wet != 0); return true; } } return false; }
遇到的问题
问题1:XPLMCreateProbe是否创建了无效探针?
预期XPLMCreateProbe(xplm_ProbeY)返回有效探针对象,但地形命中结果不符合预期,程序未崩溃。
问题2:探针总是在i == 0时返回命中
即使相机处于空中,循环第一步就检测到地形命中,但实际相机并未接触地形。
核心需求
从相机位置沿朝向投射射线,获取与地面的交点(比如鼠标或视野中心对应的地面3D点),怀疑相机方向计算有误。
疑问
- 有没有更高效的相机到地形射线投射方法?
- 为什么相机在空中时,
XPLMProbeTerrainXYZ在相机位置就能返回命中? XPLMCreateProbe在X-Plane 12中会静默失败吗?
问题解答
1. XPLMCreateProbe的有效性问题
XPLMCreateProbe(xplm_ProbeY)在X-Plane 12中不会静默失败,只有返回nullptr时才代表创建失败。你的代码已经做了空指针检查,程序未崩溃说明探针大概率是有效的,问题出在后续逻辑或方向计算上。
2. 相机空中却在初始位置命中的原因
XPLMProbeTerrainXYZ的工作逻辑是:从你传入的坐标**沿Y轴负方向(向下)**探测地形,只要该点正下方存在地形,就会返回命中结果——不管相机是否在空中。你循环的第一步i=0时,探针坐标就是相机坐标,自然会直接探测相机正下方的地形,这就是为什么总是在第一步得到命中结果。
3. 更优的射线投射方法
当前的步进式探测效率低、精度差,X-Plane提供了直接的射线探测API XPLMProbeTerrainRay,可以沿任意射线方向直接获取地形交点,完全匹配你的需求。
修改后的核心逻辑示例:
// 替换原有的循环部分 XPLMProbeInfo_t probe_info; probe_info.structSize = sizeof(XPLMProbeInfo_t); // 传入相机起点、射线方向向量、最大探测距离 XPLMProbeResult result = XPLMProbeTerrainRay( g_terrain_probe, cam_x, cam_y, cam_z, // 射线起点(相机位置) forward_x, forward_y, forward_z, // 射线方向向量(需确保单位化) max_distance, // 最大探测距离 &probe_info ); if (result == xplm_ProbeHitTerrain) { // 填充输出参数 if (outX) *outX = probe_info.locationX; if (outY) *outY = probe_info.locationY; if (outZ) *outZ = probe_info.locationZ; if (outNormalX) *outNormalX = probe_info.normalX; if (outNormalY) *outNormalY = probe_info.normalY; if (outNormalZ) *outNormalZ = probe_info.normalZ; if (outIsWet) *outIsWet = (probe_info.is_wet != 0); return true; } return false;
另外需要修正方向向量的两个问题:
- 符号检查:X-Plane坐标系为X轴东、Y轴上、Z轴北,俯仰角的符号需要确认。如果相机向上俯仰时pitch为正,
cam_pitch = -g_initial_camera_pos.pitch可能需要调整,建议打印forward_y值,确保相机向下看时该值为负。 - 单位化处理:方向向量必须是单位向量,否则
XPLMProbeTerrainRay的距离计算会出错,可添加归一化代码:
float length = sqrt(forward_x*forward_x + forward_y*forward_y + forward_z*forward_z); if (length > 1e-6) { forward_x /= length; forward_y /= length; forward_z /= length; }
总结
- 用
XPLMProbeTerrainRay替代步进式探测,效率和精度更高 XPLMCreateProbe不会静默失败,返回nullptr才是创建失败,你的探针是有效的- 初始位置命中是因为
XPLMProbeTerrainXYZ仅探测点正下方,而非沿你的射线方向 - 检查方向向量的符号和单位化,确保射线方向正确
内容的提问来源于stack exchange,提问作者oKami
相关产品推荐
相关产品推荐

