Jump to content
Atom

MTL To Redshift Material

Recommended Posts

I put together a simple script to read the .mtl file, typically associated with a .obj, and create a Redshift material for each entry it finds in the .mtl with a map_Kd token. A Redshift material is created and a texture map is linked to the diffuse color with the filename for the map populated with what is found in the .mtl entry.

This is useful when importing architectural .obj files that typically have a large number of materials associated with them.

Expected .mtl format of supported tokens.

#newmtl _4_2_                       <- Material name.
#Ns 96.078431                       <- Specular intensity
#Kd 0.640000 0.640000 0.640000      <- Diffuse color.
#Ks 0.500000 0.500000 0.500000      <- Specular color.
#Ni 1.000000                        <- Index of refraction.
#d 1.000000                         <- Opacity.
#map_Kd 21_budova/_4_2_.jpg         <- Map name.
#map_Kn 21_budova/_4_2_n.jpg        <- Map name.

 

The result of one-click texture mapping.

untitled-1.jpg

 

Here is the Colosseum auto texture mapped.

untitled1.jpg

 

The path to the .mtl file and texture path is hard coded.

Place the code in a shelf tool button and adjust the path to point to your .mtl file.

 

mtl_to_redshift_061618.zip

Edited by Atom
  • Like 6
  • Thanks 3

Share this post


Link to post
Share on other sites

I added a new feature where a rsColorCorrector is placed after the rsTexture node. I reduce the saturation to zero and connect that to a rsBumpMap. The bump map is routed to the final output. The end result is that each material gains a slight bit a relief in the final render, based upon the greyscale value of the diffuse map.

Here is the new Redshift network that is generated.

untitled-1.jpg.b9dadf5edf323c54237d34740b452fff.jpg

 

Here is the same Colosseum, pictured above, with the new bump mapping applied.

untitled1.thumb.jpg.87623b9d0b766b7681094b0f7efd3bb5.jpg

 

untitled1.jpg

Edited by Atom
  • Thanks 1

Share this post


Link to post
Share on other sites

I made a change to the script when I imported a new model. This model was making use of cards with alpha channels which were not rendering correctly. It also had some materials without image maps at all, just colors.

Here is the new Redshift network to support textures that have alphas (detected via filename extension)

untitled-1.jpg.280c55b1e638e03c2ce111be79922f45.jpg

 

Here are the before and after images for alpha support.

Before, card backgrounds are not "knocked out".no_alpha_support.thumb.jpg.9e8b926e6b747f4009b29c6165ca499e.jpg

 

rsSprite node removes or "knocks out" card background.sprite_alpha_support.thumb.jpg.8d892557e9823acd33d969ba600bb6be.jpg

 

 

untitled1.jpg

Edited by Atom
  • Thanks 1

Share this post


Link to post
Share on other sites

If you find that the script crashes on certain .MTL files, it may be that the names used for materials violate the Houdini naming convention. Most notably, any material that starts with a number. i.e. 03, for example. These files may have been exported from 3DSMax.

An example of .OBJ files with number based materials can be found at this link.

Untitled-1.thumb.jpg.060a43134c055414d7dfed5e4cbacdeb.jpg

I have written a short fixup script that will scan a folder of .OBJ files and examine the .OBJ and .MTL for Houdini naming violations. If it finds them, it will re-write the .OBJ and .MTL file with a revised name that meets the Houdini naming convention.

# Rewrite the .OBJ and .MTL files to make material names Houdini compliant.
# Most notably, 3DSMax exported .OBJ files with a material that starts with a number i.e. 03, for example.
# Like the OBJ files found at this link. https://www.turbosquid.com/3d-models/free-3ds-mode-building-ready-city/690329

import os
    
def returnFilesLike(passedFolderName, passedFileExtension = ".obj"):
    result = []
    for file in os.listdir(passedFolderName):
        if file.endswith(passedFileExtension):
            result.append(os.path.join(passedFolderName,file))
    return result
    
