| 2447 | } |
| 2448 | |
| 2449 | void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, Array<Vector3>& result) |
| 2450 | { |
| 2451 | PROFILE_CPU(); |
| 2452 | PROFILE_MEM(LevelTerrain); |
| 2453 | result.Clear(); |
| 2454 | |
| 2455 | // Skip if no intersection with patch |
| 2456 | if (!CollisionsHelper::BoxIntersectsSphere(GetBounds(), bounds) || !_physicsHeightField) |
| 2457 | return; |
| 2458 | |
| 2459 | // Prepare |
| 2460 | const auto& triangles = GetCollisionTriangles(); |
| 2461 | const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::ChunksCountEdge; |
| 2462 | Transform transform; |
| 2463 | transform.Translation = _offset + Vector3(0, _yOffset, 0); |
| 2464 | transform.Orientation = Quaternion::Identity; |
| 2465 | transform.Scale = Vector3(1.0f, _yHeight, 1.0f); |
| 2466 | transform = _terrain->_transform.LocalToWorld(transform); |
| 2467 | Matrix world; |
| 2468 | transform.GetWorld(world); |
| 2469 | Matrix invWorld; |
| 2470 | Matrix::Invert(world, invWorld); |
| 2471 | |
| 2472 | // Project bounds to terrain surface XZ plane to find the heightfield range that might intersect with the brush |
| 2473 | BoundingBox box; |
| 2474 | BoundingBox::FromSphere(bounds, box); |
| 2475 | Vector3 min, max; |
| 2476 | Vector3::Transform(box.Minimum, invWorld, min); |
| 2477 | Vector3::Transform(box.Maximum, invWorld, max); |
| 2478 | { |
| 2479 | Vector3 t = min; |
| 2480 | Vector3::Min(t, max, min); |
| 2481 | Vector3::Max(t, max, max); |
| 2482 | } |
| 2483 | |
| 2484 | // Normalize bounds and map to actual triangles buffer |
| 2485 | int32 rows, cols; |
| 2486 | PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); |
| 2487 | int32 startRow = (int32)Math::Floor(min.X / size * rows); |
| 2488 | int32 startCol = (int32)Math::Floor(min.Z / size * cols); |
| 2489 | int32 endRow = (int32)Math::Ceil(max.X / size * rows); |
| 2490 | int32 endCol = (int32)Math::Ceil(max.Z / size * cols); |
| 2491 | |
| 2492 | // Normalize bounds to patch borders |
| 2493 | startRow = Math::Clamp(startRow, 0, rows - 2); |
| 2494 | startCol = Math::Clamp(startCol, 0, cols - 2); |
| 2495 | endRow = Math::Clamp(endRow, 0, rows - 2); |
| 2496 | endCol = Math::Clamp(endCol, 0, cols - 2); |
| 2497 | |
| 2498 | // Shortcut: row=x, col=z |
| 2499 | |
| 2500 | // Check every triangle from the given range |
| 2501 | for (int32 row = startRow; row <= endRow; row++) |
| 2502 | { |
| 2503 | for (int32 col = startCol; col <= endCol; col++) |
| 2504 | { |
| 2505 | int32 index = (row * (cols - 1) + col) * 6; |
| 2506 | Vector3 t0 = triangles[index + 0]; |
no test coverage detected