mirror of
https://github.com/MapMakersAndProgrammers/Alternativa3D.git
synced 2025-10-30 08:55:17 -07:00
Test commit
This commit is contained in:
576
src/alternativa/engine3d/collisions/EllipsoidCollider.as
Normal file
576
src/alternativa/engine3d/collisions/EllipsoidCollider.as
Normal file
@@ -0,0 +1,576 @@
|
||||
/**
|
||||
* Exhibit A - Source Code Form License Notice
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
|
||||
* You may add additional accurate notices of copyright ownership.
|
||||
*
|
||||
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
|
||||
* */
|
||||
|
||||
package alternativa.engine3d.collisions {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.core.*;
|
||||
import alternativa.engine3d.resources.Geometry;
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* The class implements the algorithm of the continuous collision of an ellipsoid with the faces.
|
||||
*/
|
||||
public class EllipsoidCollider {
|
||||
|
||||
/**
|
||||
* Ellipsoid radius along X axis.
|
||||
*/
|
||||
public var radiusX:Number;
|
||||
|
||||
/**
|
||||
* Ellipsoid radius along Y axis.
|
||||
*/
|
||||
public var radiusY:Number;
|
||||
|
||||
/**
|
||||
* Ellipsoid radius along Z axis.
|
||||
*/
|
||||
public var radiusZ:Number;
|
||||
|
||||
/**
|
||||
* Geometric error. Minimum absolute difference between two values
|
||||
* when they are considered to be different. Default value is 0.001.
|
||||
*/
|
||||
public var threshold:Number = 0.001;
|
||||
|
||||
private var matrix:Transform3D = new Transform3D();
|
||||
private var inverseMatrix:Transform3D = new Transform3D();
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var geometries:Vector.<Geometry> = new Vector.<Geometry>();
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var transforms:Vector.<Transform3D> = new Vector.<Transform3D>();
|
||||
|
||||
private var vertices:Vector.<Number> = new Vector.<Number>();
|
||||
private var normals:Vector.<Number> = new Vector.<Number>();
|
||||
private var indices:Vector.<int> = new Vector.<int>();
|
||||
private var numTriangles:int;
|
||||
|
||||
private var radius:Number;
|
||||
private var src:Vector3D = new Vector3D();
|
||||
private var displ:Vector3D = new Vector3D();
|
||||
private var dest:Vector3D = new Vector3D();
|
||||
|
||||
private var collisionPoint:Vector3D = new Vector3D();
|
||||
private var collisionPlane:Vector3D = new Vector3D();
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var sphere:Vector3D = new Vector3D();
|
||||
private var cornerA:Vector3D = new Vector3D();
|
||||
private var cornerB:Vector3D = new Vector3D();
|
||||
private var cornerC:Vector3D = new Vector3D();
|
||||
private var cornerD:Vector3D = new Vector3D();
|
||||
|
||||
/**
|
||||
* Creates a EllipsoidCollider object.
|
||||
*
|
||||
* @param radiusX Ellipsoid radius along X axis.
|
||||
* @param radiusY Ellipsoid radius along Y axis.
|
||||
* @param radiusZ Ellipsoid radius along Z axis.
|
||||
*/
|
||||
public function EllipsoidCollider(radiusX:Number, radiusY:Number, radiusZ:Number) {
|
||||
this.radiusX = radiusX;
|
||||
this.radiusY = radiusY;
|
||||
this.radiusZ = radiusZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function calculateSphere(transform:Transform3D):void {
|
||||
sphere.x = transform.d;
|
||||
sphere.y = transform.h;
|
||||
sphere.z = transform.l;
|
||||
var sax:Number = transform.a*cornerA.x + transform.b*cornerA.y + transform.c*cornerA.z + transform.d;
|
||||
var say:Number = transform.e*cornerA.x + transform.f*cornerA.y + transform.g*cornerA.z + transform.h;
|
||||
var saz:Number = transform.i*cornerA.x + transform.j*cornerA.y + transform.k*cornerA.z + transform.l;
|
||||
var sbx:Number = transform.a*cornerB.x + transform.b*cornerB.y + transform.c*cornerB.z + transform.d;
|
||||
var sby:Number = transform.e*cornerB.x + transform.f*cornerB.y + transform.g*cornerB.z + transform.h;
|
||||
var sbz:Number = transform.i*cornerB.x + transform.j*cornerB.y + transform.k*cornerB.z + transform.l;
|
||||
var scx:Number = transform.a*cornerC.x + transform.b*cornerC.y + transform.c*cornerC.z + transform.d;
|
||||
var scy:Number = transform.e*cornerC.x + transform.f*cornerC.y + transform.g*cornerC.z + transform.h;
|
||||
var scz:Number = transform.i*cornerC.x + transform.j*cornerC.y + transform.k*cornerC.z + transform.l;
|
||||
var sdx:Number = transform.a*cornerD.x + transform.b*cornerD.y + transform.c*cornerD.z + transform.d;
|
||||
var sdy:Number = transform.e*cornerD.x + transform.f*cornerD.y + transform.g*cornerD.z + transform.h;
|
||||
var sdz:Number = transform.i*cornerD.x + transform.j*cornerD.y + transform.k*cornerD.z + transform.l;
|
||||
var dx:Number = sax - sphere.x;
|
||||
var dy:Number = say - sphere.y;
|
||||
var dz:Number = saz - sphere.z;
|
||||
sphere.w = dx*dx + dy*dy + dz*dz;
|
||||
dx = sbx - sphere.x;
|
||||
dy = sby - sphere.y;
|
||||
dz = sbz - sphere.z;
|
||||
var dxyz:Number = dx*dx + dy*dy + dz*dz;
|
||||
if (dxyz > sphere.w) sphere.w = dxyz;
|
||||
dx = scx - sphere.x;
|
||||
dy = scy - sphere.y;
|
||||
dz = scz - sphere.z;
|
||||
dxyz = dx*dx + dy*dy + dz*dz;
|
||||
if (dxyz > sphere.w) sphere.w = dxyz;
|
||||
dx = sdx - sphere.x;
|
||||
dy = sdy - sphere.y;
|
||||
dz = sdz - sphere.z;
|
||||
dxyz = dx*dx + dy*dy + dz*dz;
|
||||
if (dxyz > sphere.w) sphere.w = dxyz;
|
||||
sphere.w = Math.sqrt(sphere.w);
|
||||
}
|
||||
|
||||
private function prepare(source:Vector3D, displacement:Vector3D, object:Object3D, excludedObjects:Dictionary):void {
|
||||
|
||||
// Radius of the sphere
|
||||
radius = radiusX;
|
||||
if (radiusY > radius) radius = radiusY;
|
||||
if (radiusZ > radius) radius = radiusZ;
|
||||
|
||||
// The matrix of the collider
|
||||
matrix.compose(source.x, source.y, source.z, 0, 0, 0, radiusX/radius, radiusY/radius, radiusZ/radius);
|
||||
inverseMatrix.copy(matrix);
|
||||
inverseMatrix.invert();
|
||||
|
||||
// Local coordinates
|
||||
src.x = 0;
|
||||
src.y = 0;
|
||||
src.z = 0;
|
||||
// Local offset
|
||||
displ.x = inverseMatrix.a*displacement.x + inverseMatrix.b*displacement.y + inverseMatrix.c*displacement.z;
|
||||
displ.y = inverseMatrix.e*displacement.x + inverseMatrix.f*displacement.y + inverseMatrix.g*displacement.z;
|
||||
displ.z = inverseMatrix.i*displacement.x + inverseMatrix.j*displacement.y + inverseMatrix.k*displacement.z;
|
||||
// Local destination point
|
||||
dest.x = src.x + displ.x;
|
||||
dest.y = src.y + displ.y;
|
||||
dest.z = src.z + displ.z;
|
||||
|
||||
// Bound defined by movement of the sphere
|
||||
var rad:Number = radius + displ.length;
|
||||
cornerA.x = -rad;
|
||||
cornerA.y = -rad;
|
||||
cornerA.z = -rad;
|
||||
cornerB.x = rad;
|
||||
cornerB.y = -rad;
|
||||
cornerB.z = -rad;
|
||||
cornerC.x = rad;
|
||||
cornerC.y = rad;
|
||||
cornerC.z = -rad;
|
||||
cornerD.x = -rad;
|
||||
cornerD.y = rad;
|
||||
cornerD.z = -rad;
|
||||
|
||||
// Gathering the faces which with collision can occur
|
||||
if (excludedObjects == null || !excludedObjects[object]) {
|
||||
if (object.transformChanged) object.composeTransforms();
|
||||
object.globalToLocalTransform.combine(object.inverseTransform, matrix);
|
||||
// Check collision with the bound
|
||||
var intersects:Boolean = true;
|
||||
if (object.boundBox != null) {
|
||||
calculateSphere(object.globalToLocalTransform);
|
||||
intersects = object.boundBox.checkSphere(sphere);
|
||||
}
|
||||
if (intersects) {
|
||||
object.localToGlobalTransform.combine(inverseMatrix, object.transform);
|
||||
object.collectGeometry(this, excludedObjects);
|
||||
}
|
||||
// Check children
|
||||
if (object.childrenList != null) object.collectChildrenGeometry(this, excludedObjects);
|
||||
}
|
||||
|
||||
numTriangles = 0;
|
||||
var indicesLength:int = 0;
|
||||
var normalsLength:int = 0;
|
||||
|
||||
// Loop geometries
|
||||
var j:int;
|
||||
var mapOffset:int = 0;
|
||||
var verticesLength:int = 0;
|
||||
var geometriesLength:int = geometries.length;
|
||||
for (var i:int = 0; i < geometriesLength; i++) {
|
||||
var geometry:Geometry = geometries[i];
|
||||
var transform:Transform3D = transforms[i];
|
||||
var geometryIndicesLength:int = geometry._indices.length;
|
||||
if (geometry._numVertices == 0 || geometryIndicesLength == 0) continue;
|
||||
// Transform vertices
|
||||
var vBuffer:VertexStream = (VertexAttributes.POSITION < geometry._attributesStreams.length) ? geometry._attributesStreams[VertexAttributes.POSITION] : null;
|
||||
if (vBuffer != null) {
|
||||
var attributesOffset:int = geometry._attributesOffsets[VertexAttributes.POSITION];
|
||||
var numMappings:int = vBuffer.attributes.length;
|
||||
var data:ByteArray = vBuffer.data;
|
||||
for (j = 0; j < geometry._numVertices; j++) {
|
||||
data.position = 4*(numMappings*j + attributesOffset);
|
||||
var vx:Number = data.readFloat();
|
||||
var vy:Number = data.readFloat();
|
||||
var vz:Number = data.readFloat();
|
||||
vertices[verticesLength] = transform.a*vx + transform.b*vy + transform.c*vz + transform.d; verticesLength++;
|
||||
vertices[verticesLength] = transform.e*vx + transform.f*vy + transform.g*vz + transform.h; verticesLength++;
|
||||
vertices[verticesLength] = transform.i*vx + transform.j*vy + transform.k*vz + transform.l; verticesLength++;
|
||||
}
|
||||
}
|
||||
// Loop triangles
|
||||
var geometryIndices:Vector.<uint> = geometry._indices;
|
||||
for (j = 0; j < geometryIndicesLength;) {
|
||||
var a:int = geometryIndices[j] + mapOffset; j++;
|
||||
var index:int = a*3;
|
||||
var ax:Number = vertices[index]; index++;
|
||||
var ay:Number = vertices[index]; index++;
|
||||
var az:Number = vertices[index];
|
||||
var b:int = geometryIndices[j] + mapOffset; j++;
|
||||
index = b*3;
|
||||
var bx:Number = vertices[index]; index++;
|
||||
var by:Number = vertices[index]; index++;
|
||||
var bz:Number = vertices[index];
|
||||
var c:int = geometryIndices[j] + mapOffset; j++;
|
||||
index = c*3;
|
||||
var cx:Number = vertices[index]; index++;
|
||||
var cy:Number = vertices[index]; index++;
|
||||
var cz:Number = vertices[index];
|
||||
// Exclusion by bound
|
||||
if (ax > rad && bx > rad && cx > rad || ax < -rad && bx < -rad && cx < -rad) continue;
|
||||
if (ay > rad && by > rad && cy > rad || ay < -rad && by < -rad && cy < -rad) continue;
|
||||
if (az > rad && bz > rad && cz > rad || az < -rad && bz < -rad && cz < -rad) continue;
|
||||
// The normal
|
||||
var abx:Number = bx - ax;
|
||||
var aby:Number = by - ay;
|
||||
var abz:Number = bz - az;
|
||||
var acx:Number = cx - ax;
|
||||
var acy:Number = cy - ay;
|
||||
var acz:Number = cz - az;
|
||||
var normalX:Number = acz*aby - acy*abz;
|
||||
var normalY:Number = acx*abz - acz*abx;
|
||||
var normalZ:Number = acy*abx - acx*aby;
|
||||
var len:Number = normalX*normalX + normalY*normalY + normalZ*normalZ;
|
||||
if (len < 0.001) continue;
|
||||
len = 1/Math.sqrt(len);
|
||||
normalX *= len;
|
||||
normalY *= len;
|
||||
normalZ *= len;
|
||||
var offset:Number = ax*normalX + ay*normalY + az*normalZ;
|
||||
if (offset > rad || offset < -rad) continue;
|
||||
indices[indicesLength] = a; indicesLength++;
|
||||
indices[indicesLength] = b; indicesLength++;
|
||||
indices[indicesLength] = c; indicesLength++;
|
||||
normals[normalsLength] = normalX; normalsLength++;
|
||||
normals[normalsLength] = normalY; normalsLength++;
|
||||
normals[normalsLength] = normalZ; normalsLength++;
|
||||
normals[normalsLength] = offset; normalsLength++;
|
||||
numTriangles++;
|
||||
}
|
||||
// Offset by nomber of vertices
|
||||
mapOffset += geometry._numVertices;
|
||||
}
|
||||
geometries.length = 0;
|
||||
transforms.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates destination point from given start position and displacement vector.
|
||||
* @param source Starting point.
|
||||
* @param displacement Displacement vector.
|
||||
* @param object An object at crossing which will be checked. If this is a container, the application will participate and its child objects
|
||||
* @param excludedObjects An associative array whose keys are instances of <code>Object3D</code> and its children.
|
||||
* The objects that are keys of this dictionary will be excluded from intersection test.
|
||||
* @return Destination point.
|
||||
*/
|
||||
public function calculateDestination(source:Vector3D, displacement:Vector3D, object:Object3D, excludedObjects:Dictionary = null):Vector3D {
|
||||
|
||||
if (displacement.length <= threshold) return source.clone();
|
||||
|
||||
prepare(source, displacement, object, excludedObjects);
|
||||
|
||||
if (numTriangles > 0) {
|
||||
var limit:int = 50;
|
||||
for (var i:int = 0; i < limit; i++) {
|
||||
if (checkCollision()) {
|
||||
// Offset destination point from behind collision plane by radius of the sphere over plane, along the normal
|
||||
var offset:Number = radius + threshold + collisionPlane.w - dest.x*collisionPlane.x - dest.y*collisionPlane.y - dest.z*collisionPlane.z;
|
||||
dest.x += collisionPlane.x*offset;
|
||||
dest.y += collisionPlane.y*offset;
|
||||
dest.z += collisionPlane.z*offset;
|
||||
// Fixing up the current sphere coordinates for the next iteration
|
||||
src.x = collisionPoint.x + collisionPlane.x*(radius + threshold);
|
||||
src.y = collisionPoint.y + collisionPlane.y*(radius + threshold);
|
||||
src.z = collisionPoint.z + collisionPlane.z*(radius + threshold);
|
||||
// Fixing up velocity vector. The result ordered along plane of collision.
|
||||
displ.x = dest.x - src.x;
|
||||
displ.y = dest.y - src.y;
|
||||
displ.z = dest.z - src.z;
|
||||
if (displ.length < threshold) break;
|
||||
} else break;
|
||||
}
|
||||
// Setting the coordinates
|
||||
return new Vector3D(matrix.a*dest.x + matrix.b*dest.y + matrix.c*dest.z + matrix.d, matrix.e*dest.x + matrix.f*dest.y + matrix.g*dest.z + matrix.h, matrix.i*dest.x + matrix.j*dest.y + matrix.k*dest.z + matrix.l);
|
||||
} else {
|
||||
return new Vector3D(source.x + displacement.x, source.y + displacement.y, source.z + displacement.z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds first collision from given starting point aling displacement vector.
|
||||
* @param source Starting point.
|
||||
* @param displacement Displacement vector.
|
||||
* @param resCollisionPoint Collision point will be written into this variable.
|
||||
* @param resCollisionPlane Collision plane (defines by normal) parameters will be written into this variable.
|
||||
* @param object The object to use in collision detection. If a container is specified, all its children will be tested for collison with ellipsoid.
|
||||
* @param excludedObjects An associative array whose keys are instances of <code>Object3D</code> and its children.
|
||||
* @return <code>true</code> if collision detected and <code>false</code> otherwise.
|
||||
*/
|
||||
public function getCollision(source:Vector3D, displacement:Vector3D, resCollisionPoint:Vector3D, resCollisionPlane:Vector3D, object:Object3D, excludedObjects:Dictionary = null):Boolean {
|
||||
|
||||
if (displacement.length <= threshold) return false;
|
||||
|
||||
prepare(source, displacement, object, excludedObjects);
|
||||
|
||||
if (numTriangles > 0) {
|
||||
if (checkCollision()) {
|
||||
|
||||
// Transform the point to the global space
|
||||
resCollisionPoint.x = matrix.a*collisionPoint.x + matrix.b*collisionPoint.y + matrix.c*collisionPoint.z + matrix.d;
|
||||
resCollisionPoint.y = matrix.e*collisionPoint.x + matrix.f*collisionPoint.y + matrix.g*collisionPoint.z + matrix.h;
|
||||
resCollisionPoint.z = matrix.i*collisionPoint.x + matrix.j*collisionPoint.y + matrix.k*collisionPoint.z + matrix.l;
|
||||
|
||||
// Transform the plane to the global space
|
||||
var abx:Number;
|
||||
var aby:Number;
|
||||
var abz:Number;
|
||||
if (collisionPlane.x < collisionPlane.y) {
|
||||
if (collisionPlane.x < collisionPlane.z) {
|
||||
abx = 0;
|
||||
aby = -collisionPlane.z;
|
||||
abz = collisionPlane.y;
|
||||
} else {
|
||||
abx = -collisionPlane.y;
|
||||
aby = collisionPlane.x;
|
||||
abz = 0;
|
||||
}
|
||||
} else {
|
||||
if (collisionPlane.y < collisionPlane.z) {
|
||||
abx = collisionPlane.z;
|
||||
aby = 0;
|
||||
abz = -collisionPlane.x;
|
||||
} else {
|
||||
abx = -collisionPlane.y;
|
||||
aby = collisionPlane.x;
|
||||
abz = 0;
|
||||
}
|
||||
}
|
||||
var acx:Number = collisionPlane.z*aby - collisionPlane.y*abz;
|
||||
var acy:Number = collisionPlane.x*abz - collisionPlane.z*abx;
|
||||
var acz:Number = collisionPlane.y*abx - collisionPlane.x*aby;
|
||||
|
||||
var abx2:Number = matrix.a*abx + matrix.b*aby + matrix.c*abz;
|
||||
var aby2:Number = matrix.e*abx + matrix.f*aby + matrix.g*abz;
|
||||
var abz2:Number = matrix.i*abx + matrix.j*aby + matrix.k*abz;
|
||||
var acx2:Number = matrix.a*acx + matrix.b*acy + matrix.c*acz;
|
||||
var acy2:Number = matrix.e*acx + matrix.f*acy + matrix.g*acz;
|
||||
var acz2:Number = matrix.i*acx + matrix.j*acy + matrix.k*acz;
|
||||
|
||||
resCollisionPlane.x = abz2*acy2 - aby2*acz2;
|
||||
resCollisionPlane.y = abx2*acz2 - abz2*acx2;
|
||||
resCollisionPlane.z = aby2*acx2 - abx2*acy2;
|
||||
resCollisionPlane.normalize();
|
||||
resCollisionPlane.w = resCollisionPoint.x*resCollisionPlane.x + resCollisionPoint.y*resCollisionPlane.y + resCollisionPoint.z*resCollisionPlane.z;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function checkCollision():Boolean {
|
||||
var minTime:Number = 1;
|
||||
var displacementLength:Number = displ.length;
|
||||
// Loop triangles
|
||||
var indicesLength:int = numTriangles*3;
|
||||
for (var i:int = 0, j:int = 0; i < indicesLength;) {
|
||||
// Points
|
||||
var index:int = indices[i]*3; i++;
|
||||
var ax:Number = vertices[index]; index++;
|
||||
var ay:Number = vertices[index]; index++;
|
||||
var az:Number = vertices[index];
|
||||
index = indices[i]*3; i++;
|
||||
var bx:Number = vertices[index]; index++;
|
||||
var by:Number = vertices[index]; index++;
|
||||
var bz:Number = vertices[index];
|
||||
index = indices[i]*3; i++;
|
||||
var cx:Number = vertices[index]; index++;
|
||||
var cy:Number = vertices[index]; index++;
|
||||
var cz:Number = vertices[index];
|
||||
// Normal
|
||||
var normalX:Number = normals[j]; j++;
|
||||
var normalY:Number = normals[j]; j++;
|
||||
var normalZ:Number = normals[j]; j++;
|
||||
var offset:Number = normals[j]; j++;
|
||||
var distance:Number = src.x*normalX + src.y*normalY + src.z*normalZ - offset;
|
||||
// The intersection of plane and sphere
|
||||
var pointX:Number;
|
||||
var pointY:Number;
|
||||
var pointZ:Number;
|
||||
if (distance < radius) {
|
||||
pointX = src.x - normalX*distance;
|
||||
pointY = src.y - normalY*distance;
|
||||
pointZ = src.z - normalZ*distance;
|
||||
} else {
|
||||
var t:Number = (distance - radius)/(distance - dest.x*normalX - dest.y*normalY - dest.z*normalZ + offset);
|
||||
pointX = src.x + displ.x*t - normalX*radius;
|
||||
pointY = src.y + displ.y*t - normalY*radius;
|
||||
pointZ = src.z + displ.z*t - normalZ*radius;
|
||||
}
|
||||
// Closest polygon vertex
|
||||
var faceX:Number;
|
||||
var faceY:Number;
|
||||
var faceZ:Number;
|
||||
var min:Number = 1e+22;
|
||||
// Loop edges
|
||||
var inside:Boolean = true;
|
||||
for (var k:int = 0; k < 3; k++) {
|
||||
var p1x:Number;
|
||||
var p1y:Number;
|
||||
var p1z:Number;
|
||||
var p2x:Number;
|
||||
var p2y:Number;
|
||||
var p2z:Number;
|
||||
if (k == 0) {
|
||||
p1x = ax;
|
||||
p1y = ay;
|
||||
p1z = az;
|
||||
p2x = bx;
|
||||
p2y = by;
|
||||
p2z = bz;
|
||||
} else if (k == 1) {
|
||||
p1x = bx;
|
||||
p1y = by;
|
||||
p1z = bz;
|
||||
p2x = cx;
|
||||
p2y = cy;
|
||||
p2z = cz;
|
||||
} else {
|
||||
p1x = cx;
|
||||
p1y = cy;
|
||||
p1z = cz;
|
||||
p2x = ax;
|
||||
p2y = ay;
|
||||
p2z = az;
|
||||
}
|
||||
var abx:Number = p2x - p1x;
|
||||
var aby:Number = p2y - p1y;
|
||||
var abz:Number = p2z - p1z;
|
||||
var acx:Number = pointX - p1x;
|
||||
var acy:Number = pointY - p1y;
|
||||
var acz:Number = pointZ - p1z;
|
||||
var crx:Number = acz*aby - acy*abz;
|
||||
var cry:Number = acx*abz - acz*abx;
|
||||
var crz:Number = acy*abx - acx*aby;
|
||||
// Case of the point is outside of the polygon
|
||||
if (crx*normalX + cry*normalY + crz*normalZ < 0) {
|
||||
var edgeLength:Number = abx*abx + aby*aby + abz*abz;
|
||||
var edgeDistanceSqr:Number = (crx*crx + cry*cry + crz*crz)/edgeLength;
|
||||
if (edgeDistanceSqr < min) {
|
||||
// Edge normalization
|
||||
edgeLength = Math.sqrt(edgeLength);
|
||||
abx /= edgeLength;
|
||||
aby /= edgeLength;
|
||||
abz /= edgeLength;
|
||||
// Distance to intersecion of normal along theedge
|
||||
t = abx*acx + aby*acy + abz*acz;
|
||||
var acLen:Number;
|
||||
if (t < 0) {
|
||||
// Closest point is the first one
|
||||
acLen = acx*acx + acy*acy + acz*acz;
|
||||
if (acLen < min) {
|
||||
min = acLen;
|
||||
faceX = p1x;
|
||||
faceY = p1y;
|
||||
faceZ = p1z;
|
||||
}
|
||||
} else if (t > edgeLength) {
|
||||
// Closest point is the second one
|
||||
acx = pointX - p2x;
|
||||
acy = pointY - p2y;
|
||||
acz = pointZ - p2z;
|
||||
acLen = acx*acx + acy*acy + acz*acz;
|
||||
if (acLen < min) {
|
||||
min = acLen;
|
||||
faceX = p2x;
|
||||
faceY = p2y;
|
||||
faceZ = p2z;
|
||||
}
|
||||
} else {
|
||||
// Closest point is on edge
|
||||
min = edgeDistanceSqr;
|
||||
faceX = p1x + abx*t;
|
||||
faceY = p1y + aby*t;
|
||||
faceZ = p1z + abz*t;
|
||||
}
|
||||
}
|
||||
inside = false;
|
||||
}
|
||||
}
|
||||
// Case of point is inside polygon
|
||||
if (inside) {
|
||||
faceX = pointX;
|
||||
faceY = pointY;
|
||||
faceZ = pointZ;
|
||||
}
|
||||
// Vector pointed from closest point to the center of sphere
|
||||
var deltaX:Number = src.x - faceX;
|
||||
var deltaY:Number = src.y - faceY;
|
||||
var deltaZ:Number = src.z - faceZ;
|
||||
// If movement directed to point
|
||||
if (deltaX*displ.x + deltaY*displ.y + deltaZ*displ.z <= 0) {
|
||||
// reversed vector
|
||||
var backX:Number = -displ.x/displacementLength;
|
||||
var backY:Number = -displ.y/displacementLength;
|
||||
var backZ:Number = -displ.z/displacementLength;
|
||||
// Length of Vector pointed from closest point to the center of sphere
|
||||
var deltaLength:Number = deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ;
|
||||
// Projection Vector pointed from closest point to the center of sphere on reversed vector
|
||||
var projectionLength:Number = deltaX*backX + deltaY*backY + deltaZ*backZ;
|
||||
var projectionInsideLength:Number = radius*radius - deltaLength + projectionLength*projectionLength;
|
||||
if (projectionInsideLength > 0) {
|
||||
// Time of the intersection
|
||||
var time:Number = (projectionLength - Math.sqrt(projectionInsideLength))/displacementLength;
|
||||
// Collision with closest point occurs
|
||||
if (time < minTime) {
|
||||
minTime = time;
|
||||
collisionPoint.x = faceX;
|
||||
collisionPoint.y = faceY;
|
||||
collisionPoint.z = faceZ;
|
||||
if (inside) {
|
||||
collisionPlane.x = normalX;
|
||||
collisionPlane.y = normalY;
|
||||
collisionPlane.z = normalZ;
|
||||
collisionPlane.w = offset;
|
||||
} else {
|
||||
deltaLength = Math.sqrt(deltaLength);
|
||||
collisionPlane.x = deltaX/deltaLength;
|
||||
collisionPlane.y = deltaY/deltaLength;
|
||||
collisionPlane.z = deltaZ/deltaLength;
|
||||
collisionPlane.w = collisionPoint.x*collisionPlane.x + collisionPoint.y*collisionPlane.y + collisionPoint.z*collisionPlane.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return minTime < 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user