Unity:如何从球体与平面的碰撞点发射射线?
解决方案:从球体与平面的碰撞接触点映射地形生成预制体
原代码的核心问题在于:使用OnTriggerEnter无法获取真实的碰撞接触点数据,且通过transform.forward发射射线只能固定取球体正前方的点,而非球体与平面实际接触的位置。以下是修正后的实现方案:
关键修正点
- 改用
OnCollisionEnter回调(而非OnTriggerEnter),该回调能提供完整的碰撞接触信息 - 直接从
collision.contacts中提取球体与平面的碰撞点,而非通过固定方向射线模拟 - 将世界空间的碰撞点转换为平面的纹理UV坐标,再映射到地形相机的视口射线
完整代码实现
// 确保球体和平面的Collider都未勾选Is Trigger,否则无法触发OnCollisionEnter private void OnCollisionEnter(Collision collision) { if (collision.gameObject.CompareTag("Plane")) { // 遍历所有碰撞接触点(球体碰平面通常只有1个点,遍历兼容多接触场景) foreach (ContactPoint contact in collision.contacts) { // 将世界空间的碰撞点转换为平面的局部空间坐标 Vector3 localPoint = collision.transform.InverseTransformPoint(contact.point); // 计算平面的纹理UV坐标:示例假设平面是XY平面(局部Z轴向上),UV对应X/Z轴 // 若你的平面是XZ平面(Y轴向上),则替换为localPoint.x和localPoint.z Vector2 uv = new Vector2( (localPoint.x / collision.transform.localScale.x + 0.5f), (localPoint.z / collision.transform.localScale.z + 0.5f) ); // 确保UV在0-1范围内,避免视口射线越界 uv = Vector2.Clamp01(uv); // 通过地形相机发射视口射线到地形 Ray terrainRay = terrainCamera.ViewportPointToRay(uv); if (Physics.Raycast(terrainRay, out RaycastHit terrainHit)) { StartCoroutine(SpawnObjectOnTerrain(terrainHit.point)); } // 若仅需处理第一个接触点,可添加break跳出循环 // break; } } }
注意事项
- Collider设置:必须取消球体和平面的
Is Trigger勾选,OnCollisionEnter才会触发并生成接触点数据 - 平面朝向适配:根据你使用的平面朝向调整UV计算的轴,比如XZ平面(Y轴向上)需用
localPoint.x和localPoint.z - 平面缩放处理:如果平面有非均匀缩放,必须将局部坐标除以对应轴的缩放值,才能得到正确的UV范围
- 多接触点处理:如果球体滚动时会产生多个接触点,可根据需求选择处理第一个点或所有点
效果对比

上方:原方案仅从球体正前方发射射线;下方:修正后从实际碰撞接触点发射射线
内容的提问来源于stack exchange,提问作者jacob_p
相关产品推荐
相关产品推荐

