Cast a ray at LineSegments

Hi, I have a square i generated with LineSegments

     geometry = new BufferGeometry;
     geometry.addAttribute('position', new BufferAttribute(new Float32Array(vertices), 3));
     geometry.addAttribute('color', new BufferAttribute(new Uint8Array(colors), 3));

     let line = new LineSegments(geometry, material);

When using a raycast on it, it only works when i mouse over the lines. but when am inside the box it doesn’t work (expected) how can i get this to work, both on lines and inside the square)

Fiddle HERE

You can create a mesh for the square and provide it with a completely transparent material.

1 Like

Since am using LineSegments how can i add a mesh? sorry am new.

A similar example.

<!DOCTYPE html>
<!--  @author hofk, based on http://threejs.live/#/webgl_interactive_buffergeometry -->
<head>
<title> raycast </title>
<meta charset="utf-8">
 <style>
 body {
 margin: 0;
 }
 </style>
</head>
<body>

<div id="container"></div>		
<script src="three.min.101.js"></script>
<script src="OrbitControls.js"></script>
<script>
var container, camera, scene, renderer, raycaster, mouse, mesh, line;
init();
animate();
//................
function init() {
	container = document.getElementById( 'container' );
	camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.1, 35000 );
	camera.position.set( -1, 3, 6 ); 
	scene = new THREE.Scene();
	scene.background = new THREE.Color( 0xaaaaaa );
	scene.add( new THREE.AmbientLight( 0x888888 ) );
	var light1 = new THREE.DirectionalLight( 0xffffff, 0.8 );
	light1.position.set( 1, 1, 1 );
	scene.add( light1 );
	var light2 = new THREE.DirectionalLight( 0xffffff, 0.6 );
	light2.position.set( 0, -1, 0 );
	scene.add( light2 );
	controls = new THREE.OrbitControls(camera);	
	
  	var geometry = new THREE.BoxBufferGeometry( );					
	var material = new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, color: 0xff2222, transparent: true, opacity: 0.1 } ) ;

	mesh = new THREE.Mesh( geometry, material );
	scene.add( mesh );
	raycaster = new THREE.Raycaster();
	mouse = new THREE.Vector2();
	var geometry = new THREE.BufferGeometry();
	geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( 4 * 3 ), 3 ) );	
	var material = new THREE.LineBasicMaterial( { color: 0xffffff } );
	line = new THREE.Line( geometry, material );
	scene.add( line );	
	renderer = new THREE.WebGLRenderer( { antialias: false } );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	container.appendChild( renderer.domElement );
	window.addEventListener( 'resize', onWindowResize, false );
	document.addEventListener( 'mousemove', onDocumentMouseMove, false );
}
function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
	event.preventDefault();
	mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
	mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function animate() {
	requestAnimationFrame( animate );
	render();	
}
function render() {
	var time = Date.now() * 0.001;
	raycaster.setFromCamera( mouse, camera );
	var intersects = raycaster.intersectObject( mesh );
	if ( intersects.length > 0 ) {
		var intersect = intersects[ 0 ];
		var face = intersect.face;
		var linePosition = line.geometry.attributes.position;
		var meshPosition = mesh.geometry.attributes.position;
		linePosition.copyAt( 0, meshPosition, face.a );
		linePosition.copyAt( 1, meshPosition, face.b );
		linePosition.copyAt( 2, meshPosition, face.c );
		linePosition.copyAt( 3, meshPosition, face.a );
		mesh.updateMatrix();
		line.geometry.applyMatrix( mesh.matrix );
		line.visible = true;
	} else {
		line.visible = false;
	}
	renderer.render( scene, camera );
}
</script>
</body>
</html>
2 Likes

If you’re new, check out these examples.

I left it out of my question but am using LineSegments because am changing the color of each line on raycast hit.

Are you looking for something like this?

1 Like

In these examples I determine whether raycast selects a corner or edge or (more in the middle) the triangle.

Modify indexed BufferGeometry (mouse or input)
( http://discourse.threejs.hofk.de/2018/Xindex2018.html Example at the bottom)

http://sandboxthreef.threejs.hofk.de/modifyRaycastMultiMaterial.html

I’m not sure that variant was your target.

http://discourse.threejs.hofk.de/2019/RaycastForEdges/RaycastForEdges.html

<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/cast-a-ray-at-linesegments/6315/8 -->
<!-- http://discourse.threejs.hofk.de/2019/RaycastForEdges/RaycastForEdges.html -->
<head>
	<title> RaycastForEdges </title>
	<meta charset="utf-8" />
	<style>
	body {
	margin: 0;
	}
	</style>
</head>
<body> 	</body>
<script src="../js/three.min.101.js"></script>
<script src="../js/OrbitControls.js"></script>

<script>

// @author hofk

document.addEventListener('mousemove', onDocumentMouseMove, false);
var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();

var intersects 	= [];
var selection;

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( 0, 1, 4 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x000000, 1 );	
var container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement ); 

var controls = new THREE.OrbitControls( camera, renderer.domElement );

var faceIndices = [ 0,1,2, 0,2,3, 0,3,4, 0,4,1 ];

var vertices = [ 
	 0, 0, 0, // 0
	 1, 1, 0, // 1
	-1, 1, 0, // 2
	-1,-1, 0, // 3
	 1,-1, 0, // 4
	 1, 1, 0, // 1 for edge line
];

var material = new THREE.MeshBasicMaterial( { side: THREE.DoubleSide, color: 0xffff00, transparent: true, opacity: 0.0 } ) ;
var g = new THREE.BufferGeometry( );
g.setIndex( new THREE.BufferAttribute( new Uint32Array( faceIndices ), 1 ) );
g.addAttribute( 'position', new THREE.BufferAttribute(new Float32Array(vertices), 3 ) );
var mesh = new THREE.Mesh( g, material );
scene.add( mesh );

var mL = [];
var gL = [];
var line = [];
var vL = [];
var j;
var lineIdx;

for ( let i = 0; i < 4; i ++ ) {
		
	j = ( i + 1 ) * 3; 
	
	vL[ i ] = [];
	vL[ i ].push( vertices[ j ], vertices[ j + 1 ], vertices[ j + 2 ], vertices[ j + 3 ], vertices[ j + 4 ], vertices[ j + 5 ] );
	gL[ i ] = new THREE.BufferGeometry();
	gL[ i ].addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vL[ i ] ), 3 ) );
	mL[ i ] = new THREE.LineBasicMaterial( { color: 0x0000ff } );
	line[ i ] = new THREE.Line( gL[ i ], mL[ i ] );
	scene.add( line[ i ] );
	
}

animate();

// .......................

function animate() {

	requestAnimationFrame( animate );	
	renderer.render( scene, camera );
	controls.update();
	
}

function onDocumentMouseMove( event ) {

	// var b, c;
	
	mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
	mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;

	raycaster.setFromCamera( mouse, camera );	
	intersects = raycaster.intersectObject( mesh );
	
	if ( intersects.length > 0 ) {    // cutting object
	
		//b = intersects[0].face.b;
		//c = intersects[0].face.c;
		
		lineIdx = intersects[0].face.b - 1;
		line[ lineIdx ].material.color.setRGB( 255, 255, 0 );

  	} else {
		
		for( let i = 0; i < 4; i ++ ) line[ i ].material.color.setRGB( 0, 0, 255 );
		
	}

}

</script>

</html>
1 Like