Aller au contenu

3D point-triangle collision detection in Scratch

Ce contenu n’est pas encore disponible dans votre langue.

💡 Struggling with advanced 3D math and collision detection? Need expert guidance for complex algorithms? 🚀 Get Math Expert Help

MW

Math3D_Wizard

Posted on July 25, 2025 • Expert

🎯 Question

I’m working on a 3D game in Scratch and need to detect when a point (like the player) collides with a triangle in 3D space. I understand this involves projecting the point onto the triangle’s plane and then checking if it’s inside the triangle, but I’m struggling with the mathematical implementation. Can someone provide a complete solution with proper vector math?

👁️ 260 views💬 3 replies⏰ Last reply: July 25, 2025

🔬 Complete 3D Point-Triangle Collision Detection

Section titled “🔬 Complete 3D Point-Triangle Collision Detection”

Detecting collision between a point and a triangle in 3D space is one of the most fundamental operations in 3D graphics and game development. This involves several mathematical concepts including plane equations, vector projections, and barycentric coordinates.

flowchart TD A[3D Point P] --> B[Calculate Triangle Normal] B --> C[Project Point onto Plane] C --> D[Convert to 2D Coordinates] D --> E[Point-in-Triangle Test] E --> F{Inside Triangle?} F -->|Yes| G[Collision Detected] F -->|No| H[No Collision] style A fill:#e1f5fe style G fill:#c8e6c9 style H fill:#ffcdd2

🎯 Step 1: Calculate Triangle Normal Vector

Section titled “🎯 Step 1: Calculate Triangle Normal Vector”

First, we need to find the normal vector of the triangle’s plane using the cross product:

    // Calculate triangle normal vector
define calculate triangle normal
set [edge1 x v] to ((triangle B x) - (triangle A x))
set [edge1 y v] to ((triangle B y) - (triangle A y))
set [edge1 z v] to ((triangle B z) - (triangle A z))

set [edge2 x v] to ((triangle C x) - (triangle A x))
set [edge2 y v] to ((triangle C y) - (triangle A y))
set [edge2 z v] to ((triangle C z) - (triangle A z))

// Cross product: edge1 × edge2
set [normal x v] to (((edge1 y) * (edge2 z)) - ((edge1 z) * (edge2 y)))
set [normal y v] to (((edge1 z) * (edge2 x)) - ((edge1 x) * (edge2 z)))
set [normal z v] to (((edge1 x) * (edge2 y)) - ((edge1 y) * (edge2 x)))

// Normalize the normal vector
set [normal length v] to ([sqrt v] of (((normal x) * (normal x)) + ((normal y) * (normal y)) + ((normal z) * (normal z))))
set [normal x v] to ((normal x) / (normal length))
set [normal y v] to ((normal y) / (normal length))
set [normal z v] to ((normal z) / (normal length))
  

🎯 Step 2: Project Point onto Triangle Plane

Section titled “🎯 Step 2: Project Point onto Triangle Plane”

Next, we project the 3D point onto the triangle’s plane:

    // Project point onto triangle plane
define project point onto plane
// Calculate distance from point to plane
set [to point x v] to ((point x) - (triangle A x))
set [to point y v] to ((point y) - (triangle A y))
set [to point z v] to ((point z) - (triangle A z))

// Dot product with normal
set [distance to plane v] to (((to point x) * (normal x)) + ((to point y) * (normal y)) + ((to point z) * (normal z)))

// Project point onto plane
set [projected x v] to ((point x) - ((distance to plane) * (normal x)))
set [projected y v] to ((point y) - ((distance to plane) * (normal y)))
set [projected z v] to ((point z) - ((distance to plane) * (normal z)))
  

We need to create a 2D coordinate system on the triangle’s plane:

    // Create 2D coordinate system on triangle plane
define create 2d coordinate system
// Use edge1 as U axis (already calculated)
set [u axis x v] to (edge1 x)
set [u axis y v] to (edge1 y)
set [u axis z v] to (edge1 z)

