/// <summary> /// Clasifica un punto respecto de un Cuerpo Convexo de N caras. /// Puede devolver OUTSIDE o INSIDE (si es coincidente se considera como INSIDE). /// Los planos del Cuerpo Convexo deben apuntar hacia adentro. /// </summary> /// <param name="q">Punto a clasificar</param> /// <param name="polyhedron">Cuerpo Convexo</param> /// <returns>Resultado de la clasificación</returns> public static ConvexPolyhedronResult classifyPointConvexPolyhedron(Vector3 q, TgcConvexPolyhedron polyhedron) { bool fistTime = true; PointPlaneResult lastC = PointPlaneResult.BEHIND; PointPlaneResult c; for (int i = 0; i < polyhedron.Planes.Length; i++) { c = TgcCollisionUtils.classifyPointPlane(q, polyhedron.Planes[i]); if (c == PointPlaneResult.COINCIDENT) { continue; } //guardar clasif para primera vez if (fistTime) { fistTime = false; lastC = c; } //comparar con ultima clasif if (c != lastC) { //basta con que haya una distinta para que este Afuera return(ConvexPolyhedronResult.OUTSIDE); } } //Si todos dieron el mismo resultado, entonces esta adentro return(ConvexPolyhedronResult.INSIDE); }
/// <summary> /// Picking sobre un triangulo /// </summary> public bool pickTriangle(out TgcTriangle triangle, out int triangleIndex) { pickingRay.updateRay(); Vector3 segmentA = pickingRay.Ray.Origin; Vector3 segmentB = segmentA + Vector3.Scale(pickingRay.Ray.Direction, 10000f); float minDist = float.MaxValue; triangle = null; triangleIndex = -1; //Buscar la menor colision rayo-triangulo for (int i = 0; i < triangles.Count; i++) { TgcTriangle tri = triangles[i]; float t; Vector3 uvw; Vector3 col; if (TgcCollisionUtils.intersectLineTriangle(segmentA, segmentB, tri.A, tri.B, tri.C, out uvw, out t, out col)) { float dist = Vector3.Length(col - segmentA); if (dist < minDist) { minDist = dist; triangle = tri; triangleIndex = i; } } } return(triangle != null); }
/// <summary> /// Indica si un BoundingSphere colisiona con un BoundingBox. /// </summary> /// <param name="sphere">BoundingSphere</param> /// <param name="aabb">BoundingBox</param> /// <returns>True si hay colisión</returns> public static bool testSphereAABB(TgcBoundingSphere sphere, TgcBoundingBox aabb) { //Compute squared distance between sphere center and AABB float sqDist = TgcCollisionUtils.sqDistPointAABB(sphere.Center, aabb); //Sphere and AABB intersect if the (squared) distance //between them is less than the (squared) sphere radius return(sqDist <= sphere.Radius * sphere.Radius); }
/// <summary> /// Indica si un punto se encuentra dentro de un Cuerpo Convexo. /// Los planos del Cuerpo Convexo deben apuntar hacia adentro. /// Es más ágil que llamar a classifyPointConvexPolyhedron() /// </summary> /// <param name="q">Punto a clasificar</param> /// <param name="polyhedron">Cuerpo Convexo</param> /// <returns>True si se encuentra adentro.</returns> public static bool testPointConvexPolyhedron(Vector3 q, TgcConvexPolyhedron polyhedron) { for (int i = 0; i < polyhedron.Planes.Length; i++) { //Si el punto está detrás de algún plano, entonces está afuera if (TgcCollisionUtils.classifyPointPlane(q, polyhedron.Planes[i]) == PointPlaneResult.BEHIND) { return(false); } } //Si está delante de todos los planos, entonces está adentro. return(true); }
/// <summary> /// Indica si un Ray colisiona con un Plano. /// Tanto la normal del plano como la dirección del Ray se asumen normalizados. /// </summary> /// <param name="ray">Ray a testear</param> /// <param name="plane">Plano a testear</param> /// <param name="t">Instante de colisión</param> /// <param name="q">Punto de colisión con el plano</param> /// <returns>True si hubo colisión</returns> public static bool intersectRayPlane(TgcRay ray, Plane plane, out float t, out Vector3 q) { Vector3 planeNormal = TgcCollisionUtils.getPlaneNormal(plane); float numer = plane.Dot(ray.Origin); float denom = Vector3.Dot(planeNormal, ray.Direction); t = -numer / denom; if (t > 0.0f) { q = ray.Origin + ray.Direction * t; return(true); } q = Vector3.Empty; return(false); }
/// <summary> /// Indica si un segmento de recta colisiona con un BoundingSphere. /// Si el resultado es True se carga el punto de colision (q) y la distancia de colision en el t. /// La dirección del Ray debe estar normalizada. /// </summary> /// <param name="p0">Punto inicial del segmento</param> /// <param name="p1">Punto final del segmento</param> /// <param name="s">BoundingSphere</param> /// <param name="t">Distancia de colision del segmento</param> /// <param name="q">Punto de colision</param> /// <returns>True si hay colision</returns> public static bool intersectSegmentSphere(Vector3 p0, Vector3 p1, TgcBoundingSphere sphere, out float t, out Vector3 q) { Vector3 segmentDir = p1 - p0; TgcRay ray = new TgcRay(p0, segmentDir); if (TgcCollisionUtils.intersectRaySphere(ray, sphere, out t, out q)) { float segmentLengthSq = segmentDir.LengthSq(); Vector3 collisionDiff = q - p0; float collisionLengthSq = collisionDiff.LengthSq(); if (collisionLengthSq <= segmentLengthSq) { return(true); } } return(false); }
/// <summary> /// Dado el punto p, devuelve el punto del contorno del BoundingBox mas próximo a p. /// </summary> /// <param name="p">Punto a testear</param> /// <param name="aabb">BoundingBox a testear</param> /// <returns>Punto mas cercano a p del BoundingBox</returns> public static Vector3 closestPointAABB(Vector3 p, TgcBoundingBox aabb) { float[] aabbMin = toArray(aabb.PMin); float[] aabbMax = toArray(aabb.PMax); float[] pArray = toArray(p); float[] q = new float[3]; // For each coordinate axis, if the point coordinate value is // outside box, clamp it to the box, else keep it as is for (int i = 0; i < 3; i++) { float v = pArray[i]; if (v < aabbMin[i]) { v = aabbMin[i]; // v = max(v, b.min[i]) } if (v > aabbMax[i]) { v = aabbMax[i]; // v = min(v, b.max[i]) } q[i] = v; } return(TgcCollisionUtils.toVector3(q)); }