Blender 2.69 Export Script Material Index by Face (Polygon)

Started by
1 comment, last by Buckeye 9 years, 4 months ago

Problem: A DirectX X-file Python export script used as an addon in Blender 2.69 does not export the material index for each face as desired. It exports a material index of 0 (zero) for all faces.

EDIT2: See HappyCoder's resolution to the problem below.

EDIT: I have attempted to post (unsuccessfully for some reason) on BlenderArtists.org a similar topic.

I'd appreciate guidance in debugging the script in order to determine whether there's a problem with my mesh/material setup in Blender, a problem with the export script, or both.

First: I am not very familiar with Python, less familiar with running/debugging scripts in Blender, and unfamiliar to the point of ignorance with the Blender API.

Second: I have a successful (DX-11) X-file loading routine, and I have used the DX export script in Blender (attached as export_dx.txt as gamedev doesn't like attaching extension "py" files) previously to successfully export animated skinned meshes with a single material. The described problem arose when I attempted to export an animated mesh to which I had applied different materials to selected faces. The export script was originally downloaded here.

To simplify the search for the problem and hopefully eliminate any complications that armature/animations might contribute, I started in Blender with a simple cube and applied different textures to 2 faces. The cube and material properties appear as follows in Blender:

[attachment=24930:cube_2textures.png]

[attachment=24931:cube_materials.png]

I have exported that object using the DirectX export script with no errors indicated in the Blender console window, and the X-file otherwise loads and displays as a textured cube in both MView (a DirectX model viewer) and my own X-file loader (DX11).

The problem described appears in the exported DirectX X-file below. As indicated in the snippet below - there are 2 materials, applied to 6 faces of the cube. As shown, the material index for each face is 0.


      MeshMaterialList { // Cube material list
        // number of materials
        2;
        // number of faces to which the materials apply
        6;
        // list of material indices in face index order
        0,
        0,
        0,
        0, // <<<<<<<<<< if edit this to 1, mesh appears as desired
        0,
        0;;
        Material Material {
           0.640000; 0.640000; 0.640000; 1.000000;;
           96.078431;
           0.500000; 0.500000; 0.500000;;
           0.000000; 0.000000; 0.000000;;
          TextureFilename {"BODY03.JPG";}
        }
        Material Material_001 {
           0.640000; 0.640000; 0.640000; 1.000000;;
           96.078431;
           0.500000; 0.500000; 0.500000;;
           0.000000; 0.000000; 0.000000;;
          TextureFilename {"CBB.jpg";}
        }
      } // End of Cube material list

In MView (a DirectX model viewer), as well as my own loader, the mesh appears with material 0 applied to the 2 faces.

[attachment=24933:cube_2textures_mview_0.png]

If I manually edit the X file to indicate the desired material (as shown in the X file snippet above, changing the material index of 0 for face #3 to an index of 1), the mesh appears in MView and my loader as desired, similar to the Blender image.

[attachment=24932:cube_2textures_mview.png]

With that information, I found the location in the export script that writes the material list, and material indices for the faces.


        self.Exporter.File.Write("MeshMaterialList {{ // {} material list\n".
            format(self.SafeName))
        self.Exporter.File.Indent()
        
        self.Exporter.File.Write("{};\n".format(len(Materials)))
        self.Exporter.File.Write("{};\n".format(len(Mesh.polygons)))
        # Write a material index for each face
        for Index, Polygon in enumerate(Mesh.polygons):
            self.Exporter.File.Write("{}".format(Polygon.material_index))
            if Index == len(Mesh.polygons) - 1:
                self.Exporter.File.Write(";;\n", Indent=False)
            else:
                self.Exporter.File.Write(",\n", Indent=False)
        
        for Material in Materials:
            WriteMaterial(self.Exporter, Material)
        
        self.Exporter.File.Unindent()
        self.Exporter.File.Write("}} // End of {} material list\n".format(
            self.SafeName))

It appears that the error occurs in the script lines:


for Index, Polygon in enumerate(Mesh.polygons) : ... Polygon.material_index)

If I assume that Polygon.material_index is correct, it may be the Mesh object is not correct in some way, either in the script, or as I've setup the object in Blender, or both.

At this point in the debugging, due to my lack of knowledge of Python and the Blender API, I'm trying to make some intelligent guesses.

Elsewhere in the script, Mesh.polygons are accessed and, perhaps modified in two classes:


    # Represents the mesh as it is inside Blender
    class _OneToOneMeshEnumerator(_MeshEnumerator):
        def __init__(self, Mesh):
            MeshExportObject._MeshEnumerator.__init__(self, Mesh)
            
            self.vertices = Mesh.vertices
            
            self.PolygonVertexIndexes = tuple(tuple(Polygon.vertices)
                for Polygon in Mesh.polygons)

    # Duplicates each vertex for each face
    class _UnrolledFacesMeshEnumerator(_MeshEnumerator):
        def __init__(self, Mesh):
            MeshExportObject._MeshEnumerator.__init__(self, Mesh)
            
            self.vertices = tuple()
            for Polygon in Mesh.polygons:
                self.vertices += tuple(Mesh.vertices[VertexIndex]
                    for VertexIndex in Polygon.vertices)
            
            self.PolygonVertexIndexes = []
            Index = 0
            for Polygon in Mesh.polygons:
                self.PolygonVertexIndexes.append(tuple(range(Index,
                    Index + len(Polygon.vertices))))
                Index += len(Polygon.vertices)

Those classes appear to be invoked in the script depending on the interface options as follows:


        # Create the mesh enumerator based on options
        MeshEnumerator = None
        if (self.Config.ExportUVCoordinates and Mesh.uv_textures) or \
            (self.Config.ExportVertexColors and Mesh.vertex_colors) or \
            (self.Config.ExportSkinWeights):
            MeshEnumerator = MeshExportObject._UnrolledFacesMeshEnumerator(Mesh)
        else:
            MeshEnumerator = MeshExportObject._OneToOneMeshEnumerator(Mesh)

In the menu options in the Blender addon export interface, I check the Export UV Coordinates and not Export Vertex Colors or Export Skin Weights. So, continuing my guessing, the MeshEnumerator created depends on whether Mesh.uv_textures evaluates to "true."

At this point, I'm not sure how to proceed. I suspect that either I haven't setup the materials list correctly in Blender, or there's something I don't understand in the export script.

To debug further, I'm doing more research in Blending scripting via the Python console, and the Blender 2.69 API. In the meantime, if someone can provide additional guidance, it would be greatly appreciated.

EDIT: I have determined, via the Python console in Blender, that Polygon.material_index for each face is 0. As the mesh appears correctly textured in Blender's 3D View -> Texture, I'm exploring further, hopefully via a post on BlenderArtists, as well as further API searching, to determine how the texture/material for each face is accessed.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Advertisement

Blender lets you assign textures to faces independently of the material that is applied to the face. The texture assigned is used for previewing texture coordinates. Are you sure you are applying the second material to the face and not just a different texture?

My current game project Platform RPG

Are you sure you are applying the second material to the face and not just a different texture?

You hit the nail on the head. [thumbs up] I had associated a texture with a face in the UV ImageEditor window, but did not assign the material to the selected face!

For those interested in the solution to the problem noted:

A. I selected the faces I wanted to apply a material to.

B. In the properties to the right in the 3d View, selected the appropriate material.

C. Below the selected material, clicked "Assign" to apply that material to the selected faces.

D. Repeat for faces and materials as desired.

Sorry, I can only vote you up once, HappyCoder. wink.png

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

This topic is closed to new replies.

Advertisement