// Normalize U axis
set [u length v] to ([sqrt v] of (((u axis x) * (u axis x)) + ((u axis y) * (u axis y)) + ((u axis z) * (u axis z))))
set [u axis x v] to ((u axis x) / (u length))
set [u axis y v] to ((u axis y) / (u length))
set [u axis z v] to ((u axis z) / (u length))

// Calculate V axis: normal × U axis
set [v axis x v] to (((normal y) * (u axis z)) - ((normal z) * (u axis y)))
set [v axis y v] to (((normal z) * (u axis x)) - ((normal x) * (u axis z)))
set [v axis z v] to (((normal x) * (u axis y)) - ((normal y) * (u axis x)))
  

Convert all points to the 2D coordinate system:

    // Convert 3D points to 2D coordinates
define convert to 2d (x) (y) (z)
// Vector from triangle A to the point
set [to point x v] to ((x) - (triangle A x))
set [to point y v] to ((y) - (triangle A y))
set [to point z v] to ((z) - (triangle A z))

// Project onto U and V axes
set [u coord v] to (((to point x) * (u axis x)) + ((to point y) * (u axis y)) + ((to point z) * (u axis z)))
set [v coord v] to (((to point x) * (v axis x)) + ((to point y) * (v axis y)) + ((to point z) * (v axis z)))

// Convert triangle vertices to 2D
convert to 2d (triangle A x) (triangle A y) (triangle A z)
set [triangle A 2d u v] to (u coord)
set [triangle A 2d v v] to (v coord)

convert to 2d (triangle B x) (triangle B y) (triangle B z)
set [triangle B 2d u v] to (u coord)
set [triangle B 2d v v] to (v coord)

convert to 2d (triangle C x) (triangle C y) (triangle C z)
set [triangle C 2d u v] to (u coord)
set [triangle C 2d v v] to (v coord)

// Convert projected point to 2D
convert to 2d (projected x) (projected y) (projected z)
set [point 2d u v] to (u coord)
set [point 2d v v] to (v coord)
  

🎯 Step 5: Point-in-Triangle Test (Barycentric Coordinates)

Section titled “🎯 Step 5: Point-in-Triangle Test (Barycentric Coordinates)”

Use barycentric coordinates to determine if the point is inside the triangle:

    // Point-in-triangle test using barycentric coordinates
define point in triangle 2d
// Calculate vectors
set [v0 u v] to ((triangle C 2d u) - (triangle A 2d u))
set [v0 v v] to ((triangle C 2d v) - (triangle A 2d v))
set [v1 u v] to ((triangle B 2d u) - (triangle A 2d u))
set [v1 v v] to ((triangle B 2d v) - (triangle A 2d v))
set [v2 u v] to ((point 2d u) - (triangle A 2d u))
set [v2 v v] to ((point 2d v) - (triangle A 2d v))

// Calculate dot products
set [dot00 v] to (((v0 u) * (v0 u)) + ((v0 v) * (v0 v)))
set [dot01 v] to (((v0 u) * (v1 u)) + ((v0 v) * (v1 v)))
set [dot02 v] to (((v0 u) * (v2 u)) + ((v0 v) * (v2 v)))
set [dot11 v] to (((v1 u) * (v1 u)) + ((v1 v) * (v1 v)))
set [dot12 v] to (((v1 u) * (v2 u)) + ((v1 v) * (v2 v)))

// Calculate barycentric coordinates
set [inv denom v] to (1 / (((dot00) * (dot11)) - ((dot01) * (dot01))))
set [u bary v] to (((dot11) * (dot02)) - ((dot01) * (dot12))) * (inv denom)
set [v bary v] to (((dot00) * (dot12)) - ((dot01) * (dot02))) * (inv denom)

// Check if point is inside triangle
if <<((u bary) > 0) and <((v bary) > 0)>> and <((u bary) + (v bary)) < 1>> then
set [collision result v] to [true]
else
set [collision result v] to [false]
end
  

🚀 Step 6: Complete Collision Detection System

Section titled “🚀 Step 6: Complete Collision Detection System”
    // Main collision detection function
define check 3d triangle collision
calculate triangle normal
project point onto plane
create 2d coordinate system
convert to 2d (projected x) (projected y) (projected z)
point in triangle 2d

