public OctreeNode crearOctree(List<TgcMesh> modelos, TgcBoundingBox sceneBounds) { OctreeNode rootNode = new OctreeNode(); Vector3 pMax = sceneBounds.PMax; Vector3 pMin = sceneBounds.PMin; //Calcular punto medio y centro Vector3 midSize = sceneBounds.calculateAxisRadius(); Vector3 center = sceneBounds.calculateBoxCenter(); //iniciar generacion recursiva de octree doSectorOctreeX(rootNode, center, midSize, 0, modelos); //podar nodos innecesarios deleteEmptyNodes(rootNode.children); //eliminar hijos que subdividen sin necesidad //deleteSameMeshCountChilds(rootNode); //imprimir por consola el octree //printDebugOctree(rootNode); //imprimir estadisticas de debug //printEstadisticasOctree(rootNode); return rootNode; }
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 Grid(MeshCreatorControl control) { this.control = control; //El bounding box del piso es bien grande para hacer colisiones boundingBox = new TgcBoundingBox(new Vector3(-BIG_VAL, -SMALL_VAL, -BIG_VAL), new Vector3(BIG_VAL, 0, BIG_VAL)); //Planos para colision de picking pickingXZAabb = new TgcBoundingBox(new Vector3(-BIG_VAL, -SMALL_VAL, -BIG_VAL), new Vector3(BIG_VAL, 0, BIG_VAL)); pickingXYAabb = new TgcBoundingBox(new Vector3(-BIG_VAL, -BIG_VAL, -SMALL_VAL), new Vector3(BIG_VAL, BIG_VAL, 0)); pickingYZAabb = new TgcBoundingBox(new Vector3(-SMALL_VAL, -BIG_VAL, -BIG_VAL), new Vector3(0, BIG_VAL, BIG_VAL)); vertices = new CustomVertex.PositionColored[12 * 2 * 2]; int color = Color.FromArgb(76, 76, 76).ToArgb(); //10 lineas horizontales en X for (int i = 0; i < 11; i++) { vertices[i * 2] = new CustomVertex.PositionColored(-GRID_RADIUS, 0, -GRID_RADIUS + LINE_SEPARATION * i, color); vertices[i * 2 + 1] = new CustomVertex.PositionColored(GRID_RADIUS, 0, -GRID_RADIUS + LINE_SEPARATION * i, color); } //10 lineas horizontales en Z for (int i = 11; i < 22; i++) { vertices[i * 2] = new CustomVertex.PositionColored(-GRID_RADIUS * 3 + LINE_SEPARATION * i - LINE_SEPARATION, 0, -GRID_RADIUS, color); vertices[i * 2 + 1] = new CustomVertex.PositionColored(-GRID_RADIUS * 3 + LINE_SEPARATION * i - LINE_SEPARATION, 0, GRID_RADIUS, color); } }
/// <summary> /// Crear Collider a partir de BoundingBox. /// Crea el BoundingSphere del Collider. /// </summary> /// <param name="mesh">BoundingBox</param> /// <returns>Collider creado</returns> public static BoundingBoxCollider fromBoundingBox(TgcBoundingBox aabb) { BoundingBoxCollider collider = new BoundingBoxCollider(); collider.aabb = aabb; collider.BoundingSphere = TgcBoundingSphere.computeFromPoints(aabb.computeCorners()).toClass(); return collider; }
/// <summary> /// Crea una caja vacia /// </summary> public TgcBox() { Device d3dDevice = GuiController.Instance.D3dDevice; vertices = new CustomVertex.PositionColoredTextured[36]; vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColoredTextured), vertices.Length, d3dDevice, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColoredTextured.Format, Pool.Default); this.autoTransformEnable = true; this.transform = Matrix.Identity; this.translation = new Vector3(0, 0, 0); this.rotation = new Vector3(0, 0, 0); this.enabled = true; this.color = Color.White; this.alphaBlendEnable = false; this.uvOffset = new Vector2(0, 0); this.uvTiling = new Vector2(1, 1); //BoundingBox boundingBox = new TgcBoundingBox(); //Shader this.effect = GuiController.Instance.Shaders.VariosShader; this.technique = TgcShaders.T_POSITION_COLORED; }
/// <summary> /// Crea una caja vacia /// </summary> public TgcBox() { Device d3dDevice = GuiController.Instance.D3dDevice; vertices = new CustomVertex.PositionColoredTextured[36]; vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColoredTextured), vertices.Length, d3dDevice, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColoredTextured.Format, Pool.Default); this.autoTransformEnable = true; this.transform = Matrix.Identity; this.translation = new Vector3(0,0,0); this.rotation = new Vector3(0,0,0); this.enabled = true; this.color = Color.White; this.alphaBlendEnable = false; this.uvOffset = new Vector2(0, 0); this.uvTiling = new Vector2(1, 1); //BoundingBox boundingBox = new TgcBoundingBox(); //Shader this.effect = GuiController.Instance.Shaders.VariosShader; this.technique = TgcShaders.T_POSITION_COLORED; }
public EscenarioManager() { EscenarioManager.Instance = this; sonido = SoundManager.getInstance(); arboles = new List<TgcMesh>(); pasto = new List<TgcMesh>(); barriles = new List<Barril>(); loader = new TgcSceneLoader(); casillasPorEje = 50; divisionesPiso = new Vector3[2500]; _random = new Random(); piso = new TgcBox(); piso.UVTiling = new Vector2(300, 300); pisoSize = (int) tamanio; piso.setPositionSize(new Vector3(0, 0, 0), new Vector3(pisoSize*2, 0, pisoSize*2)); piso.updateValues(); piso.setTexture(TgcTexture.createTexture(GuiController.Instance.D3dDevice, GuiController.Instance.AlumnoEjemplosMediaDir + "\\RenderMan\\texturas\\nieve.png")); generarSkyBox(); colisionables = new List<TgcBoundingCylinder>(); limites = new TgcBoundingBox(new Vector3(-tamanio, 0, -tamanio), new Vector3(tamanio, 5000, tamanio)); GuiController.Instance.Modifiers.addInt("Viento en X", 0, 30, 5); GuiController.Instance.Modifiers.addInt("Viento en Z", 0, 30, 5); }
public TgcSkeletalAnimation(string name, int frameRate, int framesCount, List<TgcSkeletalAnimationFrame>[] boneFrames, TgcBoundingBox boundingBox) { this.name = name; this.frameRate = frameRate; this.framesCount = framesCount; this.boneFrames = boneFrames; this.boundingBox = boundingBox; }
/// <summary> /// Clasifica un BoundingBox respecto de un Plano. /// </summary> /// <param name="plane">Plano</param> /// <param name="aabb">BoundingBox</param> /// <returns> /// Resultado de la clasificación. /// </returns> /// public static PlaneBoxResult classifyPlaneAABB(Plane plane, TgcBoundingBox aabb) { Vector3 vmin = Vector3.Empty; Vector3 vmax = Vector3.Empty; //Obtener puntos minimos y maximos en base a la dirección de la normal del plano if (plane.A >= 0f) { vmin.X = aabb.PMin.X; vmax.X = aabb.PMax.X; } else { vmin.X = aabb.PMax.X; vmax.X = aabb.PMin.X; } if (plane.B >= 0f) { vmin.Y = aabb.PMin.Y; vmax.Y = aabb.PMax.Y; } else { vmin.Y = aabb.PMax.Y; vmax.Y = aabb.PMin.Y; } if (plane.C >= 0f) { vmin.Z = aabb.PMin.Z; vmax.Z = aabb.PMax.Z; } else { vmin.Z = aabb.PMax.Z; vmax.Z = aabb.PMin.Z; } //Analizar punto minimo y maximo contra el plano PlaneBoxResult result; if (plane.Dot(vmin) > 0f) { result = PlaneBoxResult.IN_FRONT_OF; } else if (plane.Dot(vmax) > 0f) { result = PlaneBoxResult.INTERSECT; } else { result = PlaneBoxResult.BEHIND; } return(result); }
/// <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); }
public SmartTerrain() { enabled = true; alphaBlendEnable = false; //Shader Effect = TgcShaders.loadEffect(GuiController.Instance.ExamplesDir + "TerrainEditor\\Shaders\\EditableTerrain.fx"); Technique = "PositionColoredTextured"; aabb = new TgcBoundingBox(); }
/// <summary> /// Crear un BoundingBox igual a este /// </summary> /// <returns>BoundingBox clonado</returns> public TgcBoundingBox clone() { TgcBoundingBox cloneBbox = new TgcBoundingBox(); cloneBbox.pMin = this.pMin; cloneBbox.pMax = this.pMax; cloneBbox.pMinOriginal = this.pMinOriginal; cloneBbox.pMaxOriginal = this.pMaxOriginal; return(cloneBbox); }
/// <summary> /// Crea una pared vacia. /// </summary> public TgcPlaneWall() { this.vertices = new CustomVertex.PositionTextured[6]; this.autoAdjustUv = false; this.enabled = true; this.boundingBox = new TgcBoundingBox(); this.uTile = 1; this.vTile = 1; this.alphaBlendEnable = false; this.uvOffset = new Vector2(0, 0); }
/// <summary> /// Dibujar meshes que representan los sectores del Quadtree /// </summary> public List<TgcDebugBox> createDebugQuadtreeMeshes(QuadtreeNode rootNode, TgcBoundingBox sceneBounds) { Vector3 pMax = sceneBounds.PMax; Vector3 pMin = sceneBounds.PMin; List<TgcDebugBox> debugBoxes = new List<TgcDebugBox>(); doCreateQuadtreeDebugBox(rootNode, debugBoxes, pMin.X, pMin.Y, pMin.Z, pMax.X, pMax.Y, pMax.Z, 0); return debugBoxes; }
public SimpleTerrain() { enabled = true; alphaBlendEnable = false; //BoundingBox boundingBox = new TgcBoundingBox(); //Shader this.effect = GuiController.Instance.Shaders.VariosShader; this.technique = TgcShaders.T_POSITION_TEXTURED; }
public SmartTerrain() { enabled = true; alphaBlendEnable = false; //Shader //Effect = TgcShaders.loadEffect(GuiController.Instance.ExamplesDir + "TerrainEditor\\Shaders\\EditableTerrain.fx"); //Effect = TgcShaders.loadEffect(GuiController.Instance.AlumnoEjemplosMediaDir + "shader_agua.fx"); //Technique = "RenderAgua";//"PositionColoredTextured"; aabb = new TgcBoundingBox(); }
public LightData(TgcMeshData meshData) { this.color = parserColor(meshData.userProperties["color"]); this.aabb = new TgcBoundingBox(TgcParserUtils.float3ArrayToVector3(meshData.pMin), TgcParserUtils.float3ArrayToVector3(meshData.pMax)); this.pos = this.aabb.calculateBoxCenter(); this.spot = meshData.userProperties["esSpot"].Equals("SI"); this.direccion = convertirDireccion(meshData.userProperties["dir"]); this.intencidad = float.Parse(meshData.userProperties["inten"]); this.atenuacion = float.Parse(meshData.userProperties["atenua"])/10; this.angleCos = float.Parse(meshData.userProperties["angleCos"]); this.exp = float.Parse(meshData.userProperties["exp"]); }
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 Tree(Vector3 position, Vector3 scale, Vector3 rotation) : base(MESH_PATH, position, scale, rotation) { //Hago que el bounding box sólo cubra el tronco this.boundingBox = mesh.BoundingBox.clone(); Vector3 bBScale = new Vector3(0.09f * scale.X, 1f * scale.Y, 0.09f * scale.Z); this.boundingBox.scaleTranslate(position, bBScale); center = this.boundingBox.calculateBoxCenter(); radius = this.boundingBox.calculateBoxRadius(); }
/// <summary> /// Crear una nueva grilla /// </summary> /// <param name="modelos">Modelos a contemplar</param> /// <param name="sceneBounds">Límites del escenario</param> public void create(List<TgcMesh> modelos, TgcBoundingBox sceneBounds) { this.modelos = modelos; this.sceneBounds = sceneBounds; //build grid = buildGrid(modelos, sceneBounds, new Vector3(CELL_WIDTH, CELL_HEIGHT, CELL_LENGTH)); foreach (TgcMesh mesh in modelos) { mesh.Enabled = false; } }
/// <summary> /// Indica si un Plano colisiona con un BoundingBox /// </summary> /// <param name="plane">Plano</param> /// <param name="aabb">BoundingBox</param> /// <returns>True si hay colisión.</returns> public static bool testPlaneAABB(Plane plane, TgcBoundingBox aabb) { Vector3 c = (aabb.PMax + aabb.PMin) * 0.5f; // Compute AABB center Vector3 e = aabb.PMax - c; // Compute positive extents // Compute the projection interval radius of b onto L(t) = b.c + t * p.n float r = e.X * FastMath.Abs(plane.A) + e.Y * FastMath.Abs(plane.B) + e.Z * FastMath.Abs(plane.C); // Compute distance of box center from plane float s = plane.Dot(c); // Intersection occurs when distance s falls within [-r,+r] interval return(FastMath.Abs(s) <= r); }
public Barril(Vector3 position) { this.mesh = Barril.getMesh(); this.mesh.Position = position; this.mesh.Scale = new Vector3(0.6f, 0.7f, 0.6f); this.mesh.AlphaBlendEnable = true; cilindro = new TgcBoundingCylinder(position, 10, 150); this.mesh.updateBoundingBox(); BoundigBox = this.mesh.BoundingBox; explosion = new Explosion(position); humo = new Humo(this.mesh.Position); }
/// <summary> /// Crear nuevo Quadtree /// </summary> /// <param name="modelos">Modelos a optimizar</param> /// <param name="sceneBounds">Límites del escenario</param> public void create(List<TgcMesh> modelos, TgcBoundingBox sceneBounds) { this.modelos = modelos; this.sceneBounds = sceneBounds; //Crear Quadtree this.quadtreeRootNode = builder.crearQuadtree(modelos, sceneBounds); //Deshabilitar todos los mesh inicialmente foreach (TgcMesh mesh in modelos) { mesh.Enabled = false; } }
public TerrainPatch(DivisibleTerrain father, CustomVertex.PositionTextured[] data, TgcBoundingBox bb) { this.father = father; totalVertices = data.Length; this.BoundingBox = bb; this.vbTerrainPatch = new VertexBuffer(typeof(CustomVertex.PositionTextured), data.Length, GuiController.Instance.D3dDevice, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionTextured.Format, Pool.Default); this.Effect = father.Effect; this.Technique = father.Technique; this.Enabled = father.Enabled; this.RenderBB = false; vbTerrainPatch.SetData(data, 0, LockFlags.None); }
/// <summary> /// Crea una pared vacia. /// </summary> public TgcPlaneWall() { this.vertices = new CustomVertex.PositionTextured[6]; this.autoAdjustUv = false; this.enabled = true; this.boundingBox = new TgcBoundingBox(); this.uTile = 1; this.vTile = 1; this.alphaBlendEnable = false; this.uvOffset = new Vector2(0, 0); //Shader this.effect = GuiController.Instance.Shaders.VariosShader; this.technique = TgcShaders.T_POSITION_TEXTURED; }
public ManejadorColisiones(Camara camara, List<TgcBoundingBox> obstEscenario) { this.fpsCamara = camara; velSalto = 80.0f; gravedad = 80.0f; velocidad = new Vector3(); antCamPos = Vector3.Empty; time = 0; firstTime = true; jugadorPriPers = new TgcBoundingBox(new Vector3(-20, -60, -20), new Vector3(20, 20, 20)); obstaculos = obstEscenario; }
public override void Init() { //seteamos atributos particulares de las naves health = 50; score = 2; tiempoMuerte = 5f; Device d3dDevice = GuiController.Instance.D3dDevice; MESH_SCALE = 0.5f; attackDamage = 50; MOVEMENT_SPEED = 225f; //cargamos el mesh //las naves no tienen skeletalMesh this.mesh = GameManager.Instance.ModeloNave.clone("Nave"); SPAWN_HEIGHT = 1000f; giroInicial = Matrix.RotationY(0); //realizamos el init() comun a todos los enemigos base.Init(); mesh.Effect = GameManager.Instance.envMap; mesh.Technique = "SimpleEnvironmentMapTechnique"; mesh.Effect.SetValue("lightColor", ColorValue.FromColor(Color.White)); mesh.Effect.SetValue("lightPosition", TgcParserUtils.vector3ToFloat4Array(new Vector3(0,1400,0))); mesh.Effect.SetValue("eyePosition", TgcParserUtils.vector3ToFloat4Array(CustomFpsCamera.Instance.getPosition())); mesh.Effect.SetValue("lightIntensity", 0.3f); mesh.Effect.SetValue("lightAttenuation", 1.0f); mesh.Effect.SetValue("reflection", 0.65f); //Cargar variables de shader de Material. El Material en realidad deberia ser propio de cada mesh. Pero en este ejemplo se simplifica con uno comun para todos mesh.Effect.SetValue("materialEmissiveColor", ColorValue.FromColor(Color.Black)); mesh.Effect.SetValue("materialAmbientColor", ColorValue.FromColor(Color.White)); mesh.Effect.SetValue("materialDiffuseColor", ColorValue.FromColor(Color.White)); mesh.Effect.SetValue("materialSpecularColor", ColorValue.FromColor(Color.White)); mesh.Effect.SetValue("materialSpecularExp", 9); mesh.Effect.SetValue("texCubeMap", GameManager.Instance.cubeMap); //creamos las boundingbox //a pesar de que las naves no tienen legs ni head, le seteamos boxes "vacias" para no tener problemas con Excepciones de null HEADSHOT_BOUNDINGBOX = new TgcBoundingBox(); CHEST_BOUNDINGBOX = this.mesh.BoundingBox.clone(); LEGS_BOUNDINGBOX = new TgcBoundingBox(); //carga de sonido SonidoMovimiento = new Tgc3dSound(GuiController.Instance.AlumnoEjemplosMediaDir + "Los_Borbotones\\Audio\\Robot\\ufoHum.wav", getPosicionActual()); SonidoMovimiento.MinDistance = 130f; SonidoMovimiento.play(true); }
/// <summary> /// Crear nuevo manejador de colsiones /// </summary> public BspCollisionManager(BspMap bspMap) { this.bspMap = bspMap; this.camera = new Q3FpsCamera(); jumpSpeed = 80.0f; gravity = 80.0f; maxStepHeight = 40; noClip = false; velocidad = new Vector3(); antCamPos = Vector3.Empty; time = 0; firstTime = true; playerBB = new TgcBoundingBox(new Vector3(-20, -60, -20), new Vector3(20, 20, 20)); }
public List<TgcMesh> findMeshesToCollide(TgcBoundingBox objeto) { Vector3 pMax = sceneBounds.PMax; Vector3 pMin = sceneBounds.PMin; List<TgcMesh> meshes = new List<TgcMesh>(); collidedNodes = new List<QuadtreeNode>(); findNodesToCollide(objeto, quadtreeRootNode, pMin.X, pMin.Y, pMin.Z, pMax.X, pMax.Y, pMax.Z); foreach (QuadtreeNode node in collidedNodes) { meshes.AddRange(node.models); } return meshes; }
/// <summary> /// Clasifica un BoundingBox respecto del Frustum /// </summary> /// <param name="frustum">Frustum</param> /// <param name="aabb">BoundingBox</param> /// <returns>Resultado de la clasificación</returns> public static FrustumResult classifyFrustumAABB(TgcFrustum frustum, TgcBoundingBox aabb) { int totalIn = 0; Plane[] frustumPlanes = frustum.FrustumPlanes; // get the corners of the box into the vCorner array Vector3[] aabbCorners = aabb.computeCorners(); // test all 8 corners against the 6 sides // if all points are behind 1 specific plane, we are out // if we are in with all points, then we are fully in for (int p = 0; p < 6; ++p) { int inCount = 8; int ptIn = 1; for (int i = 0; i < 8; ++i) { // test this point against the planes if (classifyPointPlane(aabbCorners[i], frustumPlanes[p]) == PointPlaneResult.BEHIND) { ptIn = 0; --inCount; } } // were all the points outside of plane p? if (inCount == 0) { return(FrustumResult.OUTSIDE); } // check if they were all on the right side of the plane totalIn += ptIn; } // so if iTotalIn is 6, then all are inside the view if (totalIn == 6) { return(FrustumResult.INSIDE); } // we must be partly in then otherwise return(FrustumResult.INTERSECT); }
/// <summary> /// Indica si un BoundingBox colisiona con otro. /// Solo indica si hay colisión o no. No va mas en detalle. /// </summary> /// <param name="a">BoundingBox 1</param> /// <param name="b">BoundingBox 2</param> /// <returns>True si hay colisión</returns> public static bool testAABBAABB(TgcBoundingBox a, TgcBoundingBox b) { // Exit with no intersection if separated along an axis if (a.PMax.X < b.PMin.X || a.PMin.X > b.PMax.X) { return(false); } if (a.PMax.Y < b.PMin.Y || a.PMin.Y > b.PMax.Y) { return(false); } if (a.PMax.Z < b.PMin.Z || a.PMin.Z > b.PMax.Z) { return(false); } // Overlapping on all axes means AABBs are intersecting return(true); }
/// <summary> /// Indica si el segmento de recta compuesto por p0-p1 colisiona con el BoundingBox. /// </summary> /// <param name="p0">Punto inicial del segmento</param> /// <param name="p1">Punto final del segmento</param> /// <param name="aabb">BoundingBox</param> /// <param name="q">Punto de intersección</param> /// <returns>True si hay colisión</returns> public static bool intersectSegmentAABB(Vector3 p0, Vector3 p1, TgcBoundingBox aabb, out Vector3 q) { Vector3 segmentDir = p1 - p0; TgcRay ray = new TgcRay(p0, segmentDir); if (TgcCollisionUtils.intersectRayAABB(ray, aabb, out q)) { float segmentLengthSq = segmentDir.LengthSq(); Vector3 collisionDiff = q - p0; float collisionLengthSq = collisionDiff.LengthSq(); if (collisionLengthSq <= segmentLengthSq) { return(true); } } return(false); }
public KdTreeNode crearKdTree(List<TgcMesh> modelos, TgcBoundingBox sceneBounds) { KdTreeNode rootNode = new KdTreeNode(); //iniciar generacion recursiva de KdTree doSectorKdTreeX(rootNode, sceneBounds.PMin, sceneBounds.PMax, 0, modelos); //podar nodos innecesarios optimizeSectorKdTree(rootNode.children); //imprimir por consola el KdTree //printDebugKdTree(rootNode); //imprimir estadisticas de debug //printEstadisticasKdTree(rootNode); return rootNode; }
/// <summary> /// Transforma el BondingBox en base a una matriz de transformación. /// Esto implica escalar, rotar y trasladar. /// El procedimiento es mas costoso que solo hacer scaleTranslate(). /// Se construye un nuevo BoundingBox en base a los puntos extremos del original /// más la transformación pedida. /// Si el BoundingBox se transformó y luego se llama a scaleTranslate(), se respeta /// la traslación y la escala, pero la rotación se va a perder. /// </summary> /// <param name="transform"></param> public void transform(Matrix transform) { //Transformar vertices extremos originales Vector3[] corners = computeCorners(pMinOriginal, pMaxOriginal); Vector3[] newCorners = new Vector3[corners.Length]; for (int i = 0; i < corners.Length; i++) { newCorners[i] = TgcVectorUtils.transform(corners[i], transform); } //Calcular nuevo BoundingBox en base a extremos transformados TgcBoundingBox newBB = TgcBoundingBox.computeFromPoints(newCorners); //actualizar solo pMin y pMax, pMinOriginal y pMaxOriginal quedan sin ser transformados pMin = newBB.pMin; pMax = newBB.pMax; dirtyValues = true; }
/// <summary> /// Crea el terreno /// </summary> public TgcEditableLand() { Device d3dDevice = GuiController.Instance.D3dDevice; //16 caras, 32 triangulos, 96 vertices vertices = new CustomVertex.PositionTextured[96]; vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionTextured), vertices.Length, d3dDevice, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionTextured.Format, Pool.Default); //Crear los 25 vertices editables, formando una grilla de 5x5 vertices editableVertices = new EditableVertex[25]; float uvStep = 1f / 4f; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { EditableVertex v = new EditableVertex(); v.Pos = new Vector3(j * PATCH_SIZE, 0, i * PATCH_SIZE); v.UV = new Vector2(j * uvStep, i * uvStep); editableVertices[i * 5 + j] = v; } } this.autoTransformEnable = true; this.transform = Matrix.Identity; this.translation = new Vector3(0, 0, 0); this.rotation = new Vector3(0, 0, 0); this.scale = new Vector3(1, 1, 1); this.enabled = true; this.alphaBlendEnable = false; this.uvOffset = new Vector2(0, 0); this.uvTiling = new Vector2(1, 1); //BoundingBox boundingBox = new TgcBoundingBox(); updateBoundingBox(); //Shader this.effect = GuiController.Instance.Shaders.VariosShader; this.technique = TgcShaders.T_POSITION_TEXTURED; }
/// <summary> /// Clasifica un BoundingBox respecto de otro. Las opciones de clasificacion son: /// <para># Adentro: box1 se encuentra completamente dentro de la box2</para> /// <para># Afuera: box2 se encuentra completamente afuera de box1</para> /// <para># Atravesando: box2 posee una parte dentro de box1 y otra parte fuera de la box1</para> /// <para># Encerrando: box1 esta completamente adentro a la box1, es decir, la box1 se encuentra dentro /// de la box2. Es un caso especial de que box2 esté afuera de box1</para> /// </summary> public static BoxBoxResult classifyBoxBox(TgcBoundingBox box1, TgcBoundingBox box2) { if (((box1.PMin.X <= box2.PMin.X && box1.PMax.X >= box2.PMax.X) || (box1.PMin.X >= box2.PMin.X && box1.PMin.X <= box2.PMax.X) || (box1.PMax.X >= box2.PMin.X && box1.PMax.X <= box2.PMax.X)) && ((box1.PMin.Y <= box2.PMin.Y && box1.PMax.Y >= box2.PMax.Y) || (box1.PMin.Y >= box2.PMin.Y && box1.PMin.Y <= box2.PMax.Y) || (box1.PMax.Y >= box2.PMin.Y && box1.PMax.Y <= box2.PMax.Y)) && ((box1.PMin.Z <= box2.PMin.Z && box1.PMax.Z >= box2.PMax.Z) || (box1.PMin.Z >= box2.PMin.Z && box1.PMin.Z <= box2.PMax.Z) || (box1.PMax.Z >= box2.PMin.Z && box1.PMax.Z <= box2.PMax.Z))) { if ((box1.PMin.X <= box2.PMin.X) && (box1.PMin.Y <= box2.PMin.Y) && (box1.PMin.Z <= box2.PMin.Z) && (box1.PMax.X >= box2.PMax.X) && (box1.PMax.Y >= box2.PMax.Y) && (box1.PMax.Z >= box2.PMax.Z)) { return BoxBoxResult.Adentro; } else if ((box1.PMin.X > box2.PMin.X) && (box1.PMin.Y > box2.PMin.Y) && (box1.PMin.Z > box2.PMin.Z) && (box1.PMax.X < box2.PMax.X) && (box1.PMax.Y < box2.PMax.Y) && (box1.PMax.Z < box2.PMax.Z)) { return BoxBoxResult.Encerrando; } else { return BoxBoxResult.Atravesando; } } else { return BoxBoxResult.Afuera; } }
/// <summary> /// Clasifica un BoundingBox respecto de otro. Las opciones de clasificacion son: /// <para># Adentro: box1 se encuentra completamente dentro de la box2</para> /// <para># Afuera: box2 se encuentra completamente afuera de box1</para> /// <para># Atravesando: box2 posee una parte dentro de box1 y otra parte fuera de la box1</para> /// <para># Encerrando: box1 esta completamente adentro a la box1, es decir, la box1 se encuentra dentro /// de la box2. Es un caso especial de que box2 esté afuera de box1</para> /// </summary> public static BoxBoxResult classifyBoxBox(TgcBoundingBox box1, TgcBoundingBox box2) { if (((box1.PMin.X <= box2.PMin.X && box1.PMax.X >= box2.PMax.X) || (box1.PMin.X >= box2.PMin.X && box1.PMin.X <= box2.PMax.X) || (box1.PMax.X >= box2.PMin.X && box1.PMax.X <= box2.PMax.X)) && ((box1.PMin.Y <= box2.PMin.Y && box1.PMax.Y >= box2.PMax.Y) || (box1.PMin.Y >= box2.PMin.Y && box1.PMin.Y <= box2.PMax.Y) || (box1.PMax.Y >= box2.PMin.Y && box1.PMax.Y <= box2.PMax.Y)) && ((box1.PMin.Z <= box2.PMin.Z && box1.PMax.Z >= box2.PMax.Z) || (box1.PMin.Z >= box2.PMin.Z && box1.PMin.Z <= box2.PMax.Z) || (box1.PMax.Z >= box2.PMin.Z && box1.PMax.Z <= box2.PMax.Z))) { if ((box1.PMin.X <= box2.PMin.X) && (box1.PMin.Y <= box2.PMin.Y) && (box1.PMin.Z <= box2.PMin.Z) && (box1.PMax.X >= box2.PMax.X) && (box1.PMax.Y >= box2.PMax.Y) && (box1.PMax.Z >= box2.PMax.Z)) { return(BoxBoxResult.Adentro); } else if ((box1.PMin.X > box2.PMin.X) && (box1.PMin.Y > box2.PMin.Y) && (box1.PMin.Z > box2.PMin.Z) && (box1.PMax.X < box2.PMax.X) && (box1.PMax.Y < box2.PMax.Y) && (box1.PMax.Z < box2.PMax.Z)) { return(BoxBoxResult.Encerrando); } else { return(BoxBoxResult.Atravesando); } } else { return(BoxBoxResult.Afuera); } }
public QuadtreeNode crearQuadtree(List<TgcMesh> TgcMeshs, TgcBoundingBox sceneBounds) { QuadtreeNode rootNode = new QuadtreeNode(); //Calcular punto medio y centro Vector3 midSize = sceneBounds.calculateAxisRadius(); Vector3 center = sceneBounds.calculateBoxCenter(); //iniciar generacion recursiva de octree doSectorQuadtreeX(rootNode, center, midSize, 0, TgcMeshs); //podar nodos innecesarios optimizeSectorQuadtree(rootNode.children); //imprimir por consola el octree //printDebugQuadtree(rootNode); //imprimir estadisticas de debug //printEstadisticasQuadtree(rootNode); return rootNode; }
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> /// Calcula la mínima distancia al cuadrado entre el punto p y el BoundingBox. /// Si no se necesita saber el punto exacto de colisión es más ágil que utilizar closestPointAABB(). /// </summary> /// <param name="p">Punto a testear</param> /// <param name="aabb">BoundingBox</param> /// <returns>Mínima distacia al cuadrado</returns> public static float sqDistPointAABB(Vector3 p, TgcBoundingBox aabb) { float[] aabbMin = toArray(aabb.PMin); float[] aabbMax = toArray(aabb.PMax); float[] pArray = toArray(p); float sqDist = 0.0f; for (int i = 0; i < 3; i++) { // For each axis count any excess distance outside box extents float v = pArray[i]; if (v < aabbMin[i]) { sqDist += (aabbMin[i] - v) * (aabbMin[i] - v); } if (v > aabbMax[i]) { sqDist += (v - aabbMax[i]) * (v - aabbMax[i]); } } return(sqDist); }
/// <summary> /// Construye la grilla /// </summary> private GrillaRegularNode[, ,] buildGrid(List<TgcMesh> modelos, TgcBoundingBox sceneBounds, Vector3 cellDim) { Vector3 sceneSize = sceneBounds.calculateSize(); int gx = (int)FastMath.Ceiling(sceneSize.X / cellDim.X) + 1; int gy = (int)FastMath.Ceiling(sceneSize.Y / cellDim.Y) + 1; int gz = (int)FastMath.Ceiling(sceneSize.Z / cellDim.Z) + 1; GrillaRegularNode[, ,] grid = new GrillaRegularNode[gx, gy, gz]; //Construir grilla for (int x = 0; x < gx; x++) { for (int y = 0; y < gy; y++) { for (int z = 0; z < gz; z++) { //Crear celda GrillaRegularNode node = new GrillaRegularNode(); //Crear BoundingBox de celda Vector3 pMin = new Vector3(sceneBounds.PMin.X + x * cellDim.X, sceneBounds.PMin.Y + y * cellDim.Y, sceneBounds.PMin.Z + z * cellDim.Z); Vector3 pMax = Vector3.Add(pMin, cellDim); node.BoundingBox = new TgcBoundingBox(pMin, pMax); //Cargar modelos en celda node.Models = new List<TgcMesh>(); addModelsToCell(node, modelos); grid[x, y, z] = node; } } } return grid; }
/// <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)); }
/// <summary> /// Hacer visible las meshes de un nodo si es visible por el Frustum /// </summary> private void testChildVisibility(TgcFrustum frustum, QuadtreeNode childNode, float boxLowerX, float boxLowerY, float boxLowerZ, float boxUpperX, float boxUpperY, float boxUpperZ) { //test frustum-box intersection TgcBoundingBox caja = new TgcBoundingBox( new Vector3(boxLowerX, boxLowerY, boxLowerZ), new Vector3(boxUpperX, boxUpperY, boxUpperZ)); TgcCollisionUtils.FrustumResult c = TgcCollisionUtils.classifyFrustumAABB(frustum, caja); //complementamente adentro: cargar todos los hijos directamente, sin testeos if (c == TgcCollisionUtils.FrustumResult.INSIDE) { addAllLeafMeshes(childNode); } //parte adentro: seguir haciendo testeos con hijos else if (c == TgcCollisionUtils.FrustumResult.INTERSECT) { findVisibleMeshes(frustum, childNode, boxLowerX, boxLowerY, boxLowerZ, boxUpperX, boxUpperY, boxUpperZ); } }
/// <summary> /// Calcular OBB a partir de un conjunto de puntos. /// Prueba todas las orientaciones entre initValues y endValues, saltando de angulo en cada intervalo segun step /// Continua recursivamente hasta llegar a un step menor a 0.01f /// </summary> /// <returns></returns> private static OBBStruct computeFromPointsRecursive(Vector3[] points, Vector3 initValues, Vector3 endValues, float step) { OBBStruct minObb = new OBBStruct(); float minVolume = float.MaxValue; Vector3 minInitValues = Vector3.Empty; Vector3 minEndValues = Vector3.Empty; Vector3[] transformedPoints = new Vector3[points.Length]; float x, y, z; x = initValues.X; while (x <= endValues.X) { y = initValues.Y; float rotX = FastMath.ToRad(x); while (y <= endValues.Y) { z = initValues.Z; float rotY = FastMath.ToRad(y); while (z <= endValues.Z) { //Matriz de rotacion float rotZ = FastMath.ToRad(z); Matrix rotM = Matrix.RotationYawPitchRoll(rotY, rotX, rotZ); Vector3[] orientation = new Vector3[] { new Vector3(rotM.M11, rotM.M12, rotM.M13), new Vector3(rotM.M21, rotM.M22, rotM.M23), new Vector3(rotM.M31, rotM.M32, rotM.M33) }; //Transformar todos los puntos a OBB-space for (int i = 0; i < transformedPoints.Length; i++) { transformedPoints[i].X = Vector3.Dot(points[i], orientation[0]); transformedPoints[i].Y = Vector3.Dot(points[i], orientation[1]); transformedPoints[i].Z = Vector3.Dot(points[i], orientation[2]); } //Obtener el AABB de todos los puntos transformados TgcBoundingBox aabb = TgcBoundingBox.computeFromPoints(transformedPoints); //Calcular volumen del AABB Vector3 extents = aabb.calculateAxisRadius(); extents = TgcVectorUtils.abs(extents); float volume = extents.X * 2 * extents.Y * 2 * extents.Z * 2; //Buscar menor volumen if (volume < minVolume) { minVolume = volume; minInitValues = new Vector3(x, y, z); minEndValues = new Vector3(x + step, y + step, z + step); //Volver centro del AABB a World-space Vector3 center = aabb.calculateBoxCenter(); center = center.X * orientation[0] + center.Y * orientation[1] + center.Z * orientation[2]; //Crear OBB minObb.center = center; minObb.extents = extents; minObb.orientation = orientation; } z += step; } y += step; } x += step; } //Recursividad en mejor intervalo encontrado if (step > 0.01f) { minObb = computeFromPointsRecursive(points, minInitValues, minEndValues, step / 10f); } return(minObb); }
/// <summary> /// Indica si un Ray colisiona con un AABB. /// Si hay intersección devuelve True, q contiene /// el punto de intesección. /// Basado en el código de: http://www.codercorner.com/RayAABB.cpp /// La dirección del Ray puede estar sin normalizar. /// </summary> /// <param name="ray">Ray</param> /// <param name="a">AABB</param> /// <param name="q">Punto de intersección</param> /// <returns>True si hay colisión</returns> public static bool intersectRayAABB(TgcRay ray, TgcBoundingBox aabb, out Vector3 q) { q = Vector3.Empty; bool inside = true; float[] aabbMin = toArray(aabb.PMin); float[] aabbMax = toArray(aabb.PMax); float[] rayOrigin = toArray(ray.Origin); float[] rayDir = toArray(ray.Direction); float[] max_t = new float[3] { -1.0f, -1.0f, -1.0f }; float[] coord = new float[3]; for (uint i = 0; i < 3; ++i) { if (rayOrigin[i] < aabbMin[i]) { inside = false; coord[i] = aabbMin[i]; if (rayDir[i] != 0.0f) { max_t[i] = (aabbMin[i] - rayOrigin[i]) / rayDir[i]; } } else if (rayOrigin[i] > aabbMax[i]) { inside = false; coord[i] = aabbMax[i]; if (rayDir[i] != 0.0f) { max_t[i] = (aabbMax[i] - rayOrigin[i]) / rayDir[i]; } } } // If the Ray's start position is inside the Box, we can return true straight away. if (inside) { q = toVector3(rayOrigin); return(true); } uint plane = 0; if (max_t[1] > max_t[plane]) { plane = 1; } if (max_t[2] > max_t[plane]) { plane = 2; } if (max_t[plane] < 0.0f) { return(false); } for (uint i = 0; i < 3; ++i) { if (plane != i) { coord[i] = rayOrigin[i] + max_t[plane] * rayDir[i]; if (coord[i] < aabbMin[i] - float.Epsilon || coord[i] > aabbMax[i] + float.Epsilon) { return(false); } } } q = toVector3(coord); return(true); }
/// <summary> /// Generar OBB a partir de AABB /// </summary> /// <param name="aabb">BoundingBox</param> /// <returns>OBB generado</returns> public static TgcObb computeFromAABB(TgcBoundingBox aabb) { return(TgcObb.computeFromAABB(aabb.toStruct()).toClass()); }