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 + -
显示快捷键?