nfBool CMeshInformation_BaseMaterials::faceHasData(_In_ nfUint32 nFaceIndex) { MESHINFORMATION_BASEMATERIAL * pFaceData = (MESHINFORMATION_BASEMATERIAL*)getFaceData(nFaceIndex); if (pFaceData) return (pFaceData->m_nMaterialGroupID != 0); return false; }
void CMeshInformation_BaseMaterials::cloneFaceInfosFrom(_In_ nfUint32 nFaceIndex, _In_ CMeshInformation * pOtherInformation, _In_ nfUint32 nOtherFaceIndex) { __NMRASSERT(pOtherInformation); MESHINFORMATION_BASEMATERIAL * pTargetFaceData = (MESHINFORMATION_BASEMATERIAL*)getFaceData(nFaceIndex); MESHINFORMATION_BASEMATERIAL * pSourceFaceData = (MESHINFORMATION_BASEMATERIAL*)pOtherInformation->getFaceData(nOtherFaceIndex); if (pTargetFaceData && pSourceFaceData) { pTargetFaceData->m_nMaterialGroupID = pSourceFaceData->m_nMaterialGroupID; pTargetFaceData->m_nMaterialIndex = pSourceFaceData->m_nMaterialIndex; } }
int renderChunkWithMeshing(Chunk *chunk, GLfloat *points, GLfloat *normals, GLfloat *colors, vec3 offset, float scale) { float blockWidth = scale * BLOCK_WIDTH; Color *face[CHUNK_SIZE][CHUNK_SIZE]; unsigned int axis1, axis2, axis3, w, h, i, j, k, points_index, pos[3], dir[3]; int sign, empty, models; Block *voxel1, *voxel2; vec3 d_axis2, d_axis3, fpos; //Color covered; // placeholder value for covered faces vec3 color; GLuint indices[] = {0, 1, 2, 0, 2, 3, 0, 3, 2, 0, 2, 1}; GLfloat verts[12]; /* axis1 is our "working" axis. We look at both sides of each "slice" of the chunk along that axis, and determine whether each face is visible by checking the block in front of it. For each face that is visible, its color is added to the face array. Then we look at the face array and split it up into rectangles of the same color using a greedy algorithm. We draw each rectangle and then move on to the next axis. // ***** this is currently removed ***** I also implemented (my own idea!) a system where if a block is covered, a placeholder value is inserted in the face array instead. Then, when calculating the rectangles, the placeholder value is treated as a solid block, except for the fact that a rectangle cannot start on a face with the placeholder value. This still prevents faces that are completely hidden from being drawn, but allows for rectangles to be combined under blocks that are hiding different colors. This should result in a strictly smaller number of rectangles being drawn, at near-zero cost :D The only drawback is that large rectangles that are mostly hidden may still be drawn. Everything will still look fine, but there is a little extra cost from drawing the overlapping triangles. My hope is that overall the scene will render even faster. */ memset(face, 0, sizeof(face)); points_index = 0; models = 0; for (axis1 = 0; axis1 < 3; axis1++) { axis2 = (axis1 + 1) % 3; axis3 = (axis1 + 2) % 3; dir[0] = dir[1] = dir[2] = 0; d_axis2[0] = d_axis2[1] = d_axis2[2] = 0; d_axis3[0] = d_axis3[1] = d_axis3[2] = 0; for (sign = -1; sign < 2; sign += 2) { dir[axis1] = sign; for (pos[axis1] = 0; pos[axis1] < CHUNK_SIZE; pos[axis1]++) { empty = 1; // generate the face array for (pos[axis2] = 0; pos[axis2] < CHUNK_SIZE; pos[axis2]++) { for (pos[axis3] = 0; pos[axis3] < CHUNK_SIZE; pos[axis3]++) { voxel1 = getBlock(chunk, pos[0], pos[1], pos[2]); voxel2 = ((sign > 0) ? (pos[axis1] < CHUNK_SIZE - 1) : (pos[axis1] > 0)) ? getBlock(chunk, pos[0]+dir[0], pos[1]+dir[1], pos[2]+dir[2]) : NULL; if (voxel1->active) { // there's a block that is potentially drawable empty = 0; if (voxel1->data) // there's a model in the chunk. These have to be // handled separately, so we mark a boolean flag // so that we know to go back and render them models = 1; else if (!voxel2 || !voxel2->active || voxel2->data) face[pos[axis3]][pos[axis2]] = &voxel1->color; } } } // nothing to do here. Continue on. if (empty) continue; /*puts("---------------"); printf("____%c%c AXIS____\n", sign > 0 ? '+' : '-', (char[]){'X','Y','Z'}[axis1]); printf("___SLICE #%02d___\n", pos[axis1]); for (i = 0; i < CHUNK_SIZE; i++) { for (j = 0; j < CHUNK_SIZE; j++) { printf("%c ", face[j][i] ? '#' : ' '); } puts(""); } puts("---------------\n");*/ // cut the face up into rectangles and draw them for (j = 0; j < CHUNK_SIZE; j++) { for (i = 0; i < CHUNK_SIZE;) { w = 1; if (face[j][i]) { // get the width while ( (i + w < CHUNK_SIZE) && (face[j][i + w]) && (face[j][i + w]->all == face[j][i]->all) ) w++; // get the height for (h = 1; j + h < CHUNK_SIZE; h++) { // we look at the next row, and make sure each // block on the face is solid and the same color. // if it's not, we break from the outer loop for (k = 0; k < w; k++) { if ((face[j + h][i + k] == NULL) || (face[j + h][i + k]->all != face[j][i]->all) ) goto done; } } done: // draw it color[0] = (float)face[j][i]->r / 255.0; color[1] = (float)face[j][i]->g / 255.0; color[2] = (float)face[j][i]->b / 255.0; fpos[axis1] = pos[axis1] * blockWidth + offset[axis1]; fpos[axis2] = i * blockWidth + offset[axis2]; fpos[axis3] = j * blockWidth + offset[axis3]; d_axis2[axis2] = w * blockWidth; d_axis3[axis3] = h * blockWidth; if (sign > 0) fpos[axis1] += blockWidth; verts[ 0] = fpos[0]; verts[ 1] = fpos[1]; verts[ 2] = fpos[2]; verts[ 3] = fpos[0] + d_axis2[0]; verts[ 4] = fpos[1] + d_axis2[1]; verts[ 5] = fpos[2] + d_axis2[2]; verts[ 6] = fpos[0] + d_axis2[0] + d_axis3[0]; verts[ 7] = fpos[1] + d_axis2[1] + d_axis3[1]; verts[ 8] = fpos[2] + d_axis2[2] + d_axis3[2]; verts[ 9] = fpos[0] + d_axis3[0]; verts[10] = fpos[1] + d_axis3[1]; verts[11] = fpos[2] + d_axis3[2]; getFaceData(&points[points_index], verts, &indices[((sign < 0) ? 6 : 0)]); getFaceData(&normals[points_index], &cubeNormals[(sign > 0) ? 5-axis1 : 2-axis1], zeroIndices); getFaceData(&colors[points_index], color, zeroIndices); points_index += 18; // empty the face array wherever we rendered it for(k = 0; k < h; k++) { memset(&face[j + k][i], 0, w * sizeof(Color*)); } } i += w; } } } } } if (models) { // there were models in the chunk. Render them for (pos[0] = 0; pos[0] < CHUNK_SIZE; pos[0]++) { for (pos[1] = 0; pos[1] < CHUNK_SIZE; pos[1]++) { for (pos[2] = 0; pos[2] < CHUNK_SIZE; pos[2]++) { voxel1 = getBlock(chunk, pos[0], pos[1], pos[2]); if (voxel1->active && voxel1->data) { if (voxel1->data->chunk->needsUpdate) { renderModel(voxel1->data); voxel1->data->chunk->needsUpdate = 0; } if (voxel1->logic) points_index += addRenderedModel( voxel1->data, &points[points_index], &normals[points_index], &colors[points_index], *voxel1->logic->rotationMatrix, (vec3){pos[0]*blockWidth + offset[0], pos[1]*blockWidth + offset[1], pos[2]*blockWidth + offset[2]}, scale / CHUNK_SIZE ); else points_index += addRenderedModel( voxel1->data, &points[points_index], &normals[points_index], &colors[points_index], identityMatrix, (vec3){pos[0]*blockWidth + offset[0], pos[1]*blockWidth + offset[1], pos[2]*blockWidth + offset[2]}, scale / CHUNK_SIZE ); } } } } } return points_index; }
// returns the number of elements added to the arrays int renderChunkToArrays(Chunk *chunk, GLfloat *points, GLfloat *normals, GLfloat *colors, vec3 offset, float scale) { float blockWidth = BLOCK_WIDTH * scale; Block *block; vec3 color; int x, y, z; float min_x, min_y, min_z, max_x, max_y, max_z; GLfloat cube_vertices[8 * 3]; GLuint zeroIndices[] = {0, 0, 0, 0, 0, 0}; int points_index = 0; for (x = 0; x < CHUNK_SIZE; x++) { min_x = x * blockWidth + offset[0]; max_x = min_x + blockWidth; for (y = 0; y < CHUNK_SIZE; y++) { min_y = y * blockWidth + offset[1]; max_y = min_y + blockWidth; for (z = 0; z < CHUNK_SIZE; z++) { min_z = z * blockWidth + offset[2]; max_z = min_z + blockWidth; block = getBlock(chunk, x, y, z); if (!block->active) { continue; } if (block->data) { if (block->data->chunk->needsUpdate) { renderModel(block->data); block->data->chunk->needsUpdate = 0; } if (block->logic) points_index += addRenderedModel( block->data, &points[points_index], &normals[points_index], &colors[points_index], *block->logic->rotationMatrix, (vec3){min_x, min_y, min_z}, scale / CHUNK_SIZE ); else points_index += addRenderedModel( block->data, &points[points_index], &normals[points_index], &colors[points_index], identityMatrix, (vec3){min_x, min_y, min_z}, scale / CHUNK_SIZE ); continue; } cube_vertices[ 0] = min_x; cube_vertices[ 1] = min_y; cube_vertices[ 2] = min_z; cube_vertices[ 3] = min_x; cube_vertices[ 4] = min_y; cube_vertices[ 5] = max_z; cube_vertices[ 6] = min_x; cube_vertices[ 7] = max_y; cube_vertices[ 8] = min_z; cube_vertices[ 9] = min_x; cube_vertices[10] = max_y; cube_vertices[11] = max_z; cube_vertices[12] = max_x; cube_vertices[13] = min_y; cube_vertices[14] = min_z; cube_vertices[15] = max_x; cube_vertices[16] = min_y; cube_vertices[17] = max_z; cube_vertices[18] = max_x; cube_vertices[19] = max_y; cube_vertices[20] = min_z; cube_vertices[21] = max_x; cube_vertices[22] = max_y; cube_vertices[23] = max_z; color[0] = (float)block->color.r / 255.0; color[1] = (float)block->color.g / 255.0; color[2] = (float)block->color.b / 255.0; // check if each face is visible if (x == CHUNK_SIZE - 1 || !getBlock(chunk, x+1, y, z)->active || getBlock(chunk, x+1, y, z)->data) { getFaceData(&points[points_index], cube_vertices, &cubeIndices[ 0]); getFaceData(&normals[points_index], &cubeNormals[5], zeroIndices); getFaceData(&colors[points_index], color, zeroIndices); points_index += 6 * 3; } if (y == CHUNK_SIZE - 1 || !getBlock(chunk, x, y+1, z)->active || getBlock(chunk, x, y+1, z)->data) { getFaceData(&points[points_index], cube_vertices, &cubeIndices[ 6]); getFaceData(&normals[points_index], &cubeNormals[4], zeroIndices); getFaceData(&colors[points_index], color, zeroIndices); points_index += 6 * 3; } if (z == CHUNK_SIZE - 1 || !getBlock(chunk, x, y, z+1)->active || getBlock(chunk, x, y, z+1)->data) { getFaceData(&points[points_index], cube_vertices, &cubeIndices[12]); getFaceData(&normals[points_index], &cubeNormals[3], zeroIndices); getFaceData(&colors[points_index], color, zeroIndices); points_index += 6 * 3; } if (x == 0 || !getBlock(chunk, x-1, y, z)->active || getBlock(chunk, x-1, y, z)->data) { getFaceData(&points[points_index], cube_vertices, &cubeIndices[18]); getFaceData(&normals[points_index], &cubeNormals[2], zeroIndices); getFaceData(&colors[points_index], color, zeroIndices); points_index += 6 * 3; } if (y == 0 || !getBlock(chunk, x, y-1, z)->active || getBlock(chunk, x, y-1, z)->data) { getFaceData(&points[points_index], cube_vertices, &cubeIndices[24]); getFaceData(&normals[points_index], &cubeNormals[1], zeroIndices); getFaceData(&colors[points_index], color, zeroIndices); points_index += 6 * 3; } if (z == 0 || !getBlock(chunk, x, y, z-1)->active || getBlock(chunk, x, y, z-1)->data) { getFaceData(&points[points_index], cube_vertices, &cubeIndices[30]); getFaceData(&normals[points_index], &cubeNormals[0], zeroIndices); getFaceData(&colors[points_index], color, zeroIndices); points_index += 6 * 3; } } } } return points_index; }
const std::vector<double>& SimulationDataContainer::faceflux() const { return getFaceData("FACEFLUX"); }
const std::vector<double>& SimulationDataContainer::facepressure() const { return getFaceData("FACEPRESSURE"); }
bool ShockBaseClass::getLocalSurfaces(Real t,std::vector<LocalSurface>& localSurfaces,uint32_t& N_shockCells,int refinements) { // Create shock mesh: if (initializeMesh(t,refinements) == false) { simClasses->logger << "(SEP SHOCK BASE) ERROR: Failed to create shock mesh" << endl << write; return false; } uint64_t N_surfaces = 0; const vector<Real>& faceData = getFaceData(N_surfaces); const vector<Real>& nodeCoordinates = getNodeCoordinates(); const vector<uint32_t>& cellConnectivity = getCellConnectivity(); N_shockCells = N_surfaces; // Iterate over all shock surface elements. If the element is on a cell hosted on // this process (determined by cell centroid), inject particles to it: size_t connIndex = 0; for (size_t s=0; s<N_surfaces; ++s) { const size_t areaIndex = s * ucdmesh::facedataelement::SIZE; const size_t connSize = cellConnectivity[connIndex+1]+2; const size_t node1 = cellConnectivity[connIndex+2]; const size_t node2 = cellConnectivity[connIndex+3]; const size_t node3 = cellConnectivity[connIndex+4]; Real centroid[3]; centroid[0] = (nodeCoordinates[3*node1+0] + nodeCoordinates[3*node2+0] + nodeCoordinates[3*node3+0])/3; centroid[1] = (nodeCoordinates[3*node1+1] + nodeCoordinates[3*node2+1] + nodeCoordinates[3*node3+1])/3; centroid[2] = (nodeCoordinates[3*node1+2] + nodeCoordinates[3*node2+2] + nodeCoordinates[3*node3+2])/3; Real normal[3]; normal[0] = faceData[areaIndex + ucdmesh::facedataelement::NORMAL_X]; normal[1] = faceData[areaIndex + ucdmesh::facedataelement::NORMAL_Y]; normal[2] = faceData[areaIndex + ucdmesh::facedataelement::NORMAL_Z]; // Convert centroid position to logical coordinates and check that it // is inside simulation domain (coords are not inf): Real logical[3]; Real xy,r,theta,phi; Real spherCentroid[3]; switch (simControl.coordinateSystem) { case sep::UNKNOWN: finalizeMesh(); return false; break; case sep::CARTESIAN: getLogicalCoordinates(sim,centroid,logical); if (logical[0] == numeric_limits<Real>::infinity()) { connIndex += connSize; continue; } break; case sep::CYLINDRICAL: finalizeMesh(); return false; break; case sep::SPHERICAL: // Need to convert to spherical coordinates first: xy = centroid[0]*centroid[0] + centroid[1]*centroid[1]; r = xy + centroid[2]*centroid[2]; r = sqrt(r); xy = sqrt(xy); theta = acos(centroid[2]/r); phi = acos(centroid[0] / xy); if (centroid[1] < 0.0) phi = -phi; spherCentroid[0] = r; spherCentroid[1] = theta; spherCentroid[2] = phi; // Check logical coords: getLogicalCoordinates(sim,spherCentroid,logical); if (logical[0] == std::numeric_limits<Real>::infinity()) { connIndex += connSize; continue; } break; default: finalizeMesh(); return false; break; } // Check that injection position is in upstream side: Real d_shock = getSquaredDistanceToShock(t,logical); bool acceptSurface = true; while (d_shock <= 1.0) { // Move injection point to the direction of shock normal: for (int i=0; i<3; ++i) centroid[i] += (0.1+1.001*fabs(d_shock))*normal[i]; switch (simControl.coordinateSystem) { case sep::UNKNOWN: finalizeMesh(); return false; break; case sep::CARTESIAN: getLogicalCoordinates(sim,centroid,logical); if (logical[0] == std::numeric_limits<Real>::infinity()) { acceptSurface = false; } break; case sep::CYLINDRICAL: finalizeMesh(); return false; break; case sep::SPHERICAL: xy = centroid[0]*centroid[0] + centroid[1]*centroid[1]; r = sqrt(xy + centroid[2]*centroid[2]); xy = sqrt(xy); theta = acos(centroid[2]/r); phi = acos(centroid[0] / xy); if (centroid[1] < 0.0) phi = -phi; spherCentroid[0] = r; spherCentroid[1] = theta; spherCentroid[2] = phi; getLogicalCoordinates(sim,spherCentroid,logical); if (logical[0] == numeric_limits<Real>::infinity()) acceptSurface = false; break; default: finalizeMesh(); return false; break; } if (acceptSurface == false) break; d_shock = simControl.shock->getSquaredDistanceToShock(t,logical); } if (acceptSurface == false) { connIndex += connSize; continue; } // Calculate cell indices: int32_t i_block = static_cast<int32_t>(logical[0]) / block::WIDTH_X; int32_t j_block = static_cast<int32_t>(logical[1]) / block::WIDTH_Y; int32_t k_block = static_cast<int32_t>(logical[2]) / block::WIDTH_Z; // Calculate block global index and check if this process has it: pargrid::CellID blockGID = block::calculateGlobalIndex(*sim,i_block,j_block,k_block); pargrid::CellID blockLID = simClasses->pargrid.getLocalID(blockGID); if (blockLID == pargrid::INVALID_CELLID) { connIndex += connSize; continue; } if (simClasses->pargrid.getHosts()[blockLID] != sim->mpiRank) { connIndex += connSize; continue; } // Surface accepted, add to output vector: LocalSurface surface; surface.localID = blockLID; surface.globalID = blockGID; for (int i=0; i<3; ++i) surface.position[i] = logical[i]; surface.area = faceData[areaIndex+ucdmesh::facedataelement::AREA]; surface.zoneIndex = s; localSurfaces.push_back(surface); connIndex += connSize; } if (finalizeMesh() == false) return false; return true; }