def rewriteOBJFiles(passedPath):
    lst_files = returnFilesLike(passedPath, ".obj")
    if len(lst_files):
        for i,file in enumerate(lst_files):
            # Scan each .OBJ looking for illegal material names.
            the_path = os.path.dirname(file)
            obj_name = os.path.basename(file)
            just_name = os.path.splitext(obj_name)[0]
            mtl_name = "%s.mtl" % just_name
            mtl_filename = os.path.join(the_path,mtl_name)
            
            if os.path.isfile(mtl_filename):
                # A companion .MTL file exists, let's read the .OBJ file.
                with open(file, 'r') as f:
                    lines = f.read().splitlines()   # Remove slash n character at the end of each line.
                f.close()

                # Let's scan the .OBJ for illegal material names.
                needs_repair = False
                new_prefix = "%s_" % just_name
                new_lines = []
                for line in lines:
                    ary = line.split(' ')
                    if ary[0] == 'usemtl':
                        if ary[1][0].isdigit():
                            # This material name violates Houdini naming condition. First letter can not be a number.
                            # Add a prefix now.
                            ary[1] = "%s%s" % (new_prefix, ary[1])
                            new_lines.append("%s %s" % (ary[0],ary[1]))
                            needs_repair = True
                    else:
                        new_lines.append(line)
                        
                if needs_repair:
                    # This .OBJ needs re-written to correct bad material names.
                    f = open(file, 'w')
                    for line in new_lines:
                      f.write("%s\n" % line)
                    f.close()
                    
                    # Time to read .MTL file.
                    with open(mtl_filename, 'r') as f:
                        lines = f.read().splitlines()   # Remove slash n character at the end of each line.
                    f.close()
                    
                    # Let's scan the .MTL for illegal material names.
                    new_lines = []
                    for line in lines:
                        ary = line.split(' ')
                        if ary[0] == 'newmtl':
                            if ary[1][0].isdigit():
                                # This material name violates Houdini naming condition. First letter can not be a number.
                                # Add a prefix now.
                                ary[1] = "%s%s" % (new_prefix, ary[1])
                                new_lines.append("%s %s" % (ary[0],ary[1]))
                        else:
                            new_lines.append(line)
                            
                    # This .MTL needs re-written to correct bad material names.
                    f = open(mtl_filename, 'w')
                    for line in new_lines:
                      f.write("%s\n" % line)
                    f.close()

    else:
        print "No [.OBJ] files found at folder [%s]." % (passedFolderName)

# NOTE: Remember to make a backup of your original .OBJ/.MTL files before you run this script.
rewriteOBJFiles ("C:\Users\Admin\Documents\Models\Blendswap\cc0_14_building_set\obj")

 

Edited by Atom
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

This is brilliant. Thanks for sharing!

Share this post


Link to post
Share on other sites
Posted (edited)

I have added support for an additional .MTL token, the map_Kn token. I came across a game based .OBJ/.MTL file that referenced companion normal maps to the diffuse maps. In this particular mesh, the normal map definition always followed the diffuse map definition. The extension to the material takes the form of a new rsTexture node being plugged into the rsBumpMap node.

untitled-2.jpg.c154e13ccc0479dded9bce84c93803fd.jpg

This disconnects the previous attempt to "auto-bump" a map by using a color correct node to create a greyscale image from the diffuse. The color correct node is still left in place, but the new rsTexture simply takes it's place for supplying the input of the rsBump map node. If no map_Kn token is found, the rsColorCorrect will remain in place.

NOTE: For this to work you must have ObjParms applied to the object using this material and the checkbox for Compute Vertex Tangents From the object UV Map must be checked. The script does create the materials, but it does not auto-check the box on your object.

 

The bump results can be a bit nicer using a normal map instead of a faked out greyscale of a diffuse.

untitled-1.thumb.jpg.6f9cba83b5d1e1f24adbea6c176d0b0c.jpg

Edited by Atom

Share this post


Link to post
Share on other sites
Posted (edited)

Briliant!  I'd  love to see a 3ds max script that exports redshift materials as a bunch of parameters to an xml file etc, and then suffixes each object name with a material identifier.  Then this script could import the obj file and create like for like materials and assign them to the imported geometry based on the suffix on the objects name.

Edited by 3di

Share this post


Link to post
Share on other sites

this is brilliant and works great, thanks for making this

I was using this to bring in some archviz models that had like 30-40 materials each so I modified it slightly to automatically promote all the RS_material parameters so you can mass change them all at once without having to dive in and out of materials hundreds of times.  Also a lot of the material settings in other DCC apps do not translate at all to redshift settings, so this helps solve that as well

pretty much just 1 line of code per vop-   rs_mat.insertParmGeneratorsForAllInputs(hou.vopParmGenType.Parameter,True)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×