topical media & game development

talk show tell print

mobile-query-three-plugins-cannonjs-vendor-cannon.js-src-collision-Ray.js / js



  /*global CANNON:true */
  
  
@class CANNON.Ray
author: Originally written by mr.doob / mrdoob.com/ for Three.js. Cannon.js-ified by schteppe. @brief A line in 3D space that intersects bodies and return points.
parameter: CANNON.Vec3 origin
parameter: CANNON.Vec3 direction

  
  CANNON.Ray = function(origin, direction){
      
@property CANNON.Vec3 origin @memberof CANNON.Ray

  
      this.origin = origin || new CANNON.Vec3();
  
      
@property CANNON.Vec3 direction @memberof CANNON.Ray

  
      this.direction = direction || new CANNON.Vec3();
  
      var precision = 0.0001;
  
      
@method setPrecision @memberof CANNON.Ray
parameter: float value @brief Sets the precision of the ray. Used when checking parallelity etc.

  
      this.setPrecision = function ( value ) {
          precision = value;
      };
  
      var a = new CANNON.Vec3();
      var b = new CANNON.Vec3();
      var c = new CANNON.Vec3();
      var d = new CANNON.Vec3();
  
      var directionCopy = new CANNON.Vec3();
  
      var vector = new CANNON.Vec3();
      var normal = new CANNON.Vec3();
      var intersectPoint = new CANNON.Vec3()
  
      
@method intersectBody @memberof CANNON.Ray
parameter: CANNON.RigidBody body @brief Shoot a ray at a body, get back information about the hit.
returns: Array An array of results. The result objects has properties: distance (float), point (CANNON.Vec3) and body (CANNON.RigidBody).

  
      this.intersectBody = function ( body ) {
          if(body.shape instanceof CANNON.ConvexPolyhedron){
              return this.intersectShape(body.shape,
                                         body.quaternion,
                                         body.position,
                                         body);
          } else if(body.shape instanceof CANNON.Box){
              return this.intersectShape(body.shape.convexPolyhedronRepresentation,
                                         body.quaternion,
                                         body.position,
                                         body);
          } else
              console.warn("Ray intersection is this far only implemented for ConvexPolyhedron and Box shapes.");
      };
      
      
@method intersectShape @memberof CANNON.Ray
parameter: CANNON.Shape shape
parameter: CANNON.Quaternion quat
parameter: CANNON.Vec3 position
parameter: CANNON.RigidBody body
returns: Array See intersectBody()

  
      this.intersectShape = function(shape,quat,position,body){
  
          var intersect, intersects = [];
  
          if ( shape instanceof CANNON.ConvexPolyhedron ) {
              // Checking boundingSphere
  
              var distance = distanceFromIntersection( this.origin, this.direction, position );
              if ( distance > shape.boundingSphereRadius() ) {
                  return intersects;
              }
  
              // Checking faces
              var dot, scalar, faces = shape.faces, vertices = shape.vertices, normals = shape.faceNormals;
  
              for ( fi = 0; fi < faces.length; fi++ ) {
  
                  var face = faces[ fi ];
                  var faceNormal = normals[ fi ];
                  var q = quat;
                  var x = position;
  
                  // determine if ray intersects the plane of the face
                  // note: this works regardless of the direction of the face normal
  
                  // Get plane point in world coordinates...
                  vertices[face[0]].copy(vector);
                  q.vmult(vector,vector);
                  vector.vadd(x,vector);
  
                  // ...but make it relative to the ray origin. We'll fix this later.
                  vector.vsub(this.origin,vector);
  
                  // Get plane normal
                  q.vmult(faceNormal,normal);
  
                  // If this dot product is negative, we have something interesting
                  dot = this.direction.dot(normal);
                  
                  // bail if ray and plane are parallel
                  if ( Math.abs( dot ) < precision ) continue;
  
                  // calc distance to plane
                  scalar = normal.dot( vector ) / dot;
  
                  // if negative distance, then plane is behind ray
                  if ( scalar < 0 ) continue;
  
                  if (  dot < 0 ) {
  
                      // Intersection point is origin + direction * scalar
                      this.direction.mult(scalar,intersectPoint);
                      intersectPoint.vadd(this.origin,intersectPoint);
  
                      // a is the point we compare points b and c with.
                      vertices[ face[0] ].copy(a);
                      q.vmult(a,a);
                      x.vadd(a,a);
  
                      for(var i=1; i<face.length-1; i++){
                          // Transform 3 vertices to world coords
                          vertices[ face[i] ].copy(b);
                          vertices[ face[i+1] ].copy(c);
                          q.vmult(b,b);
                          q.vmult(c,c);
                          x.vadd(b,b);
                          x.vadd(c,c);
                          
                          if ( pointInTriangle( intersectPoint, a, b, c ) ) {
  
                              intersect = {
  
                                  distance: this.origin.distanceTo( intersectPoint ),
                                  point: intersectPoint.copy(),
                                  face: face,
                                  body: body
                              
                              };
                              
                              intersects.push( intersect );
                              break;
                          }
                      }
                  }
              }
          }
          return intersects;
      }
  
      
@method intersectBodies @memberof CANNON.Ray
parameter: Array bodies An array of CANNON.RigidBody objects.
returns: Array See intersectBody

  
      this.intersectBodies = function ( bodies ) {
  
          var intersects = [];
  
          for ( var i = 0, l = bodies.length; i < l; i ++ ) {
              var result = this.intersectBody( bodies[ i ] );
              Array.prototype.push.apply( intersects, result );
          }
  
          intersects.sort( function ( a, b ) { return a.distance - b.distance; } );
          return intersects;
      };
  
      var v0 = new CANNON.Vec3(), intersect = new CANNON.Vec3();
      var dot, distance;
  
      function distanceFromIntersection( origin, direction, position ) {
  
          // v0 is vector from origin to position
          position.vsub(origin,v0);
          dot = v0.dot( direction );
  
          // intersect = direction*dot + origin
          direction.mult(dot,intersect);
          intersect.vadd(origin,intersect);
          
          distance = position.distanceTo( intersect );
  
          return distance;
      }
  
      // http://www.blackpawn.com/texts/pointinpoly/default.html
  
      var dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
      var v1 = new CANNON.Vec3(), v2 = new CANNON.Vec3();
  
      function pointInTriangle( p, a, b, c ) {
          c.vsub(a,v0);
          b.vsub(a,v1);
          p.vsub(a,v2);
  
          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 );
      }
  };
  CANNON.Ray.prototype.constructor = CANNON.Ray;
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.