Skip to content

Commit 61ec551

Browse files
committed
Ray casting gives texture intersection in uv coordinates
Mesh.js raycast method is updated to calculate intersection point in uv coordinates. The calculus is done in the new inner method textureIntersection and added to the object returned as the uv property. Texture.js has a new public method, transformUv, that convert the coordinates from uv (range 0 to 1) to the real texture coordinates. The input parameter is modified on output. Useful to have the intersection point in texture coordinates. There is no example in this commit because I only have example with canvas, no with plain image.
1 parent 7c3e8c6 commit 61ec551

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

src/objects/Mesh.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ THREE.Mesh.prototype.raycast = ( function () {
7070
var tempB = new THREE.Vector3();
7171
var tempC = new THREE.Vector3();
7272

73+
var uvA = new THREE.Vector2();
74+
var uvB = new THREE.Vector2();
75+
var uvC = new THREE.Vector2();
76+
7377
return function raycast( raycaster, intersects ) {
7478

7579
var geometry = this.geometry;
@@ -107,6 +111,21 @@ THREE.Mesh.prototype.raycast = ( function () {
107111

108112
var a, b, c;
109113

114+
var textureIntersection = function ( pIntersection, p1, p2, p3, uv1, uv2, uv3 ) {
115+
116+
var bary = THREE.Triangle.barycoordFromPoint( pIntersection, p1, p2, p3 );
117+
118+
uv1.multiplyScalar( bary.x );
119+
uv2.multiplyScalar( bary.y );
120+
uv3.multiplyScalar( bary.z );
121+
122+
uv1.add( uv2 );
123+
uv1.add( uv3 );
124+
125+
return uv1.clone();
126+
127+
};
128+
110129
if ( geometry instanceof THREE.BufferGeometry ) {
111130

112131
var attributes = geometry.attributes;
@@ -152,6 +171,16 @@ THREE.Mesh.prototype.raycast = ( function () {
152171

153172
if ( intersectionPoint === null ) continue;
154173

174+
// intersectionPoint in UV coordinates.
175+
var uv = undefined;
176+
if ( material.map && attributes.uv !== undefined ) {
177+
var uvs = attributes.uv.array;
178+
uvA.fromArray( uvs, a * 2 );
179+
uvB.fromArray( uvs, b * 2 );
180+
uvC.fromArray( uvs, c * 2 );
181+
uv = textureIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC )
182+
}
183+
155184
intersectionPoint.applyMatrix4( this.matrixWorld );
156185

157186
var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
@@ -162,6 +191,7 @@ THREE.Mesh.prototype.raycast = ( function () {
162191

163192
distance: distance,
164193
point: intersectionPoint,
194+
uv: uv,
165195
face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
166196
faceIndex: Math.floor( i / 3 ), // triangle number in indices buffer semantics
167197
object: this
@@ -194,6 +224,16 @@ THREE.Mesh.prototype.raycast = ( function () {
194224

195225
if ( intersectionPoint === null ) continue;
196226

227+
// intersectionPoint in UV coordinates.
228+
var uv = undefined;
229+
if ( material.map && attributes.uv !== undefined ) {
230+
var uvs = attributes.uv.array;
231+
uvA.fromArray( uvs, i );
232+
uvB.fromArray( uvs, i + 2 );
233+
uvC.fromArray( uvs, i + 4 );
234+
uv = textureIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC )
235+
}
236+
197237
intersectionPoint.applyMatrix4( this.matrixWorld );
198238

199239
var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
@@ -208,6 +248,7 @@ THREE.Mesh.prototype.raycast = ( function () {
208248

209249
distance: distance,
210250
point: intersectionPoint,
251+
uv: uv,
211252
face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
212253
index: a, // triangle number in positions buffer semantics
213254
object: this
@@ -282,6 +323,16 @@ THREE.Mesh.prototype.raycast = ( function () {
282323

283324
if ( intersectionPoint === null ) continue;
284325

326+
// intersectionPoint in UV coordinates.
327+
var uv = undefined;
328+
if ( material.map && geometry.faceVertexUvs[ 0 ] !== undefined ) {
329+
var uvs = geometry.faceVertexUvs[ 0 ][ f ];
330+
uvA.copy( uvs[ 0 ] );
331+
uvB.copy( uvs[ 1 ] );
332+
uvC.copy( uvs[ 2 ] );
333+
uv = textureIntersection( intersectionPoint, a, b, c, uvA, uvB, uvC )
334+
}
335+
285336
intersectionPoint.applyMatrix4( this.matrixWorld );
286337

287338
var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
@@ -292,6 +343,7 @@ THREE.Mesh.prototype.raycast = ( function () {
292343

293344
distance: distance,
294345
point: intersectionPoint,
346+
uv: uv,
295347
face: face,
296348
faceIndex: f,
297349
object: this

src/textures/Texture.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,56 @@ THREE.Texture.prototype = {
185185

186186
this.dispatchEvent( { type: 'dispose' } );
187187

188+
},
189+
190+
transformUv: function ( uv ) {
191+
192+
if ( this.mapping !== THREE.UVMapping ) {
193+
return;
194+
}
195+
196+
uv.multiply( this.repeat );
197+
uv.add( this.offset );
198+
199+
if ( uv.x < 0 || uv.x > 1 ) {
200+
switch ( this.wrapS ) {
201+
case THREE.RepeatWrapping:
202+
uv.x = uv.x - Math.floor( uv.x );
203+
break;
204+
case THREE.ClampToEdgeWrapping:
205+
uv.x = uv.x < 0 ? 0 : 1;
206+
break;
207+
case THREE.MirroredRepeatWrapping:
208+
if ( Math.abs(Math.floor( uv.x ) % 2) === 1 ) {
209+
uv.x = Math.ceil( uv.x ) - uv.x;
210+
} else {
211+
uv.x = uv.x - Math.floor( uv.x );
212+
}
213+
break;
214+
}
215+
}
216+
217+
if ( uv.y < 0 || uv.y > 1 ) {
218+
switch ( this.wrapT ) {
219+
case THREE.RepeatWrapping:
220+
uv.y = uv.y - Math.floor( uv.y );
221+
break;
222+
case THREE.ClampToEdgeWrapping:
223+
uv.y = uv.y < 0 ? 0 : 1;
224+
break;
225+
case THREE.MirroredRepeatWrapping:
226+
if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
227+
uv.y = Math.ceil( uv.y ) - uv.y;
228+
} else {
229+
uv.y = uv.y - Math.floor( uv.y );
230+
}
231+
break;
232+
}
233+
}
234+
235+
if ( this.flipY ) {
236+
uv.y = 1 - uv.y;
237+
}
188238
}
189239

190240
};

0 commit comments

Comments
 (0)