// Optional: Add distance threshold for near collisions
set [distance threshold v] to [5]  // Adjust as needed
if <<(collision result) = [true]> and <([abs v] of (distance to plane)) < (distance threshold)>> then
set [final collision v] to [true]
broadcast [player hit triangle v]
else
set [final collision v] to [false]
end
  
    // Use in your main game loop
when flag clicked
forever
// Update player position
change [player x v] by (player velocity x)
change [player y v] by (player velocity y)
change [player z v] by (player velocity z)

// Check collision with each triangle
set [triangle index v] to [1]
repeat (number of triangles)
// Load triangle data
set [triangle A x v] to (item (triangle index) of [triangle A x list v])
set [triangle A y v] to (item (triangle index) of [triangle A y list v])
set [triangle A z v] to (item (triangle index) of [triangle A z list v])
// ... load B and C vertices similarly

// Set point to check (player position)
set [point x v] to (player x)
set [point y v] to (player y)
set [point z v] to (player z)

// Perform collision check
check 3d triangle collision

if <(final collision) = [true]> then
// Handle collision
say [Hit triangle!] for (1) seconds
// Implement collision response (bounce, stop, etc.)
end

change [triangle index v] by (1)
end
end
  
flowchart LR A[Broad Phase] --> B[Spatial Partitioning] B --> C[AABB Culling] C --> D[Detailed Collision] D --> E[Response] F[Optimizations] --> G[Early Exit] F --> H[Precompute Normals] F --> I[Use Fixed Point] F --> J[Batch Processing] style A fill:#e3f2fd style F fill:#fff3e0
  1. Precompute Triangle Normals: Calculate normals once when loading the level
  2. Use Spatial Partitioning: Only check triangles near the player
  3. Early Exit: Skip expensive calculations when possible
  4. Batch Processing: Check multiple points at once
    // Optimized collision checking with early exit
define optimized triangle collision
// Quick AABB check first
if <<((point x) < (triangle min x)) or ((point x) > (triangle max x))> or <<((point y) < (triangle min y)) or ((point y) > (triangle max y))>> then
set [collision result v] to [false]
stop [this script v]
end

// Only do expensive calculation if AABB passes
check 3d triangle collision
  

The cross product of two vectors a × b gives us a vector perpendicular to both, which is perfect for finding the triangle’s normal:

normal = (B - A) × (C - A)

Barycentric coordinates express a point as a weighted combination of the triangle’s vertices:

P = uA + vB + wC where u + v + w = 1

A point is inside the triangle if:

  • u ≥ 0
  • v ≥ 0
  • u + v ≤ 1

For more realistic collision detection, you can add a distance threshold:

    // Advanced collision with distance threshold
define advanced collision check
check 3d triangle collision

// Check if point is within threshold distance
set [collision distance v] to ([abs v] of (distance to plane))

if <<(collision result) = [true]> and <(collision distance) < (collision threshold)>> then
set [collision strength v] to (1 - ((collision distance) / (collision threshold)))
set [final collision v] to [true]
else
set [final collision v] to [false]
end
  

This implementation provides a complete, mathematically accurate solution for 3D point-triangle collision detection in Scratch. The system is optimized for performance while maintaining precision, making it suitable for real-time 3D games.


VG

VectorGenius_Pro

July 25, 2025 at 2:15 PM

Excellent mathematical breakdown! I’d add that for performance-critical applications, you might want to precompute the triangle normals and store them in lists. Also, consider using octrees or BSP trees for spatial partitioning when dealing with complex 3D scenes with many triangles.

GM

GameMath_Expert

July 25, 2025 at 3:30 PM

This is a comprehensive solution! For beginners, I recommend starting with simpler 2D triangle collision detection first, then moving to 3D. The barycentric coordinate method is mathematically elegant and works well for both convex and non-convex triangles. Great work on the optimization tips too!

MW

Math3D_Wizard

July 25, 2025 at 4:45 PM • ✓ Best Answer

Thank you both for the additional insights! @VectorGenius_Pro, you’re absolutely right about precomputing normals and spatial partitioning. @GameMath_Expert, great point about starting with 2D first. I’ve updated my implementation to include these optimizations. This should handle most 3D collision scenarios efficiently in Scratch!