Getting ObjImporter to parse quads

The App Hub’s Custom Model Importer sample loads 3D models of the ubiquitous .obj format, and is a straightforward way to get started with the XNA Content Processor. Not surprisingly, this sample just deals with handling the basics- it parses groups, converts triangles to vertices and loads diffuse textures, and not much else. It is not prepared to handle quad polygons, so I came up with a solution for it.

3D modeling with quads is very common and helpful for an artist, since they are better than triangles for reading the topology of the model, but they are not too friendly for real-time game rendering. Graphics hardware prefers triangles, and any quads from models imported into programs need to be handled appropriately. Either they may get totally ignored or crash your program when something goes wrong in your file importer. Using simpler file formats makes it a whole lot easier to understand how to solve such problems, and use the XNA content pipeline for your own needs.

The ObjImporter class of the custom model importer can be updated to handle quads in a certain winding order. I have modified it so that it can either read triangles or quads with vertices winding clockwise. To load models with quads, simply open ObjImporter.cs and look for the “f” case found in the ParseObjLine method (found around line 200) and replace it with the following code I wrote here:

// Faces (triangles and quads are supported)
case "f":

    // For triangles
    int[] polyIndices = {
        0, 1, 2
    };

    // Change the indices if a quad is needed
    if (lineTokens.Length > 4)
    {
        Array.Resize(ref polyIndices, 6);
        polyIndices[2] = 3;
        polyIndices[3] = 1;
        polyIndices[4] = 2;
        polyIndices[5] = 3;
    }

    // If the builder is null, this face is outside of a group
    // Start a new, unnamed group
    if (meshBuilder == null)
        StartMesh(null);

    // For each triangle vertex
    for (int vertexIndex = 0; vertexIndex < polyIndices.Length; vertexIndex++)
    {
        // Each vertex is a set of three indices:
        // position, texture coordinate, and normal
        // The indices are 1-based, separated by slashes
        // and only position is required.
        string[] indices = lineTokens[polyIndices[vertexIndex] + 1].Split('/');

        // Required: Position
        int positionIndex = int.Parse(indices[0],
            CultureInfo.InvariantCulture) - 1;

        if (indices.Length > 1)
        {
            // Optional: Texture coordinate
            int texCoordIndex;
            Vector2 texCoord;
            if (int.TryParse(indices[1], out texCoordIndex))
                texCoord = texCoords[texCoordIndex - 1];
            else
            texCoord = Vector2.Zero;

            // Set channel data for texture coordinate for the following
            // vertex. This must be done before calling AddTriangleVertex
            meshBuilder.SetVertexChannelData(textureCoordinateDataIndex,
                texCoord);
        }

        if (indices.Length > 2)
        {
            // Optional: Normal
            int normalIndex;
            Vector3 normal;
            if (int.TryParse(indices[2], out normalIndex))
                normal = normals[normalIndex - 1];
            else
                normal = Vector3.Zero;

            // Set channel data for normal for the following vertex.
            // This must be done before calling AddTriangleVertex
            meshBuilder.SetVertexChannelData(normalDataIndex, normal);
        }

        // Add the vertex with the vertex data that was just set
        meshBuilder.AddTriangleVertex(positionMap[positionIndex]);
    }
    break;

The notable differences here is the setup of polygon indices for both triangle and quad cases, and the vertexIndex loop parses index data from the order given directly by the index array and not straight as it is read from the line. I suppose there should still be a warning and a break to skip the addition of vertices if a n-gon has more than 4 sides, but these are rare.

Hope this helps people wanting to import mixed-polygon models into their programs!

Advertisements

XNA 4.0 parallax occlusion mapping

The XNACommunity Codeplex site, run by a group of hobbyist Spanish game developers, has a huge collection of programs and code examples that you can use freely for your own projects. However, most of them have not been updated for XNA 4.0. I was mostly interested in the Parallax Occulsion Mapping sample, and decided to see if I could update the code.

Parallax Mapping is a more complex way to make textures pop out, and it differs from normal and bump mapping that it actually projects the texture’s details in three dimensions, as opposed to just changing the lighting from the normals.

The original sample included a particle generator, which added a bit of flair to the scene. I could not get this working because the PointSprite object has been deprecated in XNA 4.0 and there’s no easy equivalent for it. The best I could to is make the generator produce black lines :-/ Its particle system was a bit complex to just simply change from point sprites to billboarded quads, so I just decided to omit this altogether since it’s not relevant to the real purpose of the sample.

Aside from trying to get the particles working, porting the program was a breeze. Just a few tweaks were needed in the effect files, and removing unneeded rendering functions and replacing others. Pressing the space bar lets you switch between no mapping, normal mapping, and parallax mapping. Use WASD/arrow keys to move around.

You can download the updated sample here, or check out the source at GitHub. It is ready to work with your XNA 4.0 projects. Please drop a line if you found it helpful!