raycastScreenSpace function
void
raycastScreenSpace(
- LineSegments2 lineSegments,
- Camera camera,
- 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,
));
}
}
}