cmodfix.cpp
来自「celestia源代码」· C++ 代码 · 共 1,525 行 · 第 1/3 页
CPP
1,525 行
desc.nAttributes = nAttributes; desc.stride = stride;}template <typename T> voidjoinVertices(vector<Face>& faces, const void* vertexData, const Mesh::VertexDescription& desc, T& comparator){ // Don't do anything if we're given no data if (faces.size() == 0) return; // Must have a position assert(desc.getAttribute(Mesh::Position).format == Mesh::Float3); uint32 posOffset = desc.getAttribute(Mesh::Position).offset; const char* vertexPoints = reinterpret_cast<const char*>(vertexData) + posOffset; uint32 nVertices = faces.size() * 3; // Initialize the array of vertices vector<Vertex> vertices(nVertices); uint32 f; for (f = 0; f < faces.size(); f++) { for (uint32 j = 0; j < 3; j++) { uint32 index = faces[f].i[j]; vertices[f * 3 + j] = Vertex(index, vertexPoints + desc.stride * index); } } // Sort the vertices so that identical ones will be ordered consecutively sort(vertices.begin(), vertices.end(), comparator); // Build the vertex merge map vector<uint32> mergeMap(nVertices); uint32 lastUnique = 0; for (uint32 i = 0; i < nVertices; i++) { if (i == 0 || comparator.operator()(vertices[i - 1], vertices[i]) || comparator.operator()(vertices[i], vertices[i - 1])) { lastUnique = i; } mergeMap[vertices[i].index] = vertices[lastUnique].index; } // Remap the vertex indices for (f = 0; f < faces.size(); f++) { for (uint32 k= 0; k < 3; k++) faces[f].vi[k] = mergeMap[faces[f].i[k]]; }}Mesh*generateNormals(Mesh& mesh, float smoothAngle, bool weld){ uint32 nVertices = mesh.getVertexCount(); float cosSmoothAngle = (float) cos(smoothAngle); const Mesh::VertexDescription& desc = mesh.getVertexDescription(); if (desc.getAttribute(Mesh::Position).format != Mesh::Float3) { cerr << "Vertex position must be a float3\n"; return NULL; } uint32 posOffset = desc.getAttribute(Mesh::Position).offset; uint32 nFaces = 0; uint32 i; for (i = 0; mesh.getGroup(i) != NULL; i++) { const Mesh::PrimitiveGroup* group = mesh.getGroup(i); switch (group->prim) { case Mesh::TriList: if (group->nIndices < 3 || group->nIndices % 3 != 0) { cerr << "Triangle list has invalid number of indices\n"; return NULL; } nFaces += group->nIndices / 3; break; case Mesh::TriStrip: case Mesh::TriFan: if (group->nIndices < 3) { cerr << "Error: tri strip or fan has less than three indices\n"; return NULL; } nFaces += group->nIndices - 2; break; default: cerr << "Cannot generate normals for non-triangle primitives\n"; return NULL; } } // Build the array of faces; this may require decomposing triangle strips // and fans into triangle lists. vector<Face> faces(nFaces); uint32 f = 0; for (i = 0; mesh.getGroup(i) != NULL; i++) { const Mesh::PrimitiveGroup* group = mesh.getGroup(i); switch (group->prim) { case Mesh::TriList: { for (uint32 j = 0; j < group->nIndices / 3; j++) { assert(f < nFaces); faces[f].i[0] = group->indices[j * 3]; faces[f].i[1] = group->indices[j * 3 + 1]; faces[f].i[2] = group->indices[j * 3 + 2]; f++; } } break; case Mesh::TriStrip: { for (uint32 j = 2; j < group->nIndices; j++) { assert(f < nFaces); if (j % 2 == 0) { faces[f].i[0] = group->indices[j - 2]; faces[f].i[1] = group->indices[j - 1]; faces[f].i[2] = group->indices[j]; } else { faces[f].i[0] = group->indices[j - 1]; faces[f].i[1] = group->indices[j - 2]; faces[f].i[2] = group->indices[j]; } f++; } } break; case Mesh::TriFan: { for (uint32 j = 2; j < group->nIndices; j++) { assert(f < nFaces); faces[f].i[0] = group->indices[0]; faces[f].i[1] = group->indices[j - 1]; faces[f].i[2] = group->indices[j]; f++; } } break; default: assert(0); break; } } assert(f == nFaces); const void* vertexData = mesh.getVertexData(); // Compute normals for the faces for (f = 0; f < nFaces; f++) { Face& face = faces[f]; Point3f p0 = getVertex(vertexData, posOffset, desc.stride, face.i[0]); Point3f p1 = getVertex(vertexData, posOffset, desc.stride, face.i[1]); Point3f p2 = getVertex(vertexData, posOffset, desc.stride, face.i[2]); face.normal = cross(p1 - p0, p2 - p1); if (face.normal * face.normal > 0.0f) face.normal.normalize(); } // For each vertex, create a list of faces that contain it uint32* faceCounts = new uint32[nVertices]; uint32** vertexFaces = new uint32*[nVertices]; // Initialize the lists for (i = 0; i < nVertices; i++) { faceCounts[i] = 0; vertexFaces[i] = NULL; } // If we're welding vertices before generating normals, find identical // points and merge them. Otherwise, the point indices will be the same // as the attribute indices. if (weld) { joinVertices(faces, vertexData, desc, PointComparator()); } else { for (f = 0; f < nFaces; f++) { faces[f].vi[0] = faces[f].i[0]; faces[f].vi[1] = faces[f].i[1]; faces[f].vi[2] = faces[f].i[2]; } } // Count the number of faces in which each vertex appears for (f = 0; f < nFaces; f++) { Face& face = faces[f]; faceCounts[face.vi[0]]++; faceCounts[face.vi[1]]++; faceCounts[face.vi[2]]++; } // Allocate space for the per-vertex face lists for (i = 0; i < nVertices; i++) { if (faceCounts[i] > 0) { vertexFaces[i] = new uint32[faceCounts[i] + 1]; vertexFaces[i][0] = faceCounts[i]; } } // Fill in the vertex/face lists for (f = 0; f < nFaces; f++) { Face& face = faces[f]; vertexFaces[face.vi[0]][faceCounts[face.vi[0]]--] = f; vertexFaces[face.vi[1]][faceCounts[face.vi[1]]--] = f; vertexFaces[face.vi[2]][faceCounts[face.vi[2]]--] = f; } // Compute the vertex normals by averaging vector<Vec3f> vertexNormals(nFaces * 3); for (f = 0; f < nFaces; f++) { Face& face = faces[f]; for (uint32 j = 0; j < 3; j++) { vertexNormals[f * 3 + j] = averageFaceVectors(faces, f, &vertexFaces[face.vi[j]][1], vertexFaces[face.vi[j]][0], cosSmoothAngle); } } // Finally, create a new mesh with normals included // Create the new vertex description Mesh::VertexDescription newDesc(desc); augmentVertexDescription(newDesc, Mesh::Normal, Mesh::Float3); // We need to convert the copy the old vertex attributes to the new // mesh. In order to do this, we need the old offset of each attribute // in the new vertex description. The fromOffsets array will contain // this mapping. uint32 normalOffset = 0; uint32 fromOffsets[16]; for (i = 0; i < newDesc.nAttributes; i++) { fromOffsets[i] = ~0; if (newDesc.attributes[i].semantic == Mesh::Normal) { normalOffset = newDesc.attributes[i].offset; } else { for (uint32 j = 0; j < desc.nAttributes; j++) { if (desc.attributes[j].semantic == newDesc.attributes[i].semantic) { assert(desc.attributes[j].format == newDesc.attributes[i].format); fromOffsets[i] = desc.attributes[j].offset; break; } } } } // Copy the old vertex data along with the generated normals to the // new vertex data buffer. void* newVertexData = new char[newDesc.stride * nFaces * 3]; for (f = 0; f < nFaces; f++) { Face& face = faces[f]; for (uint32 j = 0; j < 3; j++) { char* newVertex = reinterpret_cast<char*>(newVertexData) + (f * 3 + j) * newDesc.stride; copyVertex(newVertex, newDesc, vertexData, desc, face.i[j], fromOffsets); memcpy(newVertex + normalOffset, &vertexNormals[f * 3 + j], Mesh::getVertexAttributeSize(Mesh::Float3)); } } // Create the Celestia mesh Mesh* newMesh = new Mesh(); newMesh->setVertexDescription(newDesc); newMesh->setVertices(nFaces * 3, newVertexData); // Create a trivial index list uint32* indices = new uint32[nFaces * 3]; for (i = 0; i < nFaces * 3; i++) indices[i] = i; // TODO: This assumes that the mesh uses only one material. Normal // generation should really be done one primitive group at a time. uint32 materialIndex = mesh.getGroup(0)->materialIndex; newMesh->addGroup(Mesh::TriList, materialIndex, nFaces * 3, indices); // Clean up delete[] faceCounts; for (i = 0; i < nVertices; i++) { if (vertexFaces[i] != NULL) delete[] vertexFaces[i]; } delete[] vertexFaces; return newMesh;}Mesh*generateTangents(Mesh& mesh, bool weld){ uint32 nVertices = mesh.getVertexCount(); // In order to generate tangents, we require positions, normals, and // 2D texture coordinates in the vertex description. const Mesh::VertexDescription& desc = mesh.getVertexDescription(); if (desc.getAttribute(Mesh::Position).format != Mesh::Float3) { cerr << "Vertex position must be a float3\n"; return NULL; } if (desc.getAttribute(Mesh::Normal).format != Mesh::Float3) { cerr << "float3 format vertex normal required\n"; return NULL; } if (desc.getAttribute(Mesh::Texture0).format == Mesh::InvalidFormat) { cerr << "Texture coordinates must be present in mesh to generate tangents\n"; return NULL; } if (desc.getAttribute(Mesh::Texture0).format != Mesh::Float2) { cerr << "Texture coordinate must be a float2\n"; return NULL; } // Count the number of faces in the mesh. // (All geometry should already converted to triangle lists) uint32 i; uint32 nFaces = 0; for (i = 0; mesh.getGroup(i) != NULL; i++) { const Mesh::PrimitiveGroup* group = mesh.getGroup(i); if (group->prim == Mesh::TriList) { assert(group->nIndices % 3 == 0); nFaces += group->nIndices / 3; } else { cerr << "Mesh should contain just triangle lists\n"; return NULL; } } // Build the array of faces; this may require decomposing triangle strips // and fans into triangle lists. vector<Face> faces(nFaces); uint32 f = 0; for (i = 0; mesh.getGroup(i) != NULL; i++) { const Mesh::PrimitiveGroup* group = mesh.getGroup(i); switch (group->prim) { case Mesh::TriList: { for (uint32 j = 0; j < group->nIndices / 3; j++) { assert(f < nFaces); faces[f].i[0] = group->indices[j * 3]; faces[f].i[1] = group->indices[j * 3 + 1]; faces[f].i[2] = group->indices[j * 3 + 2]; f++; } } break; } } uint32 posOffset = desc.getAttribute(Mesh::Position).offset; uint32 normOffset = desc.getAttribute(Mesh::Normal).offset; uint32 texCoordOffset = desc.getAttribute(Mesh::Texture0).offset; const void* vertexData = mesh.getVertexData(); // Compute tangents for faces for (f = 0; f < nFaces; f++) { Face& face = faces[f]; Point3f p0 = getVertex(vertexData, posOffset, desc.stride, face.i[0]); Point3f p1 = getVertex(vertexData, posOffset, desc.stride, face.i[1]); Point3f p2 = getVertex(vertexData, posOffset, desc.stride, face.i[2]); Point2f tc0 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[0]); Point2f tc1 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[1]); Point2f tc2 = getTexCoord(vertexData, texCoordOffset, desc.stride, face.i[2]); float s1 = tc1.x - tc0.x; float s2 = tc2.x - tc0.x; float t1 = tc1.y - tc0.y; float t2 = tc2.y - tc0.y; float a = s1 * t2 - s2 * t1; if (a != 0.0f) face.normal = (t2 * (p1 - p0) - t1 * (p2 - p0)) * (1.0f / a); else face.normal = Vec3f(0.0f, 0.0f, 0.0f); } // For each vertex, create a list of faces that contain it uint32* faceCounts = new uint32[nVertices]; uint32** vertexFaces = new uint32*[nVertices]; // Initialize the lists for (i = 0; i < nVertices; i++) { faceCounts[i] = 0; vertexFaces[i] = NULL; } // If we're welding vertices before generating normals, find identical // points and merge them. Otherwise, the point indices will be the same // as the attribute indices. if (weld) { joinVertices(faces, vertexData, desc, PointTexCoordComparator(0, 0, true)); } else { for (f = 0; f < nFaces; f++) { faces[f].vi[0] = faces[f].i[0]; faces[f].vi[1] = faces[f].i[1]; faces[f].vi[2] = faces[f].i[2]; } } // Count the number of faces in which each vertex appears for (f = 0; f < nFaces; f++) { Face& face = faces[f]; faceCounts[face.vi[0]]++; faceCounts[face.vi[1]]++; faceCounts[face.vi[2]]++; } // Allocate space for the per-vertex face lists for (i = 0; i < nVertices; i++) { if (faceCounts[i] > 0) { vertexFaces[i] = new uint32[faceCounts[i] + 1]; vertexFaces[i][0] = faceCounts[i]; } } // Fill in the vertex/face lists for (f = 0; f < nFaces; f++) { Face& face = faces[f]; vertexFaces[face.vi[0]][faceCounts[face.vi[0]]--] = f; vertexFaces[face.vi[1]][faceCounts[face.vi[1]]--] = f; vertexFaces[face.vi[2]][faceCounts[face.vi[2]]--] = f; } // Compute the vertex tangents by averaging vector<Vec3f> vertexTangents(nFaces * 3);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?