Jump to content
Atom

Post Processing An Export?

Recommended Posts

HI All,

 

I am trying to add the usemtl tag after every group inside a OBJ file that the ROP Output generates. The Houdini exporter does not seem to support this feature of the OBJ file format.

 

This simple fixup script does the job ok.

# Add a default material for each group.
# Run after .OBJ export.

file_name_in = r"C:\Users\Developer\Desktop\my_mesh.obj"
file_name_out = r"C:\Users\Developer\Desktop\my_mesh_mat.obj"
with open(file_name_in, 'r') as f:
    lines = f.read().splitlines()   # Remove slash n character at the end of each line.
f.close()

mat_count=1
new_lines = []
 
for line in lines:
    new_lines.append(line)
    ary = line.split(' ')
    if ary[0] == 'g':
        # Detected a goup.
        mat_name = "mat_%d" % mat_count
        mat_count +=1
        new_lines.append("usemtl %s" % mat_name)

f = open(file_name_out, 'w')
for line in new_lines:
  f.write("%s\n" % line)
f.close()

So the question is how do I leverage the PostFrame Script event of the ROP Output node?

I would need to somehow pass the frame # to the script. I have never used args* in python yet.

 

Does anyone have tips on how to accomplish this task?

 

Thanks

Edited by Atom
  • Like 1

Share this post


Link to post
Share on other sites

Ok, this is my first venture into using those Pre/Post script fields. There is a browse button and I browse to my external .py script but this just produces an error when I click Save To Disk because it is trying to process the file name to the script as code. I give up on that and just press CTRL-E in the field and type in a multi line python script. Remember to change the Language from Hscript to Python for your chosen field.

 

I place this code in the Post-Write Script field:

import hou
import os

node = hou.pwd()
file_name_in = node.evalParm('sopoutput')
s = os.path.splitext(file_name_in)[0]
file_name_out = "%s_mat.obj" % s

print file_name_in, file_name_out

with open(file_name_in, 'r') as f:
    lines = f.read().splitlines()   # Remove slash n character at the end of each line.
f.close()

mat_count=1
new_lines = []
 
for line in lines:
    ary = line.split(' ')
    if ary[0] == 'g':
        # Detected a group.
        if mat_count == 1:
            # The first g token should actually be an o token with the object name.
            new_lines.append("o %s" % node.parent())
        else:
            new_lines.append(line)
            mat_name = "mat_%d" % mat_count
            new_lines.append("usemtl %s" % mat_name)
        mat_count +=1
    else:
        new_lines.append(line)

f = open(file_name_out, 'w')
for line in new_lines:
  f.write("%s\n" % line)
f.close()

os.remove(file_name_in)
#os.rename(file_name_out, file_name_in)


This code does almost everything I wanted. The last line is intended to rename the newly created file to the same name in the Output File field in the node panel. But it does not work and errors out. My guess is that Houdini is still holding some file handle to the original name until after Post-Render thus I can not rename my new file to the same name as the original. I can delete it however...? Edited by Atom

Share this post


Link to post
Share on other sites

could do a rename in the "post render" rather than "post frame"?

Share this post


Link to post
Share on other sites

I wondered about that, but I am dealing with a sequence. I assumed Post-Render was after the entire sequence was done. In that case I would not have the correct $F to construct a filename.

 

Does Post-Render fire after every frame or after the end of all render/exports?

Share this post


Link to post
Share on other sites

pretty sure it's end of all render/exports

 

but you have the seq - so you'll know all you need to rename them

Share this post


Link to post
Share on other sites

Ok, I see what you mean, I could fetch the parms from the Start/End/Inc and run a clean up script at the end.

I managed to simplify the code and this seems to work.
By simply adding a usemtl after each g token, other 3D packages can import this and create a material for the groups.
 

Place this code in a Post-Write Script field of a ROP Output Driver and change Hscript to Python. This code will write a new repaired OBJ file with a PREFIX to the file name and erase the original.

# Add a default material for each group.
# Run after .OBJ export.

import os

PRE_FIX = "ap"                                          # Pick your own prefix token here.
node = hou.pwd()                                        # Get the node this code is running under.
file_name_in = node.evalParm('sopoutput')               # Fetch the name from the ROP Output panel.
the_path = os.path.dirname(file_name_in)                # Get the path.
the_name = os.path.basename(file_name_in)               # Get the name.
name_only = os.path.splitext(the_name)[0]               # Remove the file extension.
s = "%s_%s.obj" % (PRE_FIX,name_only)                   # Construct a new name that uses the PREFIX.
file_name_out = os.path.join(the_path, s)

with open(file_name_in, 'r') as f:
    lines = f.read().splitlines()   # Remove slash n character at the end of each line.
f.close()

mat_count=0
new_lines = []
for line in lines:
    ary = line.split(' ')
    if ary[0] == 'g':
        if mat_count > 0:
            # Detected a goup.
            new_lines.append(line)
            mat_name = "mat_%d" % mat_count
            new_lines.append("usemtl %s" % mat_name)
        mat_count +=1
    else:
        new_lines.append(line)
        
f = open(file_name_out, 'w')
for line in new_lines:
  f.write("%s\n" % line)
f.close()

os.remove(file_name_in)
Edited by Atom

Share this post


Link to post
Share on other sites

Thanks Atom, this script is really useful!

I've introduced a feature, which introduces constant material names via group names.

It's a simple hack to the wavefront exporter, but it works once you prepare groups to be able to transfer material names. I'll leave it here, if someone find it useful or wants to improve it.

Best

Manuel

 

## Add a default material for each group and specific material names for specific groups
# Run after .OBJ export.

import os

PRE_FIX = "hobj"                                        # Pick your own prefix token here.
node = hou.pwd()                                        # Get the node this code is running under.
file_name_in = node.evalParm('sopoutput')               # Fetch the name from the ROP Output panel.
the_path = os.path.dirname(file_name_in)                # Get the path.
the_name = os.path.basename(file_name_in)               # Get the name.
name_only = os.path.splitext(the_name)[0]               # Remove the file extension.
s = "%s_%s.obj" % (PRE_FIX,name_only)                   # Construct a new name that uses the PREFIX.
file_name_out = os.path.join(the_path, s)

with open(file_name_in, 'r') as f:
    lines = f.read().splitlines()   # Remove slash n character at the end of each line.
f.close()

mat_count=0
new_lines = []
for line in lines:
    ary = line.split(' ')   
    if ary[0] == 'g':
        if mat_count > 0:               # Detected a group.
            gr_nm=ary[1]                # check group name
            if gr_nm[0:4] == 'hmt_':    # Pick another material prefix token here.
                new_lines.append(line)
                mat_name = gr_nm
                new_lines.append("usemtl %s" % mat_name)
            else:        
                new_lines.append(line)
                mat_name = "mat_%d" % mat_count
                new_lines.append("usemtl %s" % mat_name)
        mat_count +=1
    else:
        new_lines.append(line)
        
f = open(file_name_out, 'w')
for line in new_lines:
  f.write("%s\n" % line)
f.close()

os.remove(file_name_in)

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

×