# Raycasting intersection error

**URL:** <https://discourse.threejs.org/t/raycasting-intersection-error/83721>\
**Category:** Questions\
**Tags:** geometry\
**Created:** [June 7, 2025, 10:52pm UTC](https://discourse.threejs.org/t/raycasting-intersection-error/83721 "2025-06-07T22:52:52Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![niiik](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/niiik/32/60681_2.png) [@niiik](https://discourse.threejs.org/u/niiik)\
**Post date:** [June 7, 2025, 10:52pm UTC](https://discourse.threejs.org/t/raycasting-intersection-error/83721/1 "2025-06-07T22:52:52Z")

</div>

Hey! I’m trying to develop a program which takes a gltf file and lets users draw 3d strokes within a shape to fill it in, and then make the resulting mesh exportable. I’m running into an issue with actually getting the stroke to fall within the mesh- I attached a picture below. Currently I’m detecting if the stroke is within the mesh by checking if at least half of projected rays intersect the mesh but I’m not sure if that’s correct. I attached the problem methods below  
function getMousePosition(event) {  
mouse.x = (event.clientX / window.innerWidth) \* 2 - 1;  
mouse.y = -(event.clientY / window.innerHeight) \* 2 + 1;  
}

// Check if point is inside case boundary  
function isInsideCase(point) {  
if (caseGeometry.length === 0) return false;

// Cast rays in multiple directions to determine if point is inside  
const directions = [  
new THREE.Vector3(1, 0, 0),  
new THREE.Vector3(-1, 0, 0),  
new THREE.Vector3(0, 1, 0),  
new THREE.Vector3(0, -1, 0),  
new THREE.Vector3(0, 0, 1),  
new THREE.Vector3(0, 0, -1)  
];

let insideCount = 0;

for (let dir of directions) {  
raycaster.set(point, dir);  
const intersects = raycaster.intersectObjects(caseGeometry, true);  
if (intersects.length % 2 === 1) {  
insideCount++;  
}  
}

// If majority of rays indicate inside, point is inside  
return insideCount \> directions.length / 2;  
}

// Get intersection point with case  
function getIntersectionPoint(event) {  
getMousePosition(event);  
raycaster.setFromCamera(mouse, camera);

// First try to intersect with case meshes  
const caseIntersects = raycaster.intersectObjects(caseGeometry, true);  
if (caseIntersects.length \> 0) {  
const point = caseIntersects[0].point;  
// Offset slightly inward from the surface  
const normal = caseIntersects[0].face.normal.clone();  
normal.transformDirection(caseIntersects[0].object.matrixWorld);  
point.add(normal.multiplyScalar(-0.02));  
return point;  
}

// If no case intersection, create a point at a fixed distance from camera  
const direction = new THREE.Vector3();  
raycaster.ray.direction.clone().normalize();  
const distance = 2; // Fixed distance from camera  
const point = camera.position.clone().add(raycaster.ray.direction.multiplyScalar(distance));

return point;  
}

// Create tube geometry from stroke points  
function createStrokeTube(points, radius = 0.2) {  
if (points.length \< 4) return null;

try {  
const curve = new THREE.CatmullRomCurve3(points);  
const tubeGeometry = new THREE.TubeGeometry(curve, points.length \* 2, radius, 8, false);  
const tubeMaterial = new THREE.MeshStandardMaterial({  
color: 0xc0c0c0, // Silver color  
metalness: 0.8,  
roughness: 0.2,  
});

```
const mesh = new THREE.Mesh(tubeGeometry, tubeMaterial);
console.log('Successfully created tube mesh'); // Debug output
return mesh;

```

} catch (error) {  
console.error(‘Error creating tube:’, error);

```
// Fallback: create spheres at each point
const group = new THREE.Group();
const sphereGeometry = new THREE.SphereGeometry(radius, 8, 8);
const sphereMaterial = new THREE.MeshStandardMaterial({
  color: 0xc0c0c0,
  metalness: 0.8,
  roughness: 0.2,
});

points.forEach(point => {
  const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
  sphere.position.copy(point);
  group.add(sphere);
});

console.log('Created fallback spheres'); // Debug output
return group;

```

}  
}

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/f/2/f20363fcf62a03f0cf51755209f6ca58a3da2379.png)

---

<div class="post-metadata">

**Author:** ![Lawrence3DPK](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lawrence3dpk/32/29184_2.png) [@Lawrence3DPK](https://discourse.threejs.org/u/Lawrence3DPK)\
**Post date:** [June 8, 2025, 12:06am UTC](https://discourse.threejs.org/t/raycasting-intersection-error/83721/2 "2025-06-08T00:06:05Z")

</div>

Have you considered using three-mesh-bvh [intersections](https://gkjohnson.github.io/three-mesh-bvh/example/bundle/shapecast.html) or a simple [Box3.intersect](https://threejs.org/docs/#api/en/math/Box3.intersect) for this?

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [June 8, 2025, 7:07am UTC](https://discourse.threejs.org/t/raycasting-intersection-error/83721/3 "2025-06-08T07:07:03Z")

</div>

There are a couple gotchas with raycasting.

The first is that if your renderer is not COMPLETELY FULL SCREEN, the default mouse position calculation WILL NOT WORK:

```javascript
//This does not work if the renderer is not exactly the size of the window, no padding, no margin, etc.
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

```

Another gotcha, is that as soon as you start adding markers for what you’ve hit, those markers will start getting ray hits first, so if you’re only processing the first hit [0] from a scene raycast, and adding a marker for the hit, the next cast you do will hit your marker first and the result will be wrong.

Do you think either of these gotchas are in play?

(And.. just to reassure you.. when set up correctly.. raycasting works pretty flawlessly, so this is 99.% not some weird bug in threejs.)
