/// <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) { var minObb = new OBBStruct(); var minVolume = float.MaxValue; var minInitValues = Vector3.Empty; var minEndValues = Vector3.Empty; var transformedPoints = new Vector3[points.Length]; float x, y, z; x = initValues.X; while (x <= endValues.X) { y = initValues.Y; var rotX = FastMath.ToRad(x); while (y <= endValues.Y) { z = initValues.Z; var rotY = FastMath.ToRad(y); while (z <= endValues.Z) { //Matriz de rotacion var rotZ = FastMath.ToRad(z); var rotM = Matrix.RotationYawPitchRoll(rotY, rotX, rotZ); Vector3[] orientation = { 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 (var 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 var aabb = TgcBoundingAxisAlignBox.computeFromPoints(transformedPoints); //Calcular volumen del AABB var extents = aabb.calculateAxisRadius(); extents = TgcVectorUtils.abs(extents); var 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 var 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); }
public void Init() { // Inicializo las Escalas SceneScaleY = 3 * 40f; SceneScaleXZ = 30 * 400f; //Cargar Heightmap y textura de la Escena HeightmapSize = new Bitmap(sceneHeightmapPath); terrainCenter = new Vector3(0, 0, 0); terrain = new TerrenoCustom(); terrain.AlphaBlendEnable = true; terrain.loadHeightmap(sceneHeightmapPath, SceneScaleXZ, SceneScaleY, terrainCenter); terrain.loadTexture(terrainTexturePath); // Creo el agua effectAgua = TgcShaders.loadEffect(env.ShadersDir + "BasicShader.fx"); mar = new TerrenoCustom(); mar.AlphaBlendEnable = true; mar.loadHeightmap(marHeightmapPath, 9 * SceneScaleXZ, 2 * SceneScaleY, new Vector3(0, -200, 0)); mar.loadTexture(marTexturePath); mar.Effect = effectAgua; mar.Technique = "RenderScene"; laguna = new TerrenoCustom(); laguna.AlphaBlendEnable = true; laguna.loadHeightmap(lagunaHeightmapPath, SceneScaleXZ / 4, SceneScaleY / 2, new Vector3(10, 10, 40)); laguna.loadTexture(lagunaTexturePath); laguna.Effect = effectAgua; laguna.Technique = "RenderLaguna"; // Creo el SkyBox CreateSkyBox(); // La ubicacion de los Mesh es en coordenadas Originales del HeightMap (sin escalado) [-128,128] SceneMeshes = new List <TgcMesh>(); Destroyables = new List <ObjetoEscena>(); loader = new TgcSceneLoader(); rockModel = new Roca(env); //CreateObjectsFromModel(rockModel.mesh, 100, new Vector3(0, 0, 0), new Vector3(0.9f, 0.9f, 0.9f), (HeightmapSize.Width / 3), new float[] { 30f, 35f, 40f, 45f }); CreateObjectsFromModel(rockModel.mesh, 300, new Vector3(0, 0, 0), new Vector3(0.9f, 1.3f, 1.7f), (HeightmapSize.Width / 2) - 10, new float[] { 30f, 35f, 40f, 45f }); palmModel = new Palmera(env); //CreateObjectsFromModel(palmModel.mesh, 50, new Vector3((HeightmapSize.Width / 5)*-1, 0, 0), new Vector3(0.5f, 0.5f, 0.5f), (HeightmapSize.Width / 3), new float[] { 60f, 65f, 70f, 75f }); //CreateObjectsFromModel(palmModel.mesh, 50, new Vector3((HeightmapSize.Width / 6), 0, (HeightmapSize.Width / 6)), new Vector3(0.5f, 0.5f, 0.5f), (HeightmapSize.Width / 6) * 2, new float[] { 60f, 65f, 70f, 75f }); CreateObjectsFromModel(palmModel.mesh, 300, new Vector3(0, 0, 0), new Vector3(0.5f, 0.7f, 0.9f), (HeightmapSize.Width / 2) - 10, new float[] { 60f, 65f, 70f, 75f }); //arbolModel = new Arbol(env); //CreateObjectsFromModel(arbolModel.mesh, 30, new Vector3(10, 0, 10), new Vector3(0.8f, 0.8f, 0.8f), 20, new float[] { 50f, 55f, 60f, 65f }); frutaModel = new Fruta(env); CreateObjectsFromModel(frutaModel.mesh, 150, new Vector3(0, 0, 0), new Vector3(0.8f, 0.8f, 0.8f), (HeightmapSize.Width / 2) - 10, new float[] { 2f, 2f, 2f, 2f }); pinoModel = new Pino(env); //CreateObjectsFromModel(pinoModel.mesh, 100, new Vector3((HeightmapSize.Width / 4), 0, 0), new Vector3(0.8f, 0.8f, 0.8f), (HeightmapSize.Width / 4)-10, new float[] { 50, 55f, 60f, 65f }); //CreateObjectsFromModel(pinoModel.mesh, 100, new Vector3(0, 0, (HeightmapSize.Width / 4)), new Vector3(0.8f, 0.8f, 0.8f), (HeightmapSize.Width / 4)-10, new float[] { 50, 55f, 60f, 65f }); CreateObjectsFromModel(pinoModel.mesh, 100, new Vector3(0, 0, 0), new Vector3(0.8f, 0.9f, 1.1f), (HeightmapSize.Width / 2) - 10, new float[] { 50, 55f, 60f, 65f }); //plantModel = loader.loadSceneFromFile(plantMeshPath).Meshes[0]; //CreateObjectsFromModel(plantModel, 70, new Vector3(75, 0, -75), new Vector3(0.8f, 0.8f, 0.8f), 75, new float[] { 50f, 55f, 60f, 65f }); //palm2Model = loader.loadSceneFromFile(palm2MeshPath).Meshes[0]; //CreateObjectsFromModel(palm2Model, 70, new Vector3(-20, 0, -50), new Vector3(0.8f, 0.8f, 0.8f), 80, new float[] { 10f, 15f, 20f, 25f }); //arbolFrutalModel = loader.loadSceneFromFile(arbolFrutalMeshPath).Meshes[0]; //CreateObjectsFromModel(arbolFrutalModel, 30, new Vector3(-75, 0, 75), new Vector3(0.8f, 0.8f, 0.8f), 50, new float[] { 50, 55f, 60f, 65f }); //palm3Model = loader.loadSceneFromFile(palm3MeshPath).Meshes[0]; //CreateObjectsFromModel(palm3Model, 70, new Vector3(-10, 0, -60), new Vector3(0.8f, 0.8f, 0.8f), 80, new float[] { 10f, 15f, 20f, 25f }); var fogataModel = loader.loadSceneFromFile(fogataPath); fogata = fogataModel.Meshes[0]; fogata.AutoTransformEnable = true; fogata.Scale = new Vector3(30f, 30f, 30f); fogata.Position = new Vector3(0, 0, 0); fogata.AlphaBlendEnable = true; fogata.Enabled = true; // Inicializo el Fuego emisorFuego = new ParticleEmitter(env.MediaDir + "Fogata2\\fuego.png", 30); emisorFuego.Position = new Vector3(0, 0, 0); emisorFuego.MinSizeParticle = 5.5f; emisorFuego.MaxSizeParticle = 10f; emisorFuego.ParticleTimeToLive = 1.5f; emisorFuego.CreationFrecuency = 0.25f; emisorFuego.Dispersion = 50; emisorFuego.Speed = new Vector3(50f, 50f * SceneScaleY, 50f); //Crear Quadtree: Defino el BoundinBox del Escenario triangle = new CustomVertex.PositionColored[5]; triangle[0] = new CustomVertex.PositionColored((HeightmapSize.Width / 2) * -1 * SceneScaleXZ, 0, 0, Color.Green.ToArgb()); triangle[1] = new CustomVertex.PositionColored(0, 0, (HeightmapSize.Width / 2) * SceneScaleXZ, Color.Green.ToArgb()); triangle[2] = new CustomVertex.PositionColored(0, (HeightmapSize.Width) * SceneScaleY, 0, Color.Green.ToArgb()); triangle[3] = new CustomVertex.PositionColored((HeightmapSize.Width / 2) * SceneScaleXZ, 0, 0, Color.Green.ToArgb()); triangle[4] = new CustomVertex.PositionColored(0, 0, (HeightmapSize.Width / 2) * -1 * SceneScaleXZ, Color.Green.ToArgb()); terrainBoundingBox = TgcBoundingAxisAlignBox.computeFromPoints(new[] { triangle[0].Position, triangle[1].Position, triangle[2].Position, triangle[3].Position, triangle[4].Position }); quadtree = new Quadtree(); quadtree.create(SceneMeshes, terrainBoundingBox); quadtree.createDebugQuadtreeMeshes(); }