ClickResolver.js 4.1 KB
Newer Older
1 2 3 4 5

THREE.ClickResolver = function( camera, scene ) {

	this.camera = camera;
	this.scene  = scene;
6
	this._debug = false;
7

8 9 10
};

THREE.ClickResolver.prototype = {
11

12
	findIntersectInScene : function ( xPercent, yPercent ) {
13

14 15
		var objects = this.scene.objects;
		var intersects = [];
16

17 18
		var mouseRayStart = this.translateScreenCoordsToZIndex( xPercent, yPercent, 300 );
		var mouseRayEnd =   this.translateScreenCoordsToZIndex( xPercent, yPercent, 800 );
19

20
		var mouseRayDir = new THREE.Vector3().sub( mouseRayEnd, mouseRayStart );
21

22
		var closestIntersect = null;
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

		for ( var i = 0, l = objects.length; i < l; i++ ) {

			var object = objects[i];

			if ( object instanceof THREE.Mesh ) {

				var intersect = this.getIntersectingFaces( this.scene, camera, object, mouseRayStart, mouseRayDir );

				if ( intersect.face != null && (closestIntersect == null || closestIntersect.distance > intersect.distance) ) {

					closestIntersect = intersect;

				}

38
			}
39

40
		}
41

42
		if ( closestIntersect != null && closestIntersect.face.onSelect ) {
43 44 45

			closestIntersect.face.onSelect( scene, camera, object, closestIntersect.face, closestIntersect.point );

46
		}
47

48
	},
49 50

	translateScreenCoordsToZIndex: function ( xPercent, yPercent, targetZIndex ) {
51 52

		var maxVisibleXatZIndex, maxVisibleYatZIndex;
53 54 55
		var rayToZIndex = new THREE.Vector3();
		var left = new THREE.Vector3();
		var up = new THREE.Vector3();
56 57 58
		var coordAtZIndex = new THREE.Vector3();

		rayToZIndex.sub( this.camera.target.position, this.camera.position ).setLength( targetZIndex );
59

60 61
		maxVisibleYatZIndex = rayToZIndex.length() * Math.tan( this.camera.fov * Math.PI / 360 );
		maxVisibleXatZIndex = maxVisibleYatZIndex  * this.camera.aspect;
62

63 64
		left.cross( this.camera.up, rayToZIndex );
		up  .cross( rayToZIndex, left );
65

66 67 68 69 70
		return coordAtZIndex.add( this.camera.position, rayToZIndex ).
			addSelf( left.setLength( maxVisibleXatZIndex * ( 1 - 2 * xPercent ))).
			addSelf( up  .setLength( maxVisibleYatZIndex * ( 1 - 2 * yPercent )));

	},
71

72
	getIntersectingFaces: function( scene, camera, object3d, linePoint, lineDir ) {
73

74 75 76 77 78
		var intersect = {
			face     : null,
			point    : null,
			distance : Number.MAX_VALUE
		};
79

80
		var geometry = object3d.geometry;
81
		var matrix = object3d.matrix;
82

83
		for ( f = 0; f < geometry.faces.length; f++ ) {
84

85
			var face = geometry.faces[ f ];
86

87
			// if ( !face.selectable ) continue;
88

89 90 91
			var a = matrix.transform( geometry.vertices[ face.a ].position.clone() );
			var b = matrix.transform( geometry.vertices[ face.b ].position.clone() );
			var c = matrix.transform( geometry.vertices[ face.c ].position.clone() );
92 93
			var d = face instanceof THREE.Face4 ? matrix.transform( geometry.vertices[ face.d ].position.clone() ) : null;

94 95 96
			var lineStart = linePoint.clone();
			var lineDirection = lineDir.clone();
			var dot = face.normal.dot( lineDirection );
97 98 99

			if ( dot < 0 ) { // Math.abs( dot ) > 0.0001

100 101
				var s = face.normal.dot( new THREE.Vector3().sub( a, lineStart ) ) / dot;
				var planeIntersect = lineStart.addSelf( lineDirection.multiplyScalar( s ) );
102

103
				if ( face instanceof THREE.Face3 ) {
104

105
					if ( pointInFace3( planeIntersect, a, b, c ) ) {
106

107
						logIntersect( planeIntersect, face );
108

109
					}
110

111
				} else if ( face instanceof THREE.Face4 ) {
112

113
					if ( pointInFace3( planeIntersect, a, b, d ) || pointInFace3( planeIntersect, b, c, d ) ) {
114

115
						logIntersect( planeIntersect, face );
116

117
					}
118

119
				}
120

121
			}
122

123
		}
124

125
		function logIntersect( planeIntersect, face ) {
126

127
			var distance = camera.position.distanceTo( planeIntersect );
128

129
			if ( distance < intersect.distance ) {
130

131 132 133
				intersect.distance = distance;
				intersect.face = face;
				intersect.point = planeIntersect;
134

135
			}
136

137
		}
138

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		// http://www.blackpawn.com/texts/pointinpoly/default.html

		function pointInFace3( p, a, b, c ) {

			var v0 = c.clone().subSelf( a ), v1 = b.clone().subSelf( a ), v2 = p.clone().subSelf( a ),
			dot00 = v0.dot( v0 ), dot01 = v0.dot( v1 ), dot02 = v0.dot( v2 ), dot11 = v1.dot( v1 ), dot12 = v1.dot( v2 ),

			invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 ),
			u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom,
			v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;

			return ( u > 0 ) && ( v > 0 ) && ( u + v < 1 );

		}

154 155 156
		return intersect;
	}

M
Mr.doob 已提交
157
};