Atom Posted February 23, 2016 Share Posted February 23, 2016 (edited) 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 February 23, 2016 by Atom 1 Quote Link to comment Share on other sites More sharing options...
Atom Posted February 23, 2016 Author Share Posted February 23, 2016 (edited) 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 February 24, 2016 by Atom Quote Link to comment Share on other sites More sharing options...
michael Posted February 23, 2016 Share Posted February 23, 2016 could do a rename in the "post render" rather than "post frame"? Quote Link to comment Share on other sites More sharing options...
Atom Posted February 24, 2016 Author Share Posted February 24, 2016 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? Quote Link to comment Share on other sites More sharing options...
michael Posted February 24, 2016 Share Posted February 24, 2016 pretty sure it's end of all render/exports but you have the seq - so you'll know all you need to rename them Quote Link to comment Share on other sites More sharing options...
Atom Posted February 24, 2016 Author Share Posted February 24, 2016 (edited) 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 February 24, 2016 by Atom Quote Link to comment Share on other sites More sharing options...
michael Posted February 24, 2016 Share Posted February 24, 2016 so now you have both... http://forums.odforce.net/topic/23514-mtl-file-reader/ Quote Link to comment Share on other sites More sharing options...
mnlrbr Posted September 9, 2019 Share Posted September 9, 2019 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) Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.