raycastScreenSpace function

void raycastScreenSpace(
  1. LineSegments2 lineSegments,
  2. Camera camera,
  3. List<Intersection> intersects
)

Implementation

void raycastScreenSpace(LineSegments2 lineSegments,Camera camera,List<Intersection> intersects ) {
	final projectionMatrix = camera.projectionMatrix;
	final material = lineSegments.material as LineMaterial;
	final resolution = material.resolution;
	final matrixWorld = lineSegments.matrixWorld;

	final geometry = lineSegments.geometry!;
	final instanceStart = geometry.attributes['instanceStart'];
	final instanceEnd = geometry.attributes['instanceEnd'];
	final segmentCount = math.min<int>( geometry.instanceCount!, instanceStart.count );

	final near = - camera.near;

	//

	// pick a point 1 unit out along the ray to avoid the ray origin
	// sitting at the camera origin which will cause "w" to be 0 when
	// applying the projection matrix.
	_ray.at( 1, _ssOrigin );

	// ndc space [ - 1.0, 1.0 ]
	_ssOrigin.w = 1;
	_ssOrigin.applyMatrix4( camera.matrixWorldInverse );
	_ssOrigin.applyMatrix4( projectionMatrix );
	_ssOrigin.scale( 1 / _ssOrigin.w );

	// screen space
	_ssOrigin.x *= resolution.x / 2;
	_ssOrigin.y *= resolution.y / 2;
	_ssOrigin.z = 0;

	_ssOrigin3.setFrom( _ssOrigin );

	_mvMatrix.multiply2(camera.matrixWorldInverse, matrixWorld );

	for ( int i = 0, l = segmentCount; i < l; i ++ ) {

		_start4.fromBuffer( instanceStart, i );
		_end4.fromBuffer( instanceEnd, i );

		_start4.w = 1;
		_end4.w = 1;

		// camera space
		_start4.applyMatrix4( _mvMatrix );
		_end4.applyMatrix4( _mvMatrix );

		// skip the segment if it's entirely behind the camera
		final isBehindCameraNear = _start4.z > near && _end4.z > near;
		if ( isBehindCameraNear ) {

			continue;

		}

		// trim the segment if it extends behind camera near
		if ( _start4.z > near ) {

			final deltaDist = _start4.z - _end4.z;
			final t = ( _start4.z - near ) / deltaDist;
			_start4.lerp( _end4, t );

		} else if ( _end4.z > near ) {

			final deltaDist = _end4.z - _start4.z;
			final t = ( _end4.z - near ) / deltaDist;
			_end4.lerp( _start4, t );

		}

		// clip space
		_start4.applyMatrix4( projectionMatrix );
		_end4.applyMatrix4( projectionMatrix );

		// ndc space [ - 1.0, 1.0 ]
		_start4.scale( 1 / _start4.w );
		_end4.scale( 1 / _end4.w );

		// screen space
		_start4.x *= resolution.x / 2;
		_start4.y *= resolution.y / 2;

		_end4.x *= resolution.x / 2;
		_end4.y *= resolution.y / 2;

		// create 2d segment
		_line.start.setFrom( _start4 );
		_line.start.z = 0;

		_line.end.setFrom( _end4 );
		_line.end.z = 0;

		// get closest point on ray to segment
		final param = _line.closestPointToPointParameter( _ssOrigin3, true );
		_line.at( param, _closestPoint );

		// check if the intersection point is within clip space
		final zPos = ( 1 - param ) * _start4.z + param * _end4.z;
		final isInClipSpace = zPos >= - 1 && zPos <= 1;

		final isInside = _ssOrigin3.distanceTo( _closestPoint ) < _lineWidth * 0.5;

		if ( isInClipSpace && isInside ) {

			_line.start.fromBuffer( instanceStart, i );
			_line.end.fromBuffer( instanceEnd, i );

			_line.start.applyMatrix4( matrixWorld );
			_line.end.applyMatrix4( matrixWorld );

			final pointOnLine = Vector3();
			final point = Vector3();

			_ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );

			intersects.add( LineIntersection(
				point: point,
				distance: _ray.origin.distanceTo( point ),
				object: lineSegments,
				face: null,
				faceIndex: i,
				uv: null,
        pointOnLine: pointOnLine,
				uv2: null,
      ));
		}
	}
}