override protected void UpdateValues() { base.UpdateValues(); directionPlane = TGCPlane.FromPointNormal(GetPosition(), -GetVectorCostadoIzquierda()); planoCostado = TGCPlane.FromPointNormal(GetPosition(), GetVectorAdelante()); radarSphere.setValues(this.GetPosition(), radarSphere.Radius); }
/// <summary> /// Crear un nuevo Frustum acotado usando como base el portal recorado. /// La cantidad de planos del nuevo Frustum no tiene por qué ser 6. /// Depende de la forma que haya quedado en el portal recortado. /// </summary> private TGCPlane[] createFrustumPlanes(TGCVector3 cameraPos, TGCPlane[] currentFrustumPlanes, TGCVector3[] portalVerts, TGCPlane portalPlane) { //Hay un plano por cada vértice del polígono + 2 por el near y far plane var frustumPlanes = new TGCPlane[2 + portalVerts.Length]; //Cargar near y far plane originales //TODO: habria que usar el portalPlane para acercar el NearPlane hasta el portal frustumPlanes[0] = currentFrustumPlanes[0]; frustumPlanes[1] = currentFrustumPlanes[1]; //Generar los planos laterales en base al polígono remanente del portal //Vamos tomando de a dos puntos del polígono + la posición de la cámara y creamos un plano var lastP = portalVerts[portalVerts.Length - 1]; for (var i = 0; i < portalVerts.Length; i++) { var nextP = portalVerts[i]; //Armar el plano para que la normal apunte hacia adentro del Frustum var a = lastP - cameraPos; var b = nextP - cameraPos; var plane = TGCPlane.FromPointNormal(cameraPos, TGCVector3.Cross(b, a)); //Guardar después del near y far plane frustumPlanes[i + 2] = plane; lastP = nextP; } return(frustumPlanes); }
public Plane(TGCVector3 minPoint, TGCVector3 maxPoint, TGCVector3 orientation, string fileName, float UCoordinate, float VCoordinate) { orientation.Normalize(); this.plane = new TgcPlane(new TGCVector3(0, 0, 0), new TGCVector3(0, 0, 0), this.GetPlaneOrientation(orientation), TgcTexture.createTexture(GlobalConcepts.GetInstance().GetMediaDir() + "MeshCreator\\Meshes\\" + fileName), UCoordinate, VCoordinate); this.plane.setExtremes(minPoint, maxPoint); this.plane.updateValues(); this.mesh = this.plane.toMesh("plane"); mesh.AutoTransform = false; //negrada atomica InvertNormals(orientation); this.realPlane = TGCPlane.FromPointNormal(minPoint, orientation); mesh.Effect = TgcShaders.Instance.TgcMeshPointLightShader; mesh.Technique = "DIFFUSE_MAP"; }
/// <summary> /// Detección de colisiones recursiva /// </summary> public void doCollideWithWorld(TgcBoundingSphere characterSphere, TGCVector3 movementVector, List <TgcBoundingAxisAlignBox> obstaculos, int recursionDepth) { //Limitar recursividad if (recursionDepth > 5) { return; } //Ver si la distancia a recorrer es para tener en cuenta var distanceToTravelSq = movementVector.LengthSq(); if (distanceToTravelSq < EPSILON) { return; } //Posicion deseada var originalSphereCenter = characterSphere.Center; var nextSphereCenter = originalSphereCenter + movementVector; //Buscar el punto de colision mas cercano de todos los objetos candidatos var minCollisionDistSq = float.MaxValue; var realMovementVector = movementVector; TgcBoundingAxisAlignBox.Face collisionFace = null; TgcBoundingAxisAlignBox collisionObstacle = null; var nearestPolygonIntersectionPoint = TGCVector3.Empty; foreach (var obstaculoBB in obstaculos) { //Obtener los polígonos que conforman las 6 caras del BoundingBox var bbFaces = obstaculoBB.computeFaces(); foreach (var bbFace in bbFaces) { var pNormal = TgcCollisionUtils.getPlaneNormal(bbFace.Plane); var movementRay = new TgcRay(originalSphereCenter, movementVector); float brutePlaneDist; TGCVector3 brutePlaneIntersectionPoint; if ( !TgcCollisionUtils.intersectRayPlane(movementRay, bbFace.Plane, out brutePlaneDist, out brutePlaneIntersectionPoint)) { continue; } var movementRadiusLengthSq = TGCVector3.Multiply(movementVector, characterSphere.Radius).LengthSq(); if (brutePlaneDist * brutePlaneDist > movementRadiusLengthSq) { continue; } //Obtener punto de colisión en el plano, según la normal del plano float pDist; TGCVector3 planeIntersectionPoint; TGCVector3 sphereIntersectionPoint; var planeNormalRay = new TgcRay(originalSphereCenter, -pNormal); var embebbed = false; var collisionFound = false; if (TgcCollisionUtils.intersectRayPlane(planeNormalRay, bbFace.Plane, out pDist, out planeIntersectionPoint)) { //Ver si el plano está embebido en la esfera if (pDist <= characterSphere.Radius) { embebbed = true; //TODO: REVISAR ESTO, caso embebido a analizar con más detalle sphereIntersectionPoint = originalSphereCenter - pNormal * characterSphere.Radius; } //Esta fuera de la esfera else { //Obtener punto de colisión del contorno de la esfera según la normal del plano sphereIntersectionPoint = originalSphereCenter - TGCVector3.Multiply(pNormal, characterSphere.Radius); //Disparar un rayo desde el contorno de la esfera hacia el plano, con el vector de movimiento var sphereMovementRay = new TgcRay(sphereIntersectionPoint, movementVector); if ( !TgcCollisionUtils.intersectRayPlane(sphereMovementRay, bbFace.Plane, out pDist, out planeIntersectionPoint)) { //no hay colisión continue; } } //Ver si planeIntersectionPoint pertenece al polígono TGCVector3 newMovementVector; float newMoveDistSq; TGCVector3 polygonIntersectionPoint; if (pointInBounbingBoxFace(planeIntersectionPoint, bbFace)) { if (embebbed) { //TODO: REVISAR ESTO, nunca debería pasar //throw new Exception("El polígono está dentro de la esfera"); } polygonIntersectionPoint = planeIntersectionPoint; collisionFound = true; } else { //Buscar el punto mas cercano planeIntersectionPoint que tiene el polígono real de esta cara polygonIntersectionPoint = TgcCollisionUtils.closestPointRectangle3d(planeIntersectionPoint, bbFace.Extremes[0], bbFace.Extremes[1], bbFace.Extremes[2]); //Revertir el vector de velocidad desde el nuevo polygonIntersectionPoint para ver donde colisiona la esfera, si es que llega var reversePointSeg = polygonIntersectionPoint - movementVector; if (TgcCollisionUtils.intersectSegmentSphere(polygonIntersectionPoint, reversePointSeg, characterSphere, out pDist, out sphereIntersectionPoint)) { collisionFound = true; } } if (collisionFound) { //Nuevo vector de movimiento acotado newMovementVector = polygonIntersectionPoint - sphereIntersectionPoint; newMoveDistSq = newMovementVector.LengthSq(); if (newMoveDistSq <= distanceToTravelSq && newMoveDistSq < minCollisionDistSq) { minCollisionDistSq = newMoveDistSq; realMovementVector = newMovementVector; nearestPolygonIntersectionPoint = polygonIntersectionPoint; collisionFace = bbFace; collisionObstacle = obstaculoBB; } } } } } //Si nunca hubo colisión, avanzar todo lo requerido if (collisionFace == null) { //Avanzar hasta muy cerca var movementLength = movementVector.Length(); movementVector.Multiply((movementLength - EPSILON) / movementLength); characterSphere.moveCenter(movementVector); return; } //Solo movernos si ya no estamos muy cerca if (minCollisionDistSq >= EPSILON) { //Mover el BoundingSphere hasta casi la nueva posición real var movementLength = realMovementVector.Length(); realMovementVector.Multiply((movementLength - EPSILON) / movementLength); characterSphere.moveCenter(realMovementVector); } //Calcular plano de Sliding var slidePlaneOrigin = nearestPolygonIntersectionPoint; var slidePlaneNormal = characterSphere.Center - nearestPolygonIntersectionPoint; slidePlaneNormal.Normalize(); var slidePlane = TGCPlane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal); //Proyectamos el punto original de destino en el plano de sliding var slideRay = new TgcRay(nearestPolygonIntersectionPoint + TGCVector3.Multiply(movementVector, SlideFactor), slidePlaneNormal); float slideT; TGCVector3 slideDestinationPoint; if (TgcCollisionUtils.intersectRayPlane(slideRay, slidePlane, out slideT, out slideDestinationPoint)) { //Nuevo vector de movimiento var slideMovementVector = slideDestinationPoint - nearestPolygonIntersectionPoint; if (slideMovementVector.LengthSq() < EPSILON) { return; } //Recursividad para aplicar sliding doCollideWithWorld(characterSphere, slideMovementVector, obstaculos, recursionDepth + 1); } }
public override void Init() { //Cargar un mesh var loader = new TgcSceneLoader(); var scene = loader.loadSceneFromFile(MediaDir + "MeshCreator\\Meshes\\Cimientos\\PilarEgipcio\\PilarEgipcio-TgcScene.xml"); mesh = scene.Meshes[0]; //Obtener los vértices del mesh (esta operacion es lenta, copia de la GPU a la CPU, no hacer a cada rato) var vertices = mesh.getVertexPositions(); //Iterar sobre todos los vertices y construir triangulos, normales y planos var triCount = vertices.Length / 3; triangles = new List <TgcTriangle>(triCount); normals = new List <TgcArrow>(); planes = new List <TGCQuad>(); for (var i = 0; i < triCount; i++) { //Obtenemos los 3 vertices del triangulo, es importante saber como esta estructurado nuestro mesh. var a = vertices[i * 3]; var b = vertices[i * 3 + 1]; var c = vertices[i * 3 + 2]; //Obtener normal del triangulo. El orden influye en si obtenemos el vector normal hacia adentro o hacia afuera del mesh var normal = TGCVector3.Cross(c - a, b - a); normal.Normalize(); //Crear plano que contiene el triangulo a partir un vertice y la normal var plane = TGCPlane.FromPointNormal(a, normal); //Calcular el centro del triangulo. Hay muchos tipos de centros para un triangulo (http://www.mathopenref.com/trianglecenters.html) //Aca calculamos el mas simple var center = TGCVector3.Scale(a + b + c, 1 / 3f); ///////////// Creacion de elementos para poder dibujar a pantalla (propios de este ejemplo) /////////////// //Crear un quad (pequeno plano) con la clase TgcQuad para poder dibujar el plano que contiene al triangulo var quad = new TGCQuad(); quad.Center = center; quad.Normal = normal; quad.Color = adaptColorRandom(Color.DarkGreen); quad.Size = new TGCVector2(10, 10); quad.updateValues(); planes.Add(quad); //Creamos una flecha con la clase TgcArrow para poder dibujar la normal (la normal la estiramos un poco para que se pueda ver) normals.Add(TgcArrow.fromDirection(center, TGCVector3.Scale(normal, 10f))); //Creamos la clase TgcTriangle que es un helper para dibujar triangulos sueltos var t = new TgcTriangle(); t.A = a; t.B = b; t.C = c; t.Color = adaptColorRandom(Color.Red); t.updateValues(); triangles.Add(t); } //Modifiers meshModifier = AddBoolean("mesh", "mesh", true); trianglesModifier = AddBoolean("triangles", "triangles", true); normalsModifier = AddBoolean("normals", "normals", true); planesModifier = AddBoolean("planes", "planes", false); //Camara Camera = new TgcRotationalCamera(mesh.BoundingBox.calculateBoxCenter(), mesh.BoundingBox.calculateBoxRadius() * 2, Input); }
/// <summary> /// Detección de colisiones recursiva /// </summary> public void doCollideWithWorld(TgcBoundingSphere characterSphere, TGCVector3 movementVector, List <Collider> colliders, int recursionDepth, TgcBoundingSphere movementSphere, bool sliding, float slidingMinY) { //Limitar recursividad if (recursionDepth > 5) { return; } //Posicion deseada var originalSphereCenter = characterSphere.Center; var nextSphereCenter = originalSphereCenter + movementVector; //Buscar el punto de colision mas cercano de todos los objetos candidatos Collision = false; TGCVector3 q; float t; TGCVector3 n; var minT = float.MaxValue; foreach (var collider in colliders) { //Colisionar Sphere en movimiento contra Collider (cada Collider resuelve la colision) if (collider.intersectMovingSphere(characterSphere, movementVector, movementSphere, out t, out q, out n)) { //Quedarse con el menor instante de colision if (t < minT) { minT = t; Collision = true; LastCollisionPoint = q; LastCollisionNormal = n; lastCollider = collider; } } } //Si nunca hubo colisión, avanzar todo lo requerido if (!Collision) { //Avanzar todo lo pedido //lastCollisionDistance = movementVector.Length(); characterSphere.moveCenter(movementVector); return; } //Solo movernos si ya no estamos muy cerca if (minT >= EPSILON) { //Restar un poco al instante de colision, para movernos hasta casi esa distancia minT -= EPSILON; var realMovementVector = movementVector * minT; //Mover el BoundingSphere characterSphere.moveCenter(realMovementVector); //Quitarle al punto de colision el EPSILON restado al movimiento, para no afectar al plano de sliding var v = TGCVector3.Normalize(realMovementVector); LastCollisionPoint -= v * EPSILON; } if (sliding) { //Calcular plano de Sliding, como un plano tangete al punto de colision con la esfera, apuntando hacia el centro de la esfera var slidePlaneOrigin = LastCollisionPoint; var slidePlaneNormal = characterSphere.Center - LastCollisionPoint; slidePlaneNormal.Normalize(); var slidePlane = TGCPlane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal); //Calcular vector de movimiento para sliding, proyectando el punto de destino original sobre el plano de sliding var distance = TgcCollisionUtils.distPointPlane(nextSphereCenter, slidePlane); var newDestinationPoint = nextSphereCenter - distance * slidePlaneNormal; var slideMovementVector = newDestinationPoint - LastCollisionPoint; //No hacer recursividad si es muy pequeño slideMovementVector.Scale(SlideFactor); if (slideMovementVector.Length() < EPSILON) { return; } if (LastCollisionNormal.Y <= slidingMinY) { //Recursividad para aplicar sliding doCollideWithWorld(characterSphere, slideMovementVector, colliders, recursionDepth + 1, movementSphere, sliding, slidingMinY); } } }
public TGCPlane GetPlaneOfCollision(TgcRay ray, Vehicle car) { return(TGCPlane.FromPointNormal(this.GetPosition(), TGCVector3.Up)); }
/// <summary> /// Detección de colisiones recursiva /// </summary> /// <param name="eSphere">Sphere de radio 1 pasada a Elipsoid space</param> /// <param name="eMovementVector">Movimiento pasado a Elipsoid space</param> /// <param name="eRadius">Radio de la elipsoide</param> /// <param name="colliders">Objetos contra los cuales colisionar</param> /// <param name="recursionDepth">Nivel de recursividad</param> /// <param name="movementSphere">Esfera real que representa el movimiento abarcado</param> /// <param name="slidingMinY">Minimo valor de normal Y de colision para hacer sliding</param> /// <returns>Resultado de colision</returns> public CollisionResult doCollideWithWorld(TgcBoundingSphere eSphere, TGCVector3 eMovementVector, TGCVector3 eRadius, List <Collider> colliders, int recursionDepth, TgcBoundingSphere movementSphere, float slidingMinY) { var result = new CollisionResult(); result.collisionFound = false; //Limitar recursividad if (recursionDepth > 5) { return(result); } //Posicion deseada var nextSphereCenter = eSphere.Center + eMovementVector; //Buscar el punto de colision mas cercano de todos los objetos candidatos TGCVector3 q; float t; TGCVector3 n; var minT = float.MaxValue; foreach (var collider in colliders) { //Colisionar Sphere en movimiento contra Collider (cada Collider resuelve la colision) if (collider.intersectMovingElipsoid(eSphere, eMovementVector, eRadius, movementSphere, out t, out q, out n)) { //Quedarse con el menor instante de colision if (t < minT) { minT = t; result.collisionFound = true; result.collisionPoint = q; result.collisionNormal = n; result.collider = collider; } } } //Si nunca hubo colisión, avanzar todo lo requerido if (!result.collisionFound) { //Avanzar todo lo pedido eSphere.moveCenter(eMovementVector); result.realMovmentVector = eMovementVector; result.collisionNormal = TGCVector3.Empty; result.collisionPoint = TGCVector3.Empty; result.collider = null; return(result); } //Solo movernos si ya no estamos muy cerca if (minT >= EPSILON) { //Restar un poco al instante de colision, para movernos hasta casi esa distancia minT -= EPSILON; result.realMovmentVector = eMovementVector * minT; eSphere.moveCenter(result.realMovmentVector); //Quitarle al punto de colision el EPSILON restado al movimiento, para no afectar al plano de sliding var v = TGCVector3.Normalize(result.realMovmentVector); result.collisionPoint -= v * EPSILON; } //Calcular plano de Sliding, como un plano tangete al punto de colision con la esfera, apuntando hacia el centro de la esfera var slidePlaneOrigin = result.collisionPoint; var slidePlaneNormal = eSphere.Center - result.collisionPoint; slidePlaneNormal.Normalize(); var slidePlane = TGCPlane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal); //Calcular vector de movimiento para sliding, proyectando el punto de destino original sobre el plano de sliding var distance = TgcCollisionUtils.distPointPlane(nextSphereCenter, slidePlane); var newDestinationPoint = nextSphereCenter - distance * slidePlaneNormal; var slideMovementVector = newDestinationPoint - result.collisionPoint; //No hacer recursividad si es muy pequeño slideMovementVector.Scale(SlideFactor); if (slideMovementVector.Length() < EPSILON) { return(result); } //Ver si posee la suficiente pendiente en Y para hacer sliding if (result.collisionNormal.Y <= slidingMinY) { //Recursividad para aplicar sliding doCollideWithWorld(eSphere, slideMovementVector, eRadius, colliders, recursionDepth + 1, movementSphere, slidingMinY); } return(result); }