public void init() { Device device = GuiController.Instance.D3dDevice; sphere = new TgcBoundingSphere(posicion, EXPLOSION_RADIUS); sound = new TgcStaticSound(); time = 0; int width = GuiController.Instance.Panel3d.Width; int height = GuiController.Instance.Panel3d.Height; int cantExplosion = 20; float particleTime = 1f, sizeMax = 2000f, expSpeed = 1f, expSizeSpeed = 20f; ; float expUpdateTime = 0; //Creo el emisor de explosion emisorExplosion = new ExplosionEmitter(cantExplosion, posicion, new Vector3(expSpeed, expSpeed, expSpeed), new Vector3(0.00f, 0.00f, 0.00f), 500f, sizeMax, particleTime, Color.White, 150, 0f, expUpdateTime, GameManager.Instance.random.Next(0, 1000), expSizeSpeed, 2); emisorExplosion.Init(); int cantidad = 20; Vector3 origen1 = posicion; float speed = 5f; float divergence = 7f; Vector3 velocidad = new Vector3(divergence, speed, divergence); Vector3 aceleracion = new Vector3(0, 0, 0); float min = 500f, max = 1000f, tiempoVida_Particula = 1f; int alpha = 150; float spawn = 0.01f; float sizeSpeed = 1000f; float updateTime = 0.02f; //Creo los emisores de humo emisorHumo = new SmokeEmitter(cantidad, origen1, velocidad, aceleracion, min, max, tiempoVida_Particula, Color.DarkGray, alpha, spawn, updateTime, sizeSpeed); emisorHumo.Init(); }
public override void init() { Microsoft.DirectX.Direct3D.Device d3dDevice = GuiController.Instance.D3dDevice; //Cuerpo principal que se controla con el teclado box = TgcBox.fromSize(new Vector3(0, 10, 0), new Vector3(10, 10, 10), Color.Blue); //triangulo triangle = new CustomVertex.PositionColored[3]; triangle[0] = new CustomVertex.PositionColored(-100, 0, 0, Color.Red.ToArgb()); triangle[1] = new CustomVertex.PositionColored(0, 0, 50, Color.Green.ToArgb()); triangle[2] = new CustomVertex.PositionColored(0, 100, 0, Color.Blue.ToArgb()); triagleAABB = TgcBoundingBox.computeFromPoints(new Vector3[] { triangle[0].Position, triangle[1].Position, triangle[2].Position }); //box2 box2 = TgcBox.fromSize(new Vector3(-50, 10, -20), new Vector3(15, 15, 15), Color.Violet); //sphere sphere = new TgcBoundingSphere(new Vector3(30, 20, -20), 15); //OBB: computar OBB a partir del AABB del mesh. TgcSceneLoader loader = new TgcSceneLoader(); TgcMesh meshObb = loader.loadSceneFromFile(GuiController.Instance.ExamplesMediaDir + "MeshCreator\\Meshes\\Vehiculos\\StarWars-ATST\\StarWars-ATST-TgcScene.xml").Meshes[0]; obb = TgcObb.computeFromAABB(meshObb.BoundingBox); meshObb.dispose(); obb.move(new Vector3(100, 0, 30)); obb.setRotation(new Vector3(0, FastMath.PI / 4, 0)); //Configurar camara en Tercer Persona GuiController.Instance.ThirdPersonCamera.Enable = true; GuiController.Instance.ThirdPersonCamera.setCamera(box.Position, 30, -75); }
public Enemigo(Vector3 posicionInicial, EscenarioManager escenarioManager) { this.huellas = new HuellasManager(10); this.teMataron = false; this.escenarioManager = escenarioManager; this.enemigoAmigacion = Enemigo.getAnimacion(); this.mesh = Enemigo.getMesh(); sangre = new TgcCylinder(posicionInicial, 0, 20, 0); sangre.Color = Color.Red; sangre.updateValues(); enemigoEsfera = new TgcBoundingSphere(new Vector3(posicionInicial.X, 30, posicionInicial.Z), 10); Random rnd = new Random(); mesh.Position = posicionInicial; mesh.Scale = new Vector3(1f, 1f, 1f); mesh.AutoTransformEnable = true; this.cabezaBounding = new TgcBoundingSphere(new Vector3(posicionInicial.X, posicionInicial.Y + 20, posicionInicial.Z), 20); this.setEstado(new EnemigoQuieto(this)); }
public bool isAnyCollidingWith(TgcBoundingSphere tankSphere) { foreach (var tree in trees) { if (TgcCollisionUtils.testSphereSphere(tree.boundingSphere, tankSphere)) return true; } return false; }
public override void init() { collider = new TgcFixedYBoundingCylinder(new Vector3(0, 0, 0), 3, 3); collisionableSphere = new TgcBoundingSphere(new Vector3(-6, 0, 0), 3); collisionableAABB = new TgcBoundingBox(new Vector3(4, 0, -1), new Vector3(6, 2, 1)); collisionableCylinder = new TgcFixedYBoundingCylinder(new Vector3(0, 0, -6), 2, 2); GuiController.Instance.Modifiers.addVertex2f("size", new Vector2(1, 1), new Vector2(5, 10), new Vector2(2, 5)); GuiController.Instance.Modifiers.addVertex3f("position", new Vector3(-20, -20, -20), new Vector3(20, 20, 20), new Vector3(0, 0, 0)); collider.setRenderColor(Color.LimeGreen); }
public override void init() { collider = new TgcBoundingCylinder(new Vector3(0, 0, 0), 2, 4); collisionableSphere = new TgcBoundingSphere(new Vector3(0, 0, -6), 3); GuiController.Instance.Modifiers.addVertex2f("size", new Vector2(1, 1), new Vector2(5, 10), new Vector2(2, 5)); GuiController.Instance.Modifiers.addVertex3f("position", new Vector3(-20, -20, -20), new Vector3(20, 20, 20), new Vector3(0, 0, 0)); float angle = FastMath.TWO_PI; GuiController.Instance.Modifiers.addVertex3f("rotation", new Vector3(-angle, -angle, -angle), new Vector3(angle, angle, angle), new Vector3(0, 0, 0)); collider.setRenderColor(Color.LimeGreen); }
public SphereTriangleCollisionManager() { gravityEnabled = true; gravityForce = new Vector3(0, -10, 0); slideFactor = 1.3f; lastCollisionNormal = Vector3.Empty; movementSphere = new TgcBoundingSphere(); objetosCandidatos = new List<Collider>(); lastCollider = null; onGroundMinDotValue = 0.8f; collision = false; lastMovementVector = Vector3.Empty; }
/// <summary> /// Mover BoundingSphere con detección de colisiones, sliding y gravedad. /// Se actualiza la posición del centrodel BoundingSphere. /// </summary> /// <param name="characterSphere">BoundingSphere del cuerpo a mover</param> /// <param name="movementVector">Movimiento a realizar</param> /// <param name="obstaculos">BoundingBox de obstáculos contra los cuales se puede colisionar</param> /// <returns>Desplazamiento relativo final efecutado al BoundingSphere</returns> public Vector3 moveCharacter(TgcBoundingSphere characterSphere, Vector3 movementVector, List<TgcBoundingBox> obstaculos) { Vector3 originalSphereCenter = characterSphere.Center; //Realizar movimiento collideWithWorld(characterSphere, movementVector, obstaculos); //Aplicar gravedad if (gravityEnabled) { collideWithWorld(characterSphere, gravityForce, obstaculos); } return characterSphere.Center - originalSphereCenter; }
/// <summary> /// Crear inicializado /// </summary> public ElipsoidCollisionManager() { gravityEnabled = true; gravityForce = new Vector3(0, -10, 0); slideFactor = 1.3f; movementSphere = new TgcBoundingSphere(); eSphere = new TgcBoundingSphere(); objetosCandidatos = new List<Collider>(); onGroundMinDotValue = 0.72f; result = new CollisionResult(); result.collisionFound = false; result.collisionNormal = Vector3.Empty; result.collisionPoint = Vector3.Empty; result.realMovmentVector = Vector3.Empty; }
public override void init() { cylinder = new Cylinder(new Vector3(0, 0, 0), 2, 4); sphere = new TgcBoundingSphere(new Vector3(0, 0, 0), 3); //cylinder.Transform = Matrix.Scaling(2, 1, 1); //cylinder.AutoTransformEnable = false; //cylinder.updateValues(); GuiController.Instance.Modifiers.addBoolean("boundingCylinder", "boundingCylinder", false); GuiController.Instance.Modifiers.addColor("color", Color.DarkGoldenrod); GuiController.Instance.Modifiers.addVertex2f("size", new Vector2(1, 1), new Vector2(5, 10), new Vector2(2, 5)); GuiController.Instance.Modifiers.addVertex3f("position", new Vector3(-20, -20, -20), new Vector3(20, 20, 20), new Vector3(0, 0, 0)); float angle = FastMath.TWO_PI; GuiController.Instance.Modifiers.addVertex3f("rotation", new Vector3(-angle, -angle, -angle), new Vector3(angle, angle, angle), new Vector3(0, 0, 0)); }
public Enemigo(Vector3 posicion) { //Cargar enemigo TgcSkeletalLoader skeletalLoader = new TgcSkeletalLoader(); meshEnemigos.Add("BasicHuman-TgcSkeletalMesh.xml"); meshEnemigos.Add("CombineSoldier-TgcSkeletalMesh.xml"); meshEnemigos.Add("CS_Gign-TgcSkeletalMesh.xml"); meshEnemigos.Add("CS_Arctic-TgcSkeletalMesh.xml"); meshEnemigos.Add("Pilot-TgcSkeletalMesh.xml"); meshEnemigos.Add("Quake2Scout-TgcSkeletalMesh.xml"); meshEnemigos.Add("WomanJeans-TgcSkeletalMesh.xml"); enemigo = skeletalLoader.loadMeshAndAnimationsFromFile( GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\" + meshEnemigos[randomEnemigo.Next(0, 6)], new string[] { GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\Animations\\" + "Walk-TgcSkeletalAnim.xml", GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\Animations\\" + "StandBy-TgcSkeletalAnim.xml", GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\BasicHuman\\Animations\\" + "Run-TgcSkeletalAnim.xml", GuiController.Instance.AlumnoEjemplosMediaDir + "CEGA\\Animations\\" + "Death-TgcSkeletalAnim.xml", }); enemigo.playAnimation("Run", true); enemigo.Position = posicion; enemigo.Scale = new Vector3(0.12f, 0.12f, 0.12f); this.colisionado = false; //Inicializo HP hp = 100; //Creo el BB para la cabeza cabeza = new TgcBoundingSphere(new Vector3(enemigo.Position.X, enemigo.Position.Y + 5.2F, enemigo.Position.Z), 0.5F); //Debe haber alguna forma de sacar esta info del hueso directamente cabeza.setRenderColor(System.Drawing.Color.Red); //Modifico el BB del cuerpo enemigo.AutoUpdateBoundingBox = false; enemigo.BoundingBox.scaleTranslate(enemigo.Position, new Vector3(0.07f, 0.095f, 0.07f)); //Inicializo el emisor emisorDeParticulas = new ParticleEmitter(GuiController.Instance.AlumnoEjemplosMediaDir + "CEGA\\Textures\\blood.jpg", 500); emisorDeParticulas.Playing = false; }
public Tank(Vector3 initialPosition, Terrain.Terrain terrain, string scenePath) { var loader = new TgcSceneLoader { MeshFactory = new MeshShaderFactory() }; var scene = loader.loadSceneFromFile(scenePath); this.mesh = (MeshShader) scene.Meshes[0]; this.loadShader(); this.terrain = terrain; missilesShooted = new List<Missile>(); this.boundingSphere = new TgcBoundingSphere(this.mesh.BoundingBox.calculateBoxCenter(), this.mesh.BoundingBox.calculateBoxRadius()*3); this.mesh.AutoTransformEnable = this.mesh.AutoUpdateBoundingBox = false; this.translationMatrix = Matrix.Identity; this.Position = initialPosition; this.setTranslationMatrix(initialPosition); this.totalSpeed = 0f; this.totalRotationSpeed = 100f; this.forwardVector = new Vector3(0, 0, -1); }
public override void init() { Device d3dDevice = GuiController.Instance.D3dDevice; CommandosUI.Instance.Camera = new TgcCameraAdapter(new StandardCamera()); //this.lastPos = new Vector3(0, 0, 0); //GuiController.Instance.Modifiers.addVertex3f("posicion", new Vector3(-200, 0, -200), new Vector3(200, 0, 200), this.lastPos); this.userCylinder = new CommandosCylinder(CommandosUI.Instance.Camera.getLookAt(), 40, 20, Color.Yellow); this.staticSphere = new TgcBoundingSphere(new Vector3(200, 0, -200), 40); this.staticCylinder = new CommandosCylinder(new Vector3(-100, 0, 0), 40, 40, Color.Yellow); this.staticAABB = new TgcBoundingBox(new Vector3(0, -40, -200), new Vector3(80, 40, -120)); //GuiController.Instance.Modifiers.addBoolean("closestPoint", "closestPoint", false); this.colisionNormal = new TgcArrow(); this.colisionNormal.Thickness = 2f; this.colisionNormal.HeadSize = new Vector2(4f, 4f); this.colisionNormal.Enabled = true; }
/// <summary> /// Detección de colisiones recursiva /// </summary> public void doCollideWithWorld(TgcBoundingSphere characterSphere, Vector3 movementVector, List<Collider> colliders, int recursionDepth, TgcBoundingSphere movementSphere, bool sliding, float slidingMinY) { //Limitar recursividad if (recursionDepth > 5) { return; } //Posicion deseada Vector3 originalSphereCenter = characterSphere.Center; Vector3 nextSphereCenter = originalSphereCenter + movementVector; //Buscar el punto de colision mas cercano de todos los objetos candidatos collision = false; Vector3 q; float t; Vector3 n; float minT = float.MaxValue; foreach (Collider 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; Vector3 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 Vector3 v = Vector3.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 Vector3 slidePlaneOrigin = lastCollisionPoint; Vector3 slidePlaneNormal = characterSphere.Center - lastCollisionPoint; slidePlaneNormal.Normalize(); Plane slidePlane = Plane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal); //Calcular vector de movimiento para sliding, proyectando el punto de destino original sobre el plano de sliding float distance = TgcCollisionUtils.distPointPlane(nextSphereCenter, slidePlane); Vector3 newDestinationPoint = nextSphereCenter - distance * slidePlaneNormal; Vector3 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); } } }
/// <summary> /// Detecta colision entre una esfera que se esta moviendo contra un plano. /// Si hay colision devuelve el instante t de la colision y el punto q de colision. /// </summary> /// <param name="sphere">BoundingSphere</param> /// <param name="velocity">Vector de movimiento de la esfera</param> /// <param name="plane">Plano</param> /// <param name="t">Instante de colision en el intervalo [0, 1]</param> /// <param name="q">Punto de colision</param> /// <returns>True si hay colision</returns> public static bool intersectMovingSpherePlane(TgcBoundingSphere sphere, Vector3 velocity, Plane plane, out float t, out Vector3 q) { // Compute distance of sphere center to plane float dist = plane.Dot(sphere.Center); if (FastMath.Abs(dist) <= sphere.Radius) { // The sphere is already overlapping the plane. Set time of // intersection to zero and q to sphere center t = 0.0f; q = sphere.Center; return true; } else { Vector3 p_n = getPlaneNormal(plane); float denom = Vector3.Dot(p_n, velocity); if (denom * dist >= 0.0f) { // No intersection as sphere moving parallel to or away from plane t = -1; q = Vector3.Empty; return false; } else { // Sphere is moving towards the plane // Use +r in computations if sphere in front of plane, else -r float r = dist > 0.0f ? sphere.Radius : -sphere.Radius; t = (r - dist) / denom; q = sphere.Center + t * velocity - r * p_n; if (t > 1) return false; return true; } } }
/// <summary> /// Colisiona un Elipsoide en movimiento contra el objeto colisionador. /// Si hay colision devuelve el instante t de colision, el punto q de colision y el vector normal n de la superficie contra la que /// se colisiona. /// Todo se devuelve en Elipsoid space. /// </summary> /// <param name="eSphere">BoundingSphere de radio 1 en Elipsoid space</param> /// <param name="eMovementVector">movimiento en Elipsoid space</param> /// <param name="eRadius">radio del Elipsoide</param> /// <param name="movementSphere">BoundingSphere que abarca el sphere en su punto de origen mas el sphere en su punto final deseado</param> /// <param name="t">Menor instante de colision, en Elipsoid space</param> /// <param name="q">Punto mas cercano de colision, en Elipsoid space</param> /// <param name="n">Vector normal de la superficie contra la que se colisiona</param> /// <returns>True si hay colision</returns> public abstract bool intersectMovingElipsoid(TgcBoundingSphere eSphere, Vector3 eMovementVector, Vector3 eRadius, TgcBoundingSphere movementSphere, out float t, out Vector3 q, out Vector3 n);
protected void configure(float radius, Color color, TgcTexture texture, Vector3 center) { this.autoTransformEnable = true; this.transform = Matrix.Identity; this.translation = center; this.rotation = new Vector3(0, 0, 0); this.enabled = true; this.scale = new Vector3(1, 1, 1); this.alphaBlendEnable = false; this.uvOffset = new Vector2(0, 0); //BoundingSphere boundingSphere = new TgcBoundingSphere(); //Shader this.effect = GuiController.Instance.Shaders.VariosShader; //Tipo de vertice y technique if (texture != null) this.setTexture(texture); else this.setColor(color); basePoly = eBasePoly.ICOSAHEDRON; levelOfDetail = 2; inflate = true; ForceUpdate = false; uvTiling = new Vector2(1, 1); }
/// <summary> /// Mover BoundingSphere con detección de colisiones, sliding y gravedad. /// Se actualiza la posición del centrodel BoundingSphere. /// </summary> /// <param name="characterSphere">BoundingSphere del cuerpo a mover</param> /// <param name="movementVector">Movimiento a realizar</param> /// <param name="colliders">Obstáculos contra los cuales se puede colisionar</param> /// <returns>Desplazamiento relativo final efecutado al BoundingSphere</returns> public Vector3 moveCharacter(TgcBoundingSphere characterSphere, Vector3 movementVector, List<Collider> colliders) { Vector3 originalSphereCenter = characterSphere.Center; //Mover collideWithWorld(characterSphere, movementVector, colliders, true, 1); //Aplicar gravedad if (gravityEnabled) { collideWithWorld(characterSphere, gravityForce, colliders, true, onGroundMinDotValue); } //Calcular el desplazamiento real que hubo lastMovementVector = characterSphere.Center - originalSphereCenter; return lastMovementVector; }
/// <summary> /// Detección de colisiones, filtrando los obstaculos que se encuentran dentro del radio de movimiento /// </summary> private void collideWithWorld(TgcBoundingSphere characterSphere, Vector3 movementVector, List<Collider> colliders, bool sliding, float slidingMinY) { //Ver si la distancia a recorrer es para tener en cuenta float distanceToTravelSq = movementVector.LengthSq(); if (distanceToTravelSq < EPSILON) { return; } //Dejar solo los obstáculos que están dentro del radio de movimiento de la esfera Vector3 halfMovementVec = Vector3.Multiply(movementVector, 0.5f); movementSphere.setValues( characterSphere.Center + halfMovementVec, halfMovementVec.Length() + characterSphere.Radius ); objetosCandidatos.Clear(); foreach (Collider collider in colliders) { if (collider.Enable && TgcCollisionUtils.testSphereSphere(movementSphere, collider.BoundingSphere)) { objetosCandidatos.Add(collider); } } //Detectar colisiones y deplazar con sliding doCollideWithWorld(characterSphere, movementVector, objetosCandidatos, 0, movementSphere, sliding, slidingMinY); }
/// <summary> /// Crear triangulo. /// Calcula su plano y BoundingSphere /// </summary> public Triangle(Vector3 a, Vector3 b, Vector3 c) { this.a = a; this.b = b; this.c = c; this.plane = Plane.FromPoints(a, b, c); this.boundingSphere = TgcBoundingSphere.computeFromPoints(new Vector3[] { a, b, c }).toClass(); }
public override void init() { Microsoft.DirectX.Direct3D.Device d3dDevice = GuiController.Instance.D3dDevice; //Cargar escenario específico para este ejemplo TgcSceneLoader loader = new TgcSceneLoader(); escenario = loader.loadSceneFromFile(GuiController.Instance.ExamplesDir + "\\Collision\\SphereCollision\\PatioDeJuegos\\PatioDeJuegos-TgcScene.xml"); //Cargar personaje con animaciones TgcSkeletalLoader skeletalLoader = new TgcSkeletalLoader(); personaje = skeletalLoader.loadMeshAndAnimationsFromFile( GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\Robot\\" + "Robot-TgcSkeletalMesh.xml", GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\Robot\\", new string[] { GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\Robot\\" + "Caminando-TgcSkeletalAnim.xml", GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\Robot\\" + "Parado-TgcSkeletalAnim.xml", }); //Le cambiamos la textura para diferenciarlo un poco personaje.changeDiffuseMaps(new TgcTexture[] { TgcTexture.createTexture(d3dDevice, GuiController.Instance.ExamplesMediaDir + "SkeletalAnimations\\Robot\\Textures\\" + "uvwGreen.jpg") }); //Configurar animacion inicial personaje.playAnimation("Parado", true); //Escalarlo porque es muy grande personaje.Position = new Vector3(0,500,-100); //Rotarlo 180° porque esta mirando para el otro lado personaje.rotateY(Geometry.DegreeToRadian(180f)); //BoundingSphere que va a usar el personaje personaje.AutoUpdateBoundingBox = false; characterSphere = new TgcBoundingSphere(personaje.BoundingBox.calculateBoxCenter(), personaje.BoundingBox.calculateBoxRadius()); //Almacenar volumenes de colision del escenario objetosColisionables.Clear(); foreach (TgcMesh mesh in escenario.Meshes) { objetosColisionables.Add(mesh.BoundingBox); } //Crear linea para mostrar la direccion del movimiento del personaje directionArrow = new TgcArrow(); directionArrow.BodyColor = Color.Red; directionArrow.HeadColor = Color.Green; directionArrow.Thickness = 1; directionArrow.HeadSize = new Vector2(10, 20); //Crear manejador de colisiones collisionManager = new SphereCollisionManager(); collisionManager.GravityEnabled = true; //Configurar camara en Tercer Persona GuiController.Instance.ThirdPersonCamera.Enable = true; GuiController.Instance.ThirdPersonCamera.setCamera(personaje.Position, 100, -400); GuiController.Instance.ThirdPersonCamera.TargetDisplacement = new Vector3(0, 100, 0); //Crear SkyBox skyBox = new TgcSkyBox(); skyBox.Center = new Vector3(0, 0, 0); skyBox.Size = new Vector3(10000, 10000, 10000); string texturesPath = GuiController.Instance.ExamplesMediaDir + "Texturas\\Quake\\SkyBox3\\"; skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Up, texturesPath + "Up.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Down, texturesPath + "Down.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Left, texturesPath + "Left.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Right, texturesPath + "Right.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Front, texturesPath + "Back.jpg"); skyBox.setFaceTexture(TgcSkyBox.SkyFaces.Back, texturesPath + "Front.jpg"); skyBox.updateValues(); //Modifier para ver BoundingBox GuiController.Instance.Modifiers.addBoolean("showBoundingBox", "Bouding Box", true); //Modifiers para desplazamiento del personaje GuiController.Instance.Modifiers.addFloat("VelocidadCaminar", 0, 100, 16); GuiController.Instance.Modifiers.addFloat("VelocidadRotacion", 1f, 360f, 150f); GuiController.Instance.Modifiers.addBoolean("HabilitarGravedad", "Habilitar Gravedad", true); GuiController.Instance.Modifiers.addVertex3f("Gravedad", new Vector3(-50, -50, -50), new Vector3(50, 50, 50), new Vector3(0, -10, 0)); GuiController.Instance.Modifiers.addFloat("SlideFactor", 1f, 2f, 1.3f); GuiController.Instance.UserVars.addVar("Movement"); }
/// <summary> /// Colisiona un Elipsoide en movimiento contra un conjunto de triangulos. /// Si hay colision devuelve el instante t de colision, el punto q de colision y el vector normal n de la superficie contra la que /// se colisiona. /// Todo se devuelve en Elipsoid space. /// Pasa cada triangulo a Elipsoid space para hacer el testeo. /// </summary> /// <param name="eSphere">BoundingSphere de radio 1 en Elipsoid space</param> /// <param name="eMovementVector">movimiento en Elipsoid space</param> /// <param name="eRadius">radio del Elipsoide</param> /// <param name="movementSphere">BoundingSphere que abarca el sphere en su punto de origen mas el sphere en su punto final deseado</param> /// <param name="minT">Menor instante de colision, en Elipsoid space</param> /// <param name="minQ">Punto mas cercano de colision, en Elipsoid space</param> /// <param name="n">Vector normal de la superficie contra la que se colisiona</param> /// <returns>True si hay colision</returns> public override bool intersectMovingElipsoid(TgcBoundingSphere eSphere, Vector3 eMovementVector, Vector3 eRadius, TgcBoundingSphere movementSphere, out float minT, out Vector3 minQ, out Vector3 n) { minQ = Vector3.Empty; minT = float.MaxValue; n = Vector3.Empty; Plane collisionPlane = Plane.Empty; //Colision contra cada triangulo del collider, quedarse con el menor Vector3 q; float t; for (int i = 0; i < triangles.Length; i++) { Triangle triangle = triangles[i]; //Primero hacer un Sphere-Sphere test if (TgcCollisionUtils.testSphereSphere(movementSphere, triangle.BoundingSphere)) { //Pasar triangle a Elipsoid Space Triangle eTriangle = new Triangle( TgcVectorUtils.div(triangle.A, eRadius), TgcVectorUtils.div(triangle.B, eRadius), TgcVectorUtils.div(triangle.C, eRadius), null ); //Interseccion Moving Sphere-Triangle if (intersectMovingSphereTriangle(eSphere, eMovementVector, eTriangle, out t, out q)) { if (t < minT) { minT = t; minQ = q; collisionPlane = triangle.Plane; } } } } if (minT != float.MaxValue) { n = TgcCollisionUtils.getPlaneNormal(collisionPlane); return true; } return false; }
/// <summary> /// Crear triangulo. /// Calcula su plano /// </summary> public Triangle(Vector3 a, Vector3 b, Vector3 c, TgcBoundingSphere sphere) { this.a = a; this.b = b; this.c = c; this.plane = Plane.FromPoints(a, b, c); this.boundingSphere = sphere; }
/// <summary> /// Indica si un BoundingSphere colisiona con otro. /// </summary> /// <returns>True si hay colisión</returns> public static bool testSphereSphere(TgcBoundingSphere a, TgcBoundingSphere b) { // Calculate squared distance between centers Vector3 d = a.Center - b.Center; float dist2 = Vector3.Dot(d, d); // Spheres intersect if squared distance is less than squared sum of radii float radiusSum = a.Radius + b.Radius; return dist2 <= radiusSum * radiusSum; }
/// <summary> /// Detectar colision entre una esfera que se mueve y un triangulo /// </summary> /// <param name="sphere">BoundingSphere</param> /// <param name="movementVector">Vector de movimiento de la esferfa</param> /// <param name="triangle">Triangulo</param> /// <param name="collisionPoint">Menor punto de colision encontrado</param> /// <returns>True si hay colision</returns> private bool intersectMovingSphereTriangle(TgcBoundingSphere sphere, Vector3 movementVector, Triangle triangle, out float minT, out Vector3 collisionPoint) { float t; Vector3 q; collisionPoint = Vector3.Empty; minT = float.MaxValue; //Ver si la esfera en movimiento colisiona con el plano del triangulo if (!TgcCollisionUtils.intersectMovingSpherePlane(sphere, movementVector, triangle.Plane, out t, out q)) { return false; } //Ver si la esfera ya esta dentro del Plano, hacer un chequeo Sphere-Triangle if (t == 0.0f) { if (TgcCollisionUtils.testSphereTriangle(sphere, triangle.A, triangle.B, triangle.C, out q)) { minT = 0.0f; collisionPoint = q; return true; } } else { //Si el punto de colision contra el plano pertenece al triangulo, entonces ya encontramos el punto de colision if (TgcCollisionUtils.testPointInTriangle(q, triangle.A, triangle.B, triangle.C)) { minT = t; collisionPoint = q; return true; } } //Ver de que lado del plano del triangulo esta la esfera float distPlane = triangle.Plane.Dot(sphere.Center); float sphereRad = distPlane >= 0.0f ? sphere.Radius : -sphere.Radius; Vector3 planeNormal = TgcCollisionUtils.getPlaneNormal(triangle.Plane); //Chequear colision entre la esfera en movimiento y los tres Edge y obtener el menor punto de colision //Es como un Ray del centro de la esfera contra un edge que se convierte en cilindro sin endcap Vector3 segmentEnd = sphere.Center + movementVector; if (intersectSegmentCylinderNoEndcap(sphere.Center, segmentEnd, triangle.A, triangle.B, sphere.Radius, out t)) { minT = TgcCollisionUtils.min(t, minT); } if (intersectSegmentCylinderNoEndcap(sphere.Center, segmentEnd, triangle.B, triangle.C, sphere.Radius, out t)) { minT = TgcCollisionUtils.min(t, minT); } if (intersectSegmentCylinderNoEndcap(sphere.Center, segmentEnd, triangle.C, triangle.A, sphere.Radius, out t)) { minT = TgcCollisionUtils.min(t, minT); } //Si hubo colision, retornar la menor encontrada if (minT != float.MaxValue) { collisionPoint = sphere.Center + minT * movementVector - sphereRad * planeNormal; return true; } //Sino, chequear colision entra la esfera y los tres vertices del triangulo y obtener la menor //Es como un Ray del centro de la esfera contra un vertice que se convierte en esfera TgcBoundingSphere vertSphere = new TgcBoundingSphere(); minT = float.MaxValue; vertSphere.setValues(triangle.A, sphere.Radius); if (TgcCollisionUtils.intersectSegmentSphere(sphere.Center, segmentEnd, vertSphere, out t, out q)) { minT = TgcCollisionUtils.min(t, minT); } vertSphere.setValues(triangle.B, sphere.Radius); if (TgcCollisionUtils.intersectSegmentSphere(sphere.Center, segmentEnd, vertSphere, out t, out q)) { minT = TgcCollisionUtils.min(t, minT); } vertSphere.setValues(triangle.C, sphere.Radius); if (TgcCollisionUtils.intersectSegmentSphere(sphere.Center, segmentEnd, vertSphere, out t, out q)) { minT = TgcCollisionUtils.min(t, minT); } //Si hubo colision, retornar la menor encontrada if (minT != float.MaxValue) { collisionPoint = sphere.Center + minT * movementVector - sphereRad * planeNormal; return true; } //No hay colision return false; }
/// <summary> /// Indica si un BoundingSphere colisiona con un triangulo (a, b, c). /// Si hay colision devuelve el punto p mas cercano de la colision /// </summary> /// <param name="sphere">BoundingSphere</param> /// <param name="a">Vertice A del triangulo</param> /// <param name="b">Vertice B del triangulo</param> /// <param name="c">Vertice C del triangulo</param> /// <param name="p">Punto mas cercano de colision</param> /// <returns>True si hay colision</returns> public static bool testSphereTriangle(TgcBoundingSphere sphere, Vector3 a, Vector3 b, Vector3 c, out Vector3 p) { // Find point P on triangle ABC closest to sphere center p = TgcCollisionUtils.closestPointTriangle(sphere.Center, a, b, c); // Sphere and triangle intersect if the (squared) distance from sphere // center to point p is less than the (squared) sphere radius Vector3 v = p - sphere.Center; return Vector3.Dot(v, v) <= sphere.Radius * sphere.Radius; }
/// <summary> /// Colisiona un Elipsoide en movimiento contra el BoundingBox. /// Si hay colision devuelve el instante t de colision, el punto q de colision y el vector normal n de la superficie contra la que /// se colisiona. /// Todo se devuelve en Elipsoid space. /// El BoundingBox se pasa a Elipsoid space para comparar. /// </summary> /// <param name="eSphere">BoundingSphere de radio 1 en Elipsoid space</param> /// <param name="eMovementVector">movimiento en Elipsoid space</param> /// <param name="eRadius">radio del Elipsoide</param> /// <param name="movementSphere">BoundingSphere que abarca el sphere en su punto de origen mas el sphere en su punto final deseado</param> /// <param name="t">Menor instante de colision, en Elipsoid space</param> /// <param name="q">Punto mas cercano de colision, en Elipsoid space</param> /// <param name="n">Vector normal de la superficie contra la que se colisiona</param> /// <returns>True si hay colision</returns> public override bool intersectMovingElipsoid(TgcBoundingSphere eSphere, Vector3 eMovementVector, Vector3 eRadius, TgcBoundingSphere movementSphere, out float t, out Vector3 q, out Vector3 n) { //Pasar AABB a Elipsoid Space eAABB.setExtremes( TgcVectorUtils.div(aabb.PMin, eRadius), TgcVectorUtils.div(aabb.PMax, eRadius) ); t = -1f; q = Vector3.Empty; n = Vector3.Empty; // Compute the AABB resulting from expanding b by sphere radius r TgcBoundingBox.AABBStruct e = eAABB.toStruct(); e.min.X -= eSphere.Radius; e.min.Y -= eSphere.Radius; e.min.Z -= eSphere.Radius; e.max.X += eSphere.Radius; e.max.Y += eSphere.Radius; e.max.Z += eSphere.Radius; // Intersect ray against expanded AABB e. Exit with no intersection if ray // misses e, else get intersection point p and time t as result Vector3 p; TgcRay.RayStruct ray = new TgcRay.RayStruct(); ray.origin = eSphere.Center; ray.direction = eMovementVector; if (!intersectRayAABB(ray, e, out t, out p) || t > 1.0f) return false; // Compute which min and max faces of b the intersection point p lies // outside of. Note, u and v cannot have the same bits set and // they must have at least one bit set among them int i = 0; int[] sign = new int[3]; if (p.X < eAABB.PMin.X) { sign[0] = -1; i++; } if (p.X > eAABB.PMax.X) { sign[0] = 1; i++; } if (p.Y < eAABB.PMin.Y) { sign[1] = -1; i++; } if (p.Y > eAABB.PMax.Y) { sign[1] = 1; i++; } if (p.Z < eAABB.PMin.Z) { sign[2] = -1; i++; } if (p.Z > eAABB.PMax.Z) { sign[2] = 1; i++; } //Face if (i == 1) { n = new Vector3(sign[0], sign[1], sign[2]); q = eSphere.Center + t * eMovementVector - eSphere.Radius * n; return true; } // Define line segment [c, c+d] specified by the sphere movement Segment seg = new Segment(eSphere.Center, eSphere.Center + eMovementVector); //Box extent and center Vector3 extent = eAABB.calculateAxisRadius(); Vector3 center = eAABB.PMin + extent; //Edge if (i == 2) { //Generar los dos puntos extremos del Edge float[] extentDir = new float[]{sign[0], sign[1], sign[2]}; int zeroIndex = sign[0] == 0 ? 0 : (sign[1] == 0 ? 1 : 2); extentDir[zeroIndex] = 1; Vector3 capsuleA = center + new Vector3(extent.X * extentDir[0], extent.Y * extentDir[1], extent.Z * extentDir[2]); extentDir[zeroIndex] = -1; Vector3 capsuleB = center + new Vector3(extent.X * extentDir[0], extent.Y * extentDir[1], extent.Z * extentDir[2]); //Colision contra el Edge hecho Capsula if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, eSphere.Radius), out t)) { n = new Vector3(sign[0], sign[1], sign[2]); n.Normalize(); q = eSphere.Center + t * eMovementVector - eSphere.Radius * n; return true; } } //Vertex if (i == 3) { float tmin = float.MaxValue; Vector3 capsuleA = center + new Vector3(extent.X * sign[0], extent.Y * sign[1], extent.Z * sign[2]); Vector3 capsuleB; capsuleB = center + new Vector3(extent.X * -sign[0], extent.Y * sign[1], extent.Z * sign[2]); if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, eSphere.Radius), out t)) tmin = TgcCollisionUtils.min(t, tmin); capsuleB = center + new Vector3(extent.X * sign[0], extent.Y * -sign[1], extent.Z * sign[2]); if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, eSphere.Radius), out t)) tmin = TgcCollisionUtils.min(t, tmin); capsuleB = center + new Vector3(extent.X * sign[0], extent.Y * sign[1], extent.Z * -sign[2]); if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, eSphere.Radius), out t)) tmin = TgcCollisionUtils.min(t, tmin); if (tmin == float.MaxValue) return false; // No intersection t = tmin; n = new Vector3(sign[0], sign[1], sign[2]); n.Normalize(); q = eSphere.Center + t * eMovementVector - eSphere.Radius * n; return true; // Intersection at time t == tmin } return false; }
/// <summary> /// Indica si un BoundingSphere colisiona con el Frustum /// </summary> /// <param name="frustum">Frustum</param> /// <param name="sphere">BoundingSphere</param> /// <returns>Resultado de la colisión</returns> public static FrustumResult classifyFrustumSphere(TgcFrustum frustum, TgcBoundingSphere sphere) { float distance; FrustumResult result = FrustumResult.INSIDE; Plane[] frustumPlanes = frustum.FrustumPlanes; for (int i = 0; i < 6; i++) { distance = distPointPlane(sphere.Center, frustumPlanes[i]); if (distance < - sphere.Radius) { return FrustumResult.OUTSIDE; } else if (distance < sphere.Radius) { result = FrustumResult.INTERSECT; } } return result; }
/// <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, Vector3 eMovementVector, Vector3 eRadius, List<Collider> colliders, int recursionDepth, TgcBoundingSphere movementSphere, float slidingMinY) { CollisionResult result = new CollisionResult(); result.collisionFound = false; //Limitar recursividad if (recursionDepth > 5) { return result; } //Posicion deseada Vector3 nextSphereCenter = eSphere.Center + eMovementVector; //Buscar el punto de colision mas cercano de todos los objetos candidatos Vector3 q; float t; Vector3 n; float minT = float.MaxValue; foreach (Collider 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 = Vector3.Empty; result.collisionPoint = Vector3.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 Vector3 v = Vector3.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 Vector3 slidePlaneOrigin = result.collisionPoint; Vector3 slidePlaneNormal = eSphere.Center - result.collisionPoint; slidePlaneNormal.Normalize(); Plane slidePlane = Plane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal); //Calcular vector de movimiento para sliding, proyectando el punto de destino original sobre el plano de sliding float distance = TgcCollisionUtils.distPointPlane(nextSphereCenter, slidePlane); Vector3 newDestinationPoint = nextSphereCenter - distance * slidePlaneNormal; Vector3 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; }
// /// <summary> /// Indica si un BoundingSphere se encuentra completamente en el lado negativo del plano /// </summary> /// <returns>True si se encuentra completamente en el lado negativo del plano</returns> public static bool insideSpherePlane(TgcBoundingSphere s, Plane plane) { Vector3 p = toVector3(plane); float dist = Vector3.Dot(s.Center, p) - plane.D; return dist < -s.Radius; }