public TgcPortalRenderingConnection(TgcPortalRenderingPortal portal, TgcPortalRenderingCell nextCell, TgcConvexPolygon polygon, Plane plane) { this.portal = portal; this.nextCell = nextCell; this.polygon = polygon; this.plane = plane; }
/// <summary> /// Habilitar los modelos visibles de esta celda, según el Frustum restringido /// </summary> private void findVisibleMeshes(TgcPortalRenderingCell cell, Plane[] currentFrustumPlanes) { //El Frustum puede tener más de 6 planos, asi que lo tratamos como un cuerpo convexo general. frustumConvexPolyhedon.Planes = currentFrustumPlanes; foreach (TgcMesh mesh in cell.Meshes) { if (mesh.Enabled == false) { if (TgcCollisionUtils.classifyConvexPolyhedronAABB(frustumConvexPolyhedon, mesh.BoundingBox) != TgcCollisionUtils.ConvexPolyhedronResult.OUTSIDE) { mesh.Enabled = true; } } } }
/// <summary> /// Actualiza la visibilidad de todos los modelos de las celdas. /// Las modelos visibles se cargan como Enable = true, mientras que el /// resto se deshabilita. /// </summary> /// <param name="cameraPos">Posición de la cámara</param> public void updateVisibility(Vector3 cameraPos) { //Armar Frustum para uso internor, en base al Frustum actual TgcFrustum frustum = GuiController.Instance.Frustum; Plane[] currentFrustumPlanes = new Plane[6]; currentFrustumPlanes = new Plane[6]; currentFrustumPlanes[0] = frustum.NearPlane; currentFrustumPlanes[1] = frustum.FarPlane; currentFrustumPlanes[2] = frustum.LeftPlane; currentFrustumPlanes[3] = frustum.RightPlane; currentFrustumPlanes[4] = frustum.BottomPlane; currentFrustumPlanes[5] = frustum.TopPlane; //Deshabilitar todas las celdas foreach (TgcPortalRenderingCell cell in cells) { cell.Visited = false; foreach (TgcPortalRenderingConnection connection in cell.Connections) { connection.Portal.Visited = false; } } //Buscar la celda actual en la que se encuentra la cámara TgcPortalRenderingCell currentCell = findCellFromPoint(cameraPos); if (currentCell == null) { return; } //Recorrer grafo de celdas desde la celda actual currentCell.Visited = true; traverseCellGraph(cameraPos, currentFrustumPlanes, currentCell); }
/// <summary> /// Cargar información de PortalRendering /// </summary> public TgcPortalRenderingManager loadFromData(TgcScene scene, TgcPortalRenderingData portalRenderingData) { TgcPortalRenderingManager manager = new TgcPortalRenderingManager(scene); //Crear dictionary de nombres de los meshes Dictionary<string, TgcMesh> meshDictionary = new Dictionary<string, TgcMesh>(); foreach (TgcMesh mesh in scene.Meshes) { meshDictionary.Add(mesh.Name, mesh); } //Cargar celdas foreach (TgcPortalRenderingCellData cellData in portalRenderingData.cells) { //Crear cuerpo Convexo TgcConvexPolyhedron convexPoly = new TgcConvexPolyhedron(); convexPoly.Planes = new Plane[cellData.facePlanes.Length / 4]; for (int i = 0; i < convexPoly.Planes.Length; i++) { convexPoly.Planes[i] = new Plane( cellData.facePlanes[i * 4], cellData.facePlanes[i * 4 + 1], cellData.facePlanes[i * 4 + 2], cellData.facePlanes[i * 4 + 3] ); } convexPoly.BoundingVertices = new Vector3[cellData.boundingVertices.Length / 3]; for (int i = 0; i < convexPoly.BoundingVertices.Length; i++) { convexPoly.BoundingVertices[i] = new Vector3( cellData.boundingVertices[i * 3], cellData.boundingVertices[i * 3 + 1], cellData.boundingVertices[i * 3 + 2] ); } //Crear celda TgcPortalRenderingCell cell = new TgcPortalRenderingCell(cellData.name, convexPoly); manager.Cells.Add(cell); //Cargar meshes en celda for (int i = 0; i < cellData.meshes.Length; i++) { TgcMesh mesh = meshDictionary[cellData.meshes[i]]; cell.Meshes.Add(mesh); } } //Cargar portales foreach (TgcPortalRenderingPortalData portalData in portalRenderingData.portals) { //BoundingBox del portal TgcBoundingBox boundingBox = new TgcBoundingBox( new Vector3(portalData.pMin[0], portalData.pMin[1], portalData.pMin[2]), new Vector3(portalData.pMax[0], portalData.pMax[1], portalData.pMax[2]) ); //Crear portal TgcPortalRenderingPortal portal = new TgcPortalRenderingPortal(portalData.name, boundingBox); manager.Portals.Add(portal); //Cargar conexiones para celdas A y B TgcPortalRenderingCell cellA = manager.Cells[portalData.cellA]; TgcPortalRenderingCell cellB = manager.Cells[portalData.cellB]; //Poligono del portal para la celda A TgcConvexPolygon polygonA = new TgcConvexPolygon(); polygonA.BoundingVertices = new Vector3[portalData.boundingVerticesA.Length / 3]; for (int i = 0; i < polygonA.BoundingVertices.Length; i++) { polygonA.BoundingVertices[i] = new Vector3( portalData.boundingVerticesA[i * 3], portalData.boundingVerticesA[i * 3 + 1], portalData.boundingVerticesA[i * 3 + 2] ); } //Plano del portal para la celda A Plane planeA = TgcParserUtils.float4ArrayToPlane(portalData.planeA); //Crear conexion A TgcPortalRenderingConnection connectionA = new TgcPortalRenderingConnection(portal, cellB, polygonA, planeA); cellA.Connections.Add(connectionA); //Poligono del portal para la celda B TgcConvexPolygon polygonB = new TgcConvexPolygon(); polygonB.BoundingVertices = new Vector3[portalData.boundingVerticesB.Length / 3]; for (int i = 0; i < polygonB.BoundingVertices.Length; i++) { polygonB.BoundingVertices[i] = new Vector3( portalData.boundingVerticesB[i * 3], portalData.boundingVerticesB[i * 3 + 1], portalData.boundingVerticesB[i * 3 + 2] ); } //Plano del portal para la celda B Plane planeB = TgcParserUtils.float4ArrayToPlane(portalData.planeB); //Crear conexion B TgcPortalRenderingConnection connectionB = new TgcPortalRenderingConnection(portal, cellA, polygonB, planeB); cellB.Connections.Add(connectionB); } return manager; }
/// <summary> /// Recorrer el grafo de celdas y portales /// </summary> private void traverseCellGraph(Vector3 cameraPos, Plane[] currentFrustumPlanes, TgcPortalRenderingCell cell) { //Habilitar modelos visibles de esta celda findVisibleMeshes(cell, currentFrustumPlanes); //Recorrer todas la conexiones de esta celda foreach (TgcPortalRenderingConnection connection in cell.Connections) { //Si el portal ya fue visitado, ignorar //TODO: Hay una configuración extrema de celdas y portales que no es tenida en cuenta con este atajo. Analizar en más detalle. if (connection.Portal.Visited) { continue; } //TODO: quizás convendria hacer un test Frustum-BoundingSphere del Portal para descartar más rápido los que no se ven //Hacer clipping entre el Frustum y el polígono del portal Vector3[] clippedPortalVerts = doPortalClipping(currentFrustumPlanes, connection.Polygon); //Si quedó algún remanente luego de hacer clipping, avanzar hacia esa celda if (clippedPortalVerts != null) { //Crear nuevo Frustum recortado por el portal Plane[] clippedFrustumPlanes = createFrustumPlanes(cameraPos, currentFrustumPlanes, clippedPortalVerts, connection.Plane); //Avanzar sobre la celda que conecta este portal, utilizando el Frustum recortado connection.NextCell.Visited = true; connection.Portal.Visited = true; traverseCellGraph(cameraPos, clippedFrustumPlanes, connection.NextCell); } } }
/// <summary> /// Habilitar los modelos visibles de esta celda, según el Frustum restringido /// </summary> private void findVisibleMeshes(TgcPortalRenderingCell cell, Plane[] currentFrustumPlanes) { //El Frustum puede tener más de 6 planos, asi que lo tratamos como un cuerpo convexo general. frustumConvexPolyhedon.Planes = currentFrustumPlanes; foreach (TgcMesh mesh in cell.Meshes) { if(mesh.Enabled == false) { if (TgcCollisionUtils.classifyConvexPolyhedronAABB(frustumConvexPolyhedon, mesh.BoundingBox) != TgcCollisionUtils.ConvexPolyhedronResult.OUTSIDE) { mesh.Enabled = true; } } } }
/// <summary> /// Recorrer el grafo de celdas y portales /// </summary> private void traverseCellGraph(Vector3 cameraPos, Plane[] currentFrustumPlanes, TgcPortalRenderingCell cell) { //Habilitar modelos visibles de esta celda findVisibleMeshes(cell, currentFrustumPlanes); //Recorrer todas la conexiones de esta celda foreach (TgcPortalRenderingConnection connection in cell.Connections) { //Si el portal ya fue visitado, ignorar //TODO: Hay una configuración extrema de celdas y portales que no es tenida en cuenta con este atajo. Analizar en más detalle. if (connection.Portal.Visited) continue; //TODO: quizás convendria hacer un test Frustum-BoundingSphere del Portal para descartar más rápido los que no se ven //Hacer clipping entre el Frustum y el polígono del portal Vector3[] clippedPortalVerts = doPortalClipping(currentFrustumPlanes, connection.Polygon); //Si quedó algún remanente luego de hacer clipping, avanzar hacia esa celda if (clippedPortalVerts != null) { //Crear nuevo Frustum recortado por el portal Plane[] clippedFrustumPlanes = createFrustumPlanes(cameraPos, currentFrustumPlanes, clippedPortalVerts, connection.Plane); //Avanzar sobre la celda que conecta este portal, utilizando el Frustum recortado connection.NextCell.Visited = true; connection.Portal.Visited = true; traverseCellGraph(cameraPos, clippedFrustumPlanes, connection.NextCell); } } }
/// <summary> /// Cargar información de PortalRendering /// </summary> public TgcPortalRenderingManager loadFromData(TgcScene scene, TgcPortalRenderingData portalRenderingData) { TgcPortalRenderingManager manager = new TgcPortalRenderingManager(scene); //Crear dictionary de nombres de los meshes Dictionary <string, TgcMesh> meshDictionary = new Dictionary <string, TgcMesh>(); foreach (TgcMesh mesh in scene.Meshes) { meshDictionary.Add(mesh.Name, mesh); } //Cargar celdas foreach (TgcPortalRenderingCellData cellData in portalRenderingData.cells) { //Crear cuerpo Convexo TgcConvexPolyhedron convexPoly = new TgcConvexPolyhedron(); convexPoly.Planes = new Plane[cellData.facePlanes.Length / 4]; for (int i = 0; i < convexPoly.Planes.Length; i++) { convexPoly.Planes[i] = new Plane( cellData.facePlanes[i * 4], cellData.facePlanes[i * 4 + 1], cellData.facePlanes[i * 4 + 2], cellData.facePlanes[i * 4 + 3] ); } convexPoly.BoundingVertices = new Vector3[cellData.boundingVertices.Length / 3]; for (int i = 0; i < convexPoly.BoundingVertices.Length; i++) { convexPoly.BoundingVertices[i] = new Vector3( cellData.boundingVertices[i * 3], cellData.boundingVertices[i * 3 + 1], cellData.boundingVertices[i * 3 + 2] ); } //Crear celda TgcPortalRenderingCell cell = new TgcPortalRenderingCell(cellData.name, convexPoly); manager.Cells.Add(cell); //Cargar meshes en celda for (int i = 0; i < cellData.meshes.Length; i++) { TgcMesh mesh = meshDictionary[cellData.meshes[i]]; cell.Meshes.Add(mesh); } } //Cargar portales foreach (TgcPortalRenderingPortalData portalData in portalRenderingData.portals) { //BoundingBox del portal TgcBoundingBox boundingBox = new TgcBoundingBox( new Vector3(portalData.pMin[0], portalData.pMin[1], portalData.pMin[2]), new Vector3(portalData.pMax[0], portalData.pMax[1], portalData.pMax[2]) ); //Crear portal TgcPortalRenderingPortal portal = new TgcPortalRenderingPortal(portalData.name, boundingBox); manager.Portals.Add(portal); //Cargar conexiones para celdas A y B TgcPortalRenderingCell cellA = manager.Cells[portalData.cellA]; TgcPortalRenderingCell cellB = manager.Cells[portalData.cellB]; //Poligono del portal para la celda A TgcConvexPolygon polygonA = new TgcConvexPolygon(); polygonA.BoundingVertices = new Vector3[portalData.boundingVerticesA.Length / 3]; for (int i = 0; i < polygonA.BoundingVertices.Length; i++) { polygonA.BoundingVertices[i] = new Vector3( portalData.boundingVerticesA[i * 3], portalData.boundingVerticesA[i * 3 + 1], portalData.boundingVerticesA[i * 3 + 2] ); } //Plano del portal para la celda A Plane planeA = TgcParserUtils.float4ArrayToPlane(portalData.planeA); //Crear conexion A TgcPortalRenderingConnection connectionA = new TgcPortalRenderingConnection(portal, cellB, polygonA, planeA); cellA.Connections.Add(connectionA); //Poligono del portal para la celda B TgcConvexPolygon polygonB = new TgcConvexPolygon(); polygonB.BoundingVertices = new Vector3[portalData.boundingVerticesB.Length / 3]; for (int i = 0; i < polygonB.BoundingVertices.Length; i++) { polygonB.BoundingVertices[i] = new Vector3( portalData.boundingVerticesB[i * 3], portalData.boundingVerticesB[i * 3 + 1], portalData.boundingVerticesB[i * 3 + 2] ); } //Plano del portal para la celda B Plane planeB = TgcParserUtils.float4ArrayToPlane(portalData.planeB); //Crear conexion B TgcPortalRenderingConnection connectionB = new TgcPortalRenderingConnection(portal, cellA, polygonB, planeB); cellB.Connections.Add(connectionB); } return(manager); }