├── .gitignore ├── 3DCoat └── Scripts │ ├── OD_CopyToExternal.txt │ ├── OD_PasteFromExternal.txt │ ├── ReadMe.txt │ ├── objToVertData.exe │ └── vertDataToObj.exe ├── 3DSMax ├── 3DSMax_CopyToExternal.py ├── 3DSMax_LaunchCopyToExternal.ms ├── 3DSMax_LaunchPasteFromExternal.ms └── 3DSMax_PastefromExternal.py ├── Blender ├── BLENDER_ExportToExternal.py ├── BLENDER_PasteFromExternal.py ├── Blender280 │ ├── BLENDER_ExportToExternal.py │ └── BLENDER_PasteFromExternal.py ├── Blender290 │ ├── BLENDER_ExportToExternal.py │ └── BLENDER_PasteFromExternal.py └── Blender310 │ ├── BLENDER_ExportToExternal.py │ └── BLENDER_PasteFromExternal.py ├── C4D ├── C4D_CopyToExternal.py └── C4D_PasteFromExternal.py ├── Houdini ├── Houdini_CopyToExternal.py └── Houdini_PasteFromExternal.py ├── LICENSE ├── Lightwave ├── LW_CopyPasteExternal.py ├── Layout_MenuBranch.cfg ├── Lightwave_Pre_2015 │ ├── LW_CopyToExternal.py │ ├── LW_LayoutPasteFromExternal.py │ └── LW_PasteFromExternal.py └── Modeler_MenuBranch.cfg ├── Maya ├── maya_ExportToExternal.py └── maya_PasteFromExternal.py ├── Modo └── Kits │ └── OD_ModoCopyPasteExternal │ ├── .DS_Store │ ├── ModesTailMenu.cfg │ ├── hotkeys.CFG │ ├── icons.CFG │ ├── images │ ├── icons.psd │ ├── icons_20.png │ └── icons_32.png │ ├── index.cfg │ ├── lxserv │ ├── cmd_copyToExternal.py │ └── cmd_pasteFromExternal.py │ └── od_copy_paste_external │ ├── __init__.py │ ├── copy_to_external.py │ └── paste_from_external.py ├── Moi3D ├── ODCopyToExternal.js ├── ODPasteFromExternal.htm ├── ODPasteFromExternal.js ├── objToVertData.exe └── vertDataToObj.exe ├── README.md ├── Rhino ├── Rhino_CopyToExternal.py └── Rhino_PasteFromExternal.py ├── Sketchup └── SKETCHUP_PastefromExternal.rb ├── SubstancePainter └── ODCopyPaste │ ├── OSX_binary_vertDataToObj.zip │ ├── main.qml │ ├── paste.qml │ ├── paste_udim.qml │ └── vertDataToObj.exe ├── Unity └── Assets │ ├── OD_CopyPaste.meta │ └── OD_CopyPaste │ ├── CopyPaste.cs │ ├── CopyPaste.cs.meta │ ├── Editor.meta │ ├── Editor │ ├── CopyPasteMenuItems.cs │ ├── CopyPasteMenuItems.cs.meta │ ├── CopyPastePreferences.cs │ └── CopyPastePreferences.cs.meta │ ├── MeshUtility.cs │ ├── MeshUtility.cs.meta │ ├── Polygon.cs │ ├── Polygon.cs.meta │ ├── UVCoord.cs │ ├── UVCoord.cs.meta │ ├── Vertex.cs │ └── Vertex.cs.meta ├── XSI ├── XSI_CopyToExternal.py └── XSI_PasteFromExternal.py ├── ZBrush ├── ODCopyPaste │ ├── OSX_binary_objToVertData.zip │ ├── OSX_binary_vertDataToObj.zip │ ├── ZFileUtils.lib │ ├── ZFileUtils64.dll │ ├── objToVertData.exe │ ├── source │ │ ├── ZBRUSH_ODCopyPasteExternal.txt │ │ ├── objToVertData.py │ │ └── vertDataToObj.py │ └── vertDataToObj.exe └── ZBRUSH_ODCopyPasteExternal.zsc ├── _config.yml └── docs ├── datafile.txt ├── datafile_example.txt ├── objToVertData.py └── vertDataToObj.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # unity project generated files 92 | Unity/Library 93 | Unity/ProjectSettings 94 | Unity/Temp 95 | Unity/Packages 96 | Unity/Assets/Debug* 97 | Unity/Assets/Plugins* 98 | Unity/obj 99 | Unity/*.sln 100 | Unity/*.csproj 101 | Unity/.idea 102 | 103 | Unity/Assets/UVee/ 104 | 105 | Unity/Assets/UVee\.meta 106 | # PyCharm Junk 107 | .idea/ 108 | -------------------------------------------------------------------------------- /3DCoat/Scripts/OD_CopyToExternal.txt: -------------------------------------------------------------------------------- 1 | void main() { 2 | 3 | ////////////////////////////////////////////////////////////////////////////// 4 | // CHANGE THIS PATH IF IT IS DIFFERENT TO YOUR DOCUMENTS/3D-COATV47/SCRIPTS // 5 | ////////////////////////////////////////////////////////////////////////////// 6 | 7 | string instPath = installPath(); 8 | string userFolder = homePath(); 9 | string scriptPath = rwPath(userFolder) + "/3D-CoatV47/Scripts"; 10 | 11 | SetFileForFileDialogs("Scripts/1.obj"); 12 | SetModalDialogCallback( "callback" ); 13 | 14 | cmd( "$ApplyUV" ); 15 | cmd( "$EXPORTUV" ); 16 | cmd( "$ExportObject" ); 17 | 18 | string exe = scriptPath + "/objToVertData.exe"; 19 | string args = ""; 20 | Execute(exe, args); 21 | } 22 | 23 | void callback(){ 24 | cmd( "$DialogButton#1" ); 25 | UI ui; 26 | ui( "OK" ); 27 | } -------------------------------------------------------------------------------- /3DCoat/Scripts/OD_PasteFromExternal.txt: -------------------------------------------------------------------------------- 1 | //this is callback for dialog that asks if user needs to save scene after New command 2 | void ModalDialogCallbackDontSave(){ 3 | cmd("$DialogButton#2");/*press Don't save - second button*/ 4 | } 5 | //this is callback to press OK when user is asked to keep scale or not 6 | void ModalDialogCallbackOk(){ 7 | cmd("$DialogButton#1");/*press OK*/ 8 | } 9 | 10 | void main(){ 11 | //This function will call void ForAnyFile(string &in FileName) for each file in user defined folder - stl and obj are just for example 12 | 13 | ////////////////////////////////////////////////////////////////////////////// 14 | // CHANGE THIS PATH IF IT IS DIFFERENT TO YOUR DOCUMENTS/3D-COATV47/SCRIPTS // 15 | ////////////////////////////////////////////////////////////////////////////// 16 | 17 | string instPath = installPath(); 18 | string userFolder = homePath(); 19 | string scriptPath = rwPath(userFolder) + "/3D-CoatV47/Scripts"; 20 | string exe = scriptPath + "/vertDataToObj.exe"; 21 | string args = ""; 22 | Execute(exe, args); 23 | ForAnyFile(scriptPath + "/1.obj"); 24 | } 25 | 26 | void ForAnyFile(string &in FileName){ 27 | //During the New command 3D-Coat will ask what to do with the scene - save or not, this dialog intended to skip it 28 | SetModalDialogCallback("ModalDialogCallbackDontSave"); 29 | cmd("$CLEARSCENE");/*New*/ 30 | //Substitute filename for the next file dialog 31 | SetFileForFileDialogs(FileName); 32 | //Import model for per pixel painting 33 | SetModalDialogCallback("ModalDialogCallbackOk"); 34 | ppp(FileName); 35 | //go to uv room 36 | uv(); 37 | SetFileForFileDialogs(""); 38 | } 39 | -------------------------------------------------------------------------------- /3DCoat/Scripts/ReadMe.txt: -------------------------------------------------------------------------------- 1 | To Install, copy these files into the scripts folder in your 3dCoat documents folder. 2 | Here, it is C:\Users\\Documents\3D-CoatV47\Scripts. Should you not have a 3 | Scripts folder there, just copy the entire folder, otherwise, make a folder, in put the 4 | files in there. 5 | 6 | In 3DCoat, under the scripts tab, select Run Script, and select the two .txt files contained 7 | here. From that point on, they'll show up under the Script Menu and you can use them as is. 8 | 9 | In case the path is DIFFERENT to 3d-CoatV47\scripts, change the path line in the scripts 10 | themselves. There's a line clearly marked, where you can adjust the path (in case of 3D-Coat 11 | version changes, etc.) -------------------------------------------------------------------------------- /3DCoat/Scripts/objToVertData.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/3DCoat/Scripts/objToVertData.exe -------------------------------------------------------------------------------- /3DCoat/Scripts/vertDataToObj.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/3DCoat/Scripts/vertDataToObj.exe -------------------------------------------------------------------------------- /3DSMax/3DSMax_CopyToExternal.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Create a max script file, and this is how you call # 3 | # it in the max script: # 4 | # python.ExecuteFile " # 5 | # example: # 6 | # python.ExecuteFile "C:\Users\Oliver\Desktop\3DSMax_CopyToExternal.py" # 7 | ############################################################################### 8 | # encoding: utf-8 9 | import MaxPlus, tempfile, os 10 | 11 | def writeODMesh(mesh): 12 | 13 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 14 | f = open(file, "w") 15 | f.write("VERTICES:" + str(mesh.GetNumVertices()) + "\n") 16 | for i in xrange(mesh.GetNumVertices()): 17 | f.write(str(mesh.GetVertex(i).GetX()) + " " + str(mesh.GetVertex(i).GetZ()) + " " + str(mesh.GetVertex(i).GetY()*-1) + "\n") 18 | 19 | f.write("POLYGONS:" + str(mesh.GetNumFaces()) + "\n") 20 | for i in xrange(mesh.GetNumFaces()): 21 | #materialID = mesh.GetFace(i).GetMatID() 22 | fpts = [] 23 | for x in xrange(0,3): 24 | face = mesh.GetFace(i) 25 | fpts.append(str(face.GetVert(x))) 26 | fpts = fpts[::-1] 27 | line = ",".join(fpts) 28 | #currently, material name and facetype are hardcoded 29 | line += ";;" + "Default" + ";;" + "FACE" + "\n" 30 | f.write(line) 31 | 32 | f.close() 33 | print "Finished Copy..." 34 | 35 | def main(): 36 | time = MaxPlus.Animation.GetTime() 37 | now = MaxPlus.Core.GetCurrentTime() 38 | triObjectID = MaxPlus.Class_ID(0x0009, 0) 39 | for node in MaxPlus.SelectionManager.Nodes: 40 | obj = node.EvalWorldState(time).Getobj() 41 | print "obj", obj 42 | if (obj.CanConvertToType(triObjectID)): 43 | mesh = MaxPlus.TriObject._CastFrom(obj.ConvertToType(triObjectID, time)).GetMesh() 44 | 45 | if mesh.GetNumVertices() > 0: 46 | writeODMesh(mesh) 47 | else: 48 | print "No Vertices Found, will only work on MeshObjects" 49 | 50 | if __name__ == "__main__": 51 | main() -------------------------------------------------------------------------------- /3DSMax/3DSMax_LaunchCopyToExternal.ms: -------------------------------------------------------------------------------- 1 | python.ExecuteFile "3DSMax_CopyToExternal.py" -------------------------------------------------------------------------------- /3DSMax/3DSMax_LaunchPasteFromExternal.ms: -------------------------------------------------------------------------------- 1 | python.ExecuteFile "3DSMax_PastefromExternal.py" -------------------------------------------------------------------------------- /3DSMax/3DSMax_PastefromExternal.py: -------------------------------------------------------------------------------- 1 | 2 | ############################################################################### 3 | # Create a max script file, and this is how you call # 4 | # it in the max script: # 5 | # python.ExecuteFile " # 6 | # example: # 7 | # python.ExecuteFile "C:\Users\Oliver\Desktop\3DSMax_PastefromExternal.py" # 8 | ############################################################################### 9 | # encoding: utf-8 10 | import MaxPlus, tempfile, os 11 | 12 | def buildODMesh(mesh): 13 | 14 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 15 | 16 | #open the temp file 17 | if os.path.exists(file): 18 | f = open(file) 19 | lines = f.readlines() 20 | f.close() 21 | 22 | vertline = [] 23 | polyline = [] 24 | uvMaps = [] 25 | morphMaps = [] 26 | weightMaps = [] 27 | count = 0 28 | #Parse File to see what Data we have 29 | for line in lines: 30 | if line.startswith("VERTICES:"): 31 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 32 | if line.startswith("POLYGONS:"): 33 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 34 | if line.startswith("UV:"): 35 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 36 | if line.startswith("MORPH"): 37 | morphMaps.append([line.split(":")[1].strip(), count]) 38 | if line.startswith("WEIGHT"): 39 | weightMaps.append([line.split(":")[1].strip(), count]) 40 | count += 1 41 | 42 | #create Points 43 | mesh.SetNumVerts(vertline[0][0]) 44 | for verts in vertline: 45 | points = [] 46 | count = 0 47 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 48 | x = lines[i].split(" ") 49 | pt = [ float(x[0]), float(x[2].strip())*-1, float(x[1].strip()) ] 50 | mesh.SetVert(count, MaxPlus.Point3(pt[0], pt[1], pt[2])) 51 | count += 1 52 | 53 | #need to calculate the amount of faces we are going to have 54 | faces = 0 55 | for polygons in polyline: 56 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 57 | pt = [] 58 | for x in (lines[i].split(";;")[0]).strip().split(","): 59 | pt.append(x.strip()) 60 | if len(pt) > 3: 61 | faces += 2 62 | else: faces += 1 63 | 64 | #create Polygons 65 | mesh.SetNumFaces(faces) 66 | count = 0 67 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 68 | pts = [] 69 | surf = (lines[i].split(";;")[1]).strip() 70 | polytype = (lines[i].split(";;")[2]).strip() 71 | for x in (lines[i].split(";;")[0]).strip().split(","): 72 | pts.insert(0, int(x.strip())) 73 | if len(pts) > 3: 74 | faces += 1 75 | mesh.GetFace(count).SetVerts(pts[0], pts[1], pts[2]) 76 | mesh.GetFace(count).SetEdgeVisFlags(1,1,0) 77 | count += 1 78 | mesh.GetFace(count).SetVerts(pts[2], pts[3], pts[0]) 79 | mesh.GetFace(count).SetEdgeVisFlags(1,1,0) 80 | else: 81 | mesh.GetFace(count).SetVerts(pts[0], pts[1], pts[2]) 82 | mesh.GetFace(count).SetEdgeVisFlags(1,1,0) 83 | count +=1 84 | 85 | def main(): 86 | geom = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.TriMeshGeometry) 87 | tri = MaxPlus.TriObject._CastFrom(geom) 88 | mesh = tri.GetMesh() 89 | buildODMesh(mesh) 90 | node = MaxPlus.Factory.CreateNode(tri) 91 | 92 | if __name__ == "__main__": 93 | main() -------------------------------------------------------------------------------- /Blender/BLENDER_ExportToExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Copy To External", 3 | "version": (1, 0), 4 | "author": "Oliver Hotz", 5 | "description": "Copies current object to clipboard for use in other applications / instances", 6 | "category": "Object" 7 | } 8 | 9 | import bpy, tempfile, os 10 | from mathutils import Vector 11 | 12 | class CopyToExternal(bpy.types.Operator): 13 | """Object Cursor Array""" 14 | bl_idname = "object.copy_to_external" 15 | bl_label = "Copy To External" 16 | bl_options = {'REGISTER', 'UNDO'} 17 | 18 | def execute(self, context): 19 | 20 | def OD_CopyToExternal(_name, size): 21 | 22 | def mesh_to_weight_list(ob, me): 23 | # clear the vert group. 24 | group_names = [g.name for g in ob.vertex_groups] 25 | group_names_tot = len(group_names) 26 | if not group_names_tot: 27 | # no verts? return a vert aligned empty list 28 | return [[] for i in range(len(me.vertices))], [] 29 | else: 30 | weight_ls = [[0.0] * group_names_tot for i in range(len(me.vertices))] 31 | for i, v in enumerate(me.vertices): 32 | for g in v.groups: 33 | # possible weights are out of range 34 | index = g.group 35 | if index < group_names_tot: 36 | weight_ls[i][index] = g.weight 37 | return group_names, weight_ls 38 | 39 | # get active object 40 | obj = bpy.context.active_object 41 | mesh = obj.data 42 | 43 | point_count = len(obj.data.vertices) 44 | poly_count = len(obj.data.polygons) 45 | 46 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 47 | f = open(file, "w") 48 | f.write ("VERTICES:" + str(point_count) + "\n") 49 | 50 | #write Vertices 51 | for vert in obj.data.vertices: 52 | f.write(str(vert.co[0]) + " " + str(vert.co[2]) + " " + str(vert.co[1]*-1) + "\n") 53 | 54 | #write polygons-point connection for poly reconstructions 55 | f.write("POLYGONS:" + str(poly_count) + "\n") 56 | for poly in obj.data.polygons: 57 | surf = "Default" 58 | if len(obj.material_slots)!= 0: 59 | slot = obj.material_slots[poly.material_index] 60 | surf = slot.name 61 | ppoint = "" 62 | polytype = "FACE" 63 | for idx in poly.vertices: 64 | ppoint += "," + str(obj.data.vertices[idx].index) 65 | f.write(ppoint[1:] + ";;" + str(surf) + ";;" + polytype + "\n") 66 | 67 | #write all weights 68 | result1, result2 = mesh_to_weight_list(obj, mesh) 69 | if len(result1[0]) > 0: 70 | count = 0 71 | for weight in result1: 72 | f.write("WEIGHT:" + weight + "\n") 73 | for r in result2: 74 | f.write(str(r[count]) + "\n") 75 | count += 1 76 | 77 | #write all morphs 78 | for keys in bpy.data.shape_keys: 79 | for key in keys.key_blocks[1:]: 80 | f.write("MORPH:" + key.name + "\n") 81 | basis_verts = keys.key_blocks[0].data 82 | for j, kv in enumerate(key.data): 83 | delta = kv.co - basis_verts[j].co 84 | f.write(str(delta[0]) + " " + str(delta[2]) + " " + str(delta[1]*-1) + "\n") 85 | 86 | #UVs 87 | for j, ul in enumerate(mesh.uv_layers): 88 | uv = [] 89 | for poly in mesh.polygons: 90 | for i in poly.loop_indices: 91 | l = mesh.loops[i] 92 | v = mesh.vertices[l.vertex_index] 93 | uv.append([str(ul.data[l.index].uv[0]), str(ul.data[l.index].uv[1]), str(poly.index), str(l.vertex_index) ]) 94 | f.write("UV:" + ul.name + ":" + str(len(uv)) + "\n") 95 | for entry in uv: 96 | f.write(entry[0] + " " + entry[1] + ":PLY:" + entry[2] + ":PNT:" + entry[3] + "\n") 97 | 98 | # call the function 99 | new_mesh = OD_CopyToExternal('ODCopy', 1) 100 | 101 | return {'FINISHED'} 102 | 103 | 104 | def menu_func(self, context): 105 | self.layout.operator(CopyToExternal.bl_idname) 106 | 107 | def register(): 108 | bpy.utils.register_class(CopyToExternal) 109 | bpy.types.VIEW3D_MT_object.append(menu_func) 110 | 111 | def unregister(): 112 | bpy.utils.unregister_class(CopyToExternal) 113 | bpy.types.VIEW3D_MT_object.remove(menu_func) 114 | 115 | if __name__ == "__main__": 116 | register() -------------------------------------------------------------------------------- /Blender/BLENDER_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Paste From External", 3 | "version": (1, 0), 4 | "author": "Oliver Hotz", 5 | "description": "Paste from an external Object of other applications / instances to a current mesh", 6 | "category": "Object" 7 | } 8 | 9 | import bpy, tempfile, os 10 | from mathutils import Vector 11 | import bmesh 12 | 13 | class PasteFromExternal(bpy.types.Operator): 14 | """Object Cursor Array""" 15 | bl_idname = "object.paste_from_external" 16 | bl_label = "Paste From External" 17 | bl_options = {'REGISTER', 'UNDO'} 18 | 19 | def execute(self, context): 20 | 21 | def OD_PasteFromExternal(_name, size): 22 | 23 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 24 | 25 | if os.path.exists(file): 26 | f = open(file) 27 | lines = f.readlines() 28 | f.close() 29 | else: 30 | print("Cannot find file") 31 | 32 | vertline = [] 33 | polyline = [] 34 | uvMaps = [] 35 | morphMaps = [] 36 | weightMaps = [] 37 | count = 0 38 | #Parse File to see what Data we have here 39 | for line in lines: 40 | if line.startswith("VERTICES:"): 41 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 42 | if line.startswith("POLYGONS:"): 43 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 44 | if line.startswith("UV:"): 45 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 46 | if line.startswith("MORPH"): 47 | morphMaps.append([line.split(":")[1].strip(), count]) 48 | if line.startswith("WEIGHT"): 49 | weightMaps.append([line.split(":")[1].strip(), count]) 50 | count += 1 51 | 52 | #create Points 53 | for v in vertline: 54 | verts = [] 55 | for i in range(v[1] + 1, v[1] + v[0] + 1): 56 | x = lines[i].split(" ") 57 | pt = [ float(x[0].strip()), float(x[2].strip())*-1, float(x[1].strip()) ] 58 | verts.append(pt) 59 | 60 | blenderMats = bpy.data.materials[:] 61 | blenderMatsNames = [] 62 | for bm in blenderMats: 63 | blenderMatsNames.append(bm.name) 64 | 65 | for polygons in polyline: 66 | faces = [] 67 | facesMat = [] 68 | objMats = [] 69 | for i in range(polygons[1] + 1, polygons[1] + polygons[0] + 1): 70 | pts = [] 71 | surf = (lines[i].split(";;")[1]).strip() 72 | for x in (lines[i].split(";;")[0]).strip().split(","): 73 | pts.append(int(x.strip())) 74 | faces.append(pts) 75 | if surf not in blenderMatsNames: 76 | blenderMatsNames.append(surf) 77 | bpy.data.materials.new(surf) 78 | #obj.data.materials.append(blenderSurf) 79 | if surf not in objMats: 80 | objMats.append(surf) 81 | facesMat.append(surf) 82 | 83 | #remove old object first 84 | obj = bpy.context.active_object 85 | if obj != None: 86 | me = obj.data 87 | bpy.ops.object.mode_set(mode = 'OBJECT') 88 | facesr = me.polygons 89 | for f in facesr: f.select = 1 90 | bpy.ops.object.mode_set(mode = 'EDIT') 91 | bpy.ops.mesh.delete(type='FACE') 92 | bpy.ops.object.mode_set(mode = 'OBJECT') 93 | mesh = me 94 | mesh.from_pydata(verts, [], faces) 95 | mesh.update() 96 | mesh.update() 97 | else: 98 | # the rest keep like in this example 99 | # here the mesh data is constructed 100 | mesh = bpy.data.meshes.new(_name) 101 | mesh.from_pydata(verts, [], faces) 102 | mesh.update() 103 | mesh.update() 104 | # now generate an object to hold this data 105 | obj = bpy.data.objects.new(_name, mesh) 106 | # link the object to the scene (it is not visible so far!) 107 | bpy.context.scene.objects.link(obj) 108 | 109 | for i in range(len(obj.material_slots)): 110 | bpy.ops.object.material_slot_remove({'object': obj}) 111 | for mat in objMats: 112 | obj.data.materials.append(bpy.data.materials.get(mat)) 113 | 114 | for i in range(len(faces)): 115 | obj.data.polygons[i].material_index = objMats.index(facesMat[i]) 116 | 117 | # create vertex group lookup dictionary for names 118 | vgroup_names = {vgroup.index: vgroup.name for vgroup in obj.vertex_groups} 119 | 120 | # create dictionary of vertex group assignments per vertex 121 | vgroups = {v.index: [vgroup_names[g.group] for g in v.groups] for v in obj.data.vertices} 122 | 123 | for x in obj.vertex_groups: 124 | obj.vertex_groups.remove(x) 125 | 126 | #setup weightmaps 127 | for weightMap in weightMaps: 128 | vg = obj.vertex_groups.new(weightMap[0]) 129 | count = 0 130 | for v in range(len(verts)): 131 | if lines[weightMap[1]+1+count].strip() != "None": 132 | vg.add([v], float(lines[weightMap[1]+1+count].strip()), "ADD") 133 | count += 1 134 | 135 | if obj.data.shape_keys != None: 136 | bpy.ops.object.shape_key_remove(all=True) 137 | 138 | #create Base Shape Key 139 | if len(morphMaps) > 0: 140 | shapeKey = obj.shape_key_add(from_mix=False) 141 | #shapeKey.name = "Base" 142 | for vert in obj.data.vertices: 143 | shapeKey.data[vert.index].co = vert.co 144 | 145 | #Set Morph Map Values 146 | for morphMap in morphMaps: 147 | shapeKey = obj.shape_key_add(from_mix=False) 148 | shapeKey.name = morphMap[0] 149 | count = 0 150 | for vert in obj.data.vertices: 151 | if lines[morphMap[1]+1+count].strip() != "None": 152 | x = float(lines[morphMap[1]+1+count].split(" ")[0]) 153 | y = float(lines[morphMap[1]+1+count].split(" ")[1]) 154 | z = float(lines[morphMap[1]+1+count].split(" ")[2])*-1 155 | newVert = Vector((vert.co[0] + x, vert.co[1] + z, vert.co[2]+y)) 156 | shapeKey.data[vert.index].co = newVert 157 | count += 1 158 | 159 | for x in mesh.uv_textures: 160 | mesh.uv_textures.remove(x) 161 | 162 | for uvMap in uvMaps: 163 | uv = mesh.uv_textures.new(uvMap[0][0]) 164 | bm = bmesh.new() 165 | bm.from_mesh(mesh) 166 | bm.faces.ensure_lookup_table() 167 | uv_layer = bm.loops.layers.uv[uv.name] 168 | 169 | count = 0 170 | for i in range(int(uvMap[0][1])): 171 | line = lines[uvMap[1]+1+count] 172 | split = line.split(":") 173 | if len(split) > 3: #check the format to see if it has a point and poly classifier, determining with that, whether the uv is discontinuous or continuous 174 | face = (bm.faces[int(split[2])].loops[count%(len(bm.faces[int(split[2])].loops))])[uv_layer].uv = [float(split[0].split(" ")[0]), float(split[0].split(" ")[1])] 175 | else: 176 | pass 177 | count +=1 178 | bm.to_mesh(mesh) 179 | 180 | bpy.context.scene.update() 181 | 182 | # return the object to the function caller for further stuff 183 | return obj 184 | 185 | # call the function 186 | new_mesh = OD_PasteFromExternal('ODCopy', 1) 187 | return {'FINISHED'} 188 | 189 | 190 | def menu_func(self, context): 191 | self.layout.operator(PasteFromExternal.bl_idname) 192 | 193 | def register(): 194 | bpy.utils.register_class(PasteFromExternal) 195 | bpy.types.VIEW3D_MT_object.append(menu_func) 196 | 197 | def unregister(): 198 | bpy.utils.unregister_class(PasteFromExternal) 199 | bpy.types.VIEW3D_MT_object.remove(menu_func) 200 | 201 | if __name__ == "__main__": 202 | register() -------------------------------------------------------------------------------- /Blender/Blender280/BLENDER_ExportToExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Copy To External", 3 | "version": (1, 0), 4 | "blender": (2, 80, 0), 5 | "author": "Oliver Hotz", 6 | "description": "Copies current object to clipboard for use in other applications / instances", 7 | "category": "Object" 8 | } 9 | 10 | import bpy, tempfile, os 11 | from mathutils import Vector 12 | 13 | class OD_OT_CopyToExternal(bpy.types.Operator): 14 | """Object Cursor Array""" 15 | bl_idname = "object.copy_to_external" 16 | bl_label = "Copy To External" 17 | bl_options = {'REGISTER', 'UNDO'} 18 | 19 | def execute(self, context): 20 | 21 | def OD_CopyToExternal(_name, size): 22 | 23 | def mesh_to_weight_list(ob, me): 24 | # clear the vert group. 25 | group_names = [g.name for g in ob.vertex_groups] 26 | group_names_tot = len(group_names) 27 | if not group_names_tot: 28 | # no verts? return a vert aligned empty list 29 | return [[] for i in range(len(me.vertices))], [] 30 | else: 31 | weight_ls = [[0.0] * group_names_tot for i in range(len(me.vertices))] 32 | for i, v in enumerate(me.vertices): 33 | for g in v.groups: 34 | # possible weights are out of range 35 | index = g.group 36 | if index < group_names_tot: 37 | weight_ls[i][index] = g.weight 38 | return group_names, weight_ls 39 | 40 | # get active object 41 | obj = bpy.context.active_object 42 | mesh = obj.data 43 | 44 | point_count = len(obj.data.vertices) 45 | poly_count = len(obj.data.polygons) 46 | 47 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 48 | f = open(file, "w") 49 | f.write ("VERTICES:" + str(point_count) + "\n") 50 | 51 | #write Vertices 52 | for vert in obj.data.vertices: 53 | f.write(str(vert.co[0]) + " " + str(vert.co[2]) + " " + str(vert.co[1]*-1) + "\n") 54 | 55 | #write polygons-point connection for poly reconstructions 56 | f.write("POLYGONS:" + str(poly_count) + "\n") 57 | for poly in obj.data.polygons: 58 | surf = "Default" 59 | if len(obj.material_slots)!= 0: 60 | slot = obj.material_slots[poly.material_index] 61 | surf = slot.name 62 | ppoint = "" 63 | polytype = "FACE" 64 | for idx in poly.vertices: 65 | ppoint += "," + str(obj.data.vertices[idx].index) 66 | f.write(ppoint[1:] + ";;" + str(surf) + ";;" + polytype + "\n") 67 | 68 | #write all weights 69 | result1, result2 = mesh_to_weight_list(obj, mesh) 70 | if len(result1[0]) > 0: 71 | count = 0 72 | for weight in result1: 73 | f.write("WEIGHT:" + weight + "\n") 74 | for r in result2: 75 | f.write(str(r[count]) + "\n") 76 | count += 1 77 | 78 | #write all morphs 79 | for keys in bpy.data.shape_keys: 80 | for key in keys.key_blocks[1:]: 81 | f.write("MORPH:" + key.name + "\n") 82 | basis_verts = keys.key_blocks[0].data 83 | for j, kv in enumerate(key.data): 84 | delta = kv.co - basis_verts[j].co 85 | f.write(str(delta[0]) + " " + str(delta[2]) + " " + str(delta[1]*-1) + "\n") 86 | 87 | #UVs 88 | for j, ul in enumerate(mesh.uv_layers): 89 | uv = [] 90 | for poly in mesh.polygons: 91 | for i in poly.loop_indices: 92 | l = mesh.loops[i] 93 | v = mesh.vertices[l.vertex_index] 94 | uv.append([str(ul.data[l.index].uv[0]), str(ul.data[l.index].uv[1]), str(poly.index), str(l.vertex_index) ]) 95 | f.write("UV:" + ul.name + ":" + str(len(uv)) + "\n") 96 | for entry in uv: 97 | f.write(entry[0] + " " + entry[1] + ":PLY:" + entry[2] + ":PNT:" + entry[3] + "\n") 98 | 99 | # call the function 100 | new_mesh = OD_CopyToExternal('ODCopy', 1) 101 | 102 | return {'FINISHED'} 103 | 104 | 105 | def menu_func(self, context): 106 | self.layout.operator(OD_OT_CopyToExternal.bl_idname) 107 | 108 | def register(): 109 | bpy.utils.register_class(OD_OT_CopyToExternal) 110 | bpy.types.VIEW3D_MT_object.append(menu_func) 111 | 112 | def unregister(): 113 | bpy.utils.unregister_class(OD_OT_CopyToExternal) 114 | bpy.types.VIEW3D_MT_object.remove(menu_func) 115 | 116 | if __name__ == "__main__": 117 | register() -------------------------------------------------------------------------------- /Blender/Blender280/BLENDER_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Paste From External", 3 | "version": (1, 0), 4 | "blender": (2, 80, 0), 5 | "author": "Oliver Hotz", 6 | "description": "Paste from an external Object of other applications / instances to a current mesh", 7 | "category": "Object" 8 | } 9 | 10 | import bpy, tempfile, os 11 | from mathutils import Vector 12 | import bmesh 13 | 14 | class OD_OT_PasteFromExternal(bpy.types.Operator): 15 | """Object Cursor Array""" 16 | bl_idname = "object.paste_from_external" 17 | bl_label = "Paste From External" 18 | bl_options = {'REGISTER', 'UNDO'} 19 | 20 | def execute(self, context): 21 | 22 | def OD_PasteFromExternal(_name, size): 23 | 24 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 25 | 26 | if os.path.exists(file): 27 | f = open(file) 28 | lines = f.readlines() 29 | f.close() 30 | else: 31 | print("Cannot find file") 32 | 33 | vertline = [] 34 | polyline = [] 35 | uvMaps = [] 36 | morphMaps = [] 37 | weightMaps = [] 38 | count = 0 39 | #Parse File to see what Data we have here 40 | for line in lines: 41 | if line.startswith("VERTICES:"): 42 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 43 | if line.startswith("POLYGONS:"): 44 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 45 | if line.startswith("UV:"): 46 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 47 | if line.startswith("MORPH"): 48 | morphMaps.append([line.split(":")[1].strip(), count]) 49 | if line.startswith("WEIGHT"): 50 | weightMaps.append([line.split(":")[1].strip(), count]) 51 | count += 1 52 | 53 | #create Points 54 | for v in vertline: 55 | verts = [] 56 | for i in range(v[1] + 1, v[1] + v[0] + 1): 57 | x = lines[i].split(" ") 58 | pt = [ float(x[0].strip()), float(x[2].strip())*-1, float(x[1].strip()) ] 59 | verts.append(pt) 60 | 61 | blenderMats = bpy.data.materials[:] 62 | blenderMatsNames = [] 63 | for bm in blenderMats: 64 | blenderMatsNames.append(bm.name) 65 | 66 | for polygons in polyline: 67 | faces = [] 68 | facesMat = [] 69 | objMats = [] 70 | for i in range(polygons[1] + 1, polygons[1] + polygons[0] + 1): 71 | pts = [] 72 | surf = (lines[i].split(";;")[1]).strip() 73 | for x in (lines[i].split(";;")[0]).strip().split(","): 74 | pts.append(int(x.strip())) 75 | faces.append(pts) 76 | if surf not in blenderMatsNames: 77 | blenderMatsNames.append(surf) 78 | bpy.data.materials.new(surf) 79 | #obj.data.materials.append(blenderSurf) 80 | if surf not in objMats: 81 | objMats.append(surf) 82 | facesMat.append(surf) 83 | 84 | #remove old object first 85 | obj = bpy.context.active_object 86 | if obj != None: 87 | me = obj.data 88 | bpy.ops.object.mode_set(mode = 'OBJECT') 89 | facesr = me.polygons 90 | for f in facesr: f.select = 1 91 | bpy.ops.object.mode_set(mode = 'EDIT') 92 | bpy.ops.mesh.delete(type='FACE') 93 | bpy.ops.object.mode_set(mode = 'OBJECT') 94 | mesh = me 95 | mesh.from_pydata(verts, [], faces) 96 | mesh.update() 97 | mesh.update() 98 | else: 99 | # the rest keep like in this example 100 | # here the mesh data is constructed 101 | mesh = bpy.data.meshes.new(_name) 102 | mesh.from_pydata(verts, [], faces) 103 | mesh.update() 104 | mesh.update() 105 | # now generate an object to hold this data 106 | obj = bpy.data.objects.new(_name, mesh) 107 | # link the object to the scene (it is not visible so far!) 108 | bpy.context.scene.collection.objects.link(obj) 109 | 110 | for i in range(len(obj.material_slots)): 111 | bpy.ops.object.material_slot_remove({'object': obj}) 112 | for mat in objMats: 113 | obj.data.materials.append(bpy.data.materials.get(mat)) 114 | 115 | for i in range(len(faces)): 116 | obj.data.polygons[i].material_index = objMats.index(facesMat[i]) 117 | 118 | # create vertex group lookup dictionary for names 119 | vgroup_names = {vgroup.index: vgroup.name for vgroup in obj.vertex_groups} 120 | 121 | # create dictionary of vertex group assignments per vertex 122 | vgroups = {v.index: [vgroup_names[g.group] for g in v.groups] for v in obj.data.vertices} 123 | 124 | for x in obj.vertex_groups: 125 | obj.vertex_groups.remove(x) 126 | 127 | #setup weightmaps 128 | for weightMap in weightMaps: 129 | vg = obj.vertex_groups.new(weightMap[0]) 130 | count = 0 131 | for v in range(len(verts)): 132 | if lines[weightMap[1]+1+count].strip() != "None": 133 | vg.add([v], float(lines[weightMap[1]+1+count].strip()), "ADD") 134 | count += 1 135 | 136 | if obj.data.shape_keys != None: 137 | bpy.ops.object.shape_key_remove(all=True) 138 | 139 | #create Base Shape Key 140 | if len(morphMaps) > 0: 141 | shapeKey = obj.shape_key_add(from_mix=False) 142 | #shapeKey.name = "Base" 143 | for vert in obj.data.vertices: 144 | shapeKey.data[vert.index].co = vert.co 145 | 146 | #Set Morph Map Values 147 | for morphMap in morphMaps: 148 | shapeKey = obj.shape_key_add(from_mix=False) 149 | shapeKey.name = morphMap[0] 150 | count = 0 151 | for vert in obj.data.vertices: 152 | if lines[morphMap[1]+1+count].strip() != "None": 153 | x = float(lines[morphMap[1]+1+count].split(" ")[0]) 154 | y = float(lines[morphMap[1]+1+count].split(" ")[1]) 155 | z = float(lines[morphMap[1]+1+count].split(" ")[2])*-1 156 | newVert = Vector((vert.co[0] + x, vert.co[1] + z, vert.co[2]+y)) 157 | shapeKey.data[vert.index].co = newVert 158 | count += 1 159 | 160 | for x in mesh.uv_layers: 161 | mesh.uv_layers.remove(x) 162 | 163 | for uvMap in uvMaps: 164 | uv = mesh.uv_layers.new(name=uvMap[0][0]) 165 | bm = bmesh.new() 166 | bm.from_mesh(mesh) 167 | bm.faces.ensure_lookup_table() 168 | uv_layer = bm.loops.layers.uv[uv.name] 169 | 170 | count = 0 171 | for i in range(int(uvMap[0][1])): 172 | line = lines[uvMap[1]+1+count] 173 | split = line.split(":") 174 | if len(split) > 3: #check the format to see if it has a point and poly classifier, determining with that, whether the uv is discontinuous or continuous 175 | face = (bm.faces[int(split[2])].loops[count%(len(bm.faces[int(split[2])].loops))])[uv_layer].uv = [float(split[0].split(" ")[0]), float(split[0].split(" ")[1])] 176 | else: 177 | pass 178 | count +=1 179 | bm.to_mesh(mesh) 180 | 181 | bpy.context.view_layer.update() 182 | 183 | # return the object to the function caller for further stuff 184 | return obj 185 | 186 | # call the function 187 | new_mesh = OD_PasteFromExternal('ODCopy', 1) 188 | return {'FINISHED'} 189 | 190 | 191 | def menu_func(self, context): 192 | self.layout.operator(OD_OT_PasteFromExternal.bl_idname) 193 | 194 | def register(): 195 | bpy.utils.register_class(OD_OT_PasteFromExternal) 196 | bpy.types.VIEW3D_MT_object.append(menu_func) 197 | 198 | def unregister(): 199 | bpy.utils.unregister_class(OD_OT_PasteFromExternal) 200 | bpy.types.VIEW3D_MT_object.remove(menu_func) 201 | 202 | if __name__ == "__main__": 203 | register() -------------------------------------------------------------------------------- /Blender/Blender290/BLENDER_ExportToExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Copy To External", 3 | "version": (1, 0), 4 | "blender": (2, 90, 0), 5 | "author": "Oliver Hotz", 6 | "description": "Copies current object to clipboard for use in other applications / instances", 7 | "category": "Object" 8 | } 9 | 10 | import bpy, tempfile, os 11 | from mathutils import Vector 12 | 13 | class OD_OT_CopyToExternal(bpy.types.Operator): 14 | """Object Cursor Array""" 15 | bl_idname = "object.copy_to_external" 16 | bl_label = "Copy To External" 17 | bl_options = {'REGISTER', 'UNDO'} 18 | 19 | def execute(self, context): 20 | 21 | def OD_CopyToExternal(_name, size): 22 | 23 | def mesh_to_weight_list(ob, me): 24 | # clear the vert group. 25 | group_names = [g.name for g in ob.vertex_groups] 26 | group_names_tot = len(group_names) 27 | if not group_names_tot: 28 | # no verts? return a vert aligned empty list 29 | return [[] for i in range(len(me.vertices))], [] 30 | else: 31 | weight_ls = [[0.0] * group_names_tot for i in range(len(me.vertices))] 32 | for i, v in enumerate(me.vertices): 33 | for g in v.groups: 34 | # possible weights are out of range 35 | index = g.group 36 | if index < group_names_tot: 37 | weight_ls[i][index] = g.weight 38 | return group_names, weight_ls 39 | 40 | # get active object 41 | obj = bpy.context.active_object 42 | mesh = obj.data 43 | 44 | point_count = len(obj.data.vertices) 45 | poly_count = len(obj.data.polygons) 46 | 47 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 48 | f = open(file, "w") 49 | f.write ("VERTICES:" + str(point_count) + "\n") 50 | 51 | #write Vertices 52 | for vert in obj.data.vertices: 53 | f.write(str(vert.co[0]) + " " + str(vert.co[2]) + " " + str(vert.co[1]*-1) + "\n") 54 | 55 | #write polygons-point connection for poly reconstructions 56 | f.write("POLYGONS:" + str(poly_count) + "\n") 57 | for poly in obj.data.polygons: 58 | surf = "Default" 59 | if len(obj.material_slots)!= 0: 60 | slot = obj.material_slots[poly.material_index] 61 | surf = slot.name 62 | ppoint = "" 63 | polytype = "FACE" 64 | for idx in poly.vertices: 65 | ppoint += "," + str(obj.data.vertices[idx].index) 66 | f.write(ppoint[1:] + ";;" + str(surf) + ";;" + polytype + "\n") 67 | 68 | #write all weights 69 | result1, result2 = mesh_to_weight_list(obj, mesh) 70 | if len(result1[0]) > 0: 71 | count = 0 72 | for weight in result1: 73 | f.write("WEIGHT:" + weight + "\n") 74 | for r in result2: 75 | f.write(str(r[count]) + "\n") 76 | count += 1 77 | 78 | #write object morphs 79 | keys = obj.data.shape_keys 80 | for key in keys.key_blocks[1:]: 81 | f.write("MORPH:" + key.name + "\n") 82 | basis_verts = keys.key_blocks[0].data 83 | for j, kv in enumerate(key.data): 84 | delta = kv.co - basis_verts[j].co 85 | f.write(str(delta[0]) + " " + str(delta[2]) + " " + str(delta[1]*-1) + "\n") 86 | 87 | #UVs 88 | for j, ul in enumerate(mesh.uv_layers): 89 | uv = [] 90 | for poly in mesh.polygons: 91 | for i in poly.loop_indices: 92 | l = mesh.loops[i] 93 | v = mesh.vertices[l.vertex_index] 94 | uv.append([str(ul.data[l.index].uv[0]), str(ul.data[l.index].uv[1]), str(poly.index), str(l.vertex_index) ]) 95 | f.write("UV:" + ul.name + ":" + str(len(uv)) + "\n") 96 | for entry in uv: 97 | f.write(entry[0] + " " + entry[1] + ":PLY:" + entry[2] + ":PNT:" + entry[3] + "\n") 98 | 99 | # call the function 100 | new_mesh = OD_CopyToExternal('ODCopy', 1) 101 | 102 | return {'FINISHED'} 103 | 104 | 105 | def menu_func(self, context): 106 | self.layout.operator(OD_OT_CopyToExternal.bl_idname) 107 | 108 | def register(): 109 | bpy.utils.register_class(OD_OT_CopyToExternal) 110 | bpy.types.VIEW3D_MT_object.append(menu_func) 111 | 112 | def unregister(): 113 | bpy.utils.unregister_class(OD_OT_CopyToExternal) 114 | bpy.types.VIEW3D_MT_object.remove(menu_func) 115 | 116 | if __name__ == "__main__": 117 | register() -------------------------------------------------------------------------------- /Blender/Blender290/BLENDER_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Paste From External", 3 | "version": (1, 0), 4 | "blender": (2, 90, 0), 5 | "author": "Oliver Hotz", 6 | "description": "Paste from an external Object of other applications / instances to a current mesh", 7 | "category": "Object" 8 | } 9 | 10 | import bpy, tempfile, os 11 | from mathutils import Vector 12 | import bmesh 13 | 14 | class OD_OT_PasteFromExternal(bpy.types.Operator): 15 | """Object Cursor Array""" 16 | bl_idname = "object.paste_from_external" 17 | bl_label = "Paste From External" 18 | bl_options = {'REGISTER', 'UNDO'} 19 | 20 | def execute(self, context): 21 | 22 | def OD_PasteFromExternal(_name, size): 23 | 24 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 25 | 26 | if os.path.exists(file): 27 | f = open(file) 28 | lines = f.readlines() 29 | f.close() 30 | else: 31 | print("Cannot find file") 32 | 33 | vertline = [] 34 | polyline = [] 35 | uvMaps = [] 36 | morphMaps = [] 37 | weightMaps = [] 38 | count = 0 39 | #Parse File to see what Data we have here 40 | for line in lines: 41 | if line.startswith("VERTICES:"): 42 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 43 | if line.startswith("POLYGONS:"): 44 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 45 | if line.startswith("UV:"): 46 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 47 | if line.startswith("MORPH"): 48 | morphMaps.append([line.split(":")[1].strip(), count]) 49 | if line.startswith("WEIGHT"): 50 | weightMaps.append([line.split(":")[1].strip(), count]) 51 | count += 1 52 | 53 | #create Points 54 | for v in vertline: 55 | verts = [] 56 | for i in range(v[1] + 1, v[1] + v[0] + 1): 57 | x = lines[i].split(" ") 58 | pt = [ float(x[0].strip()), float(x[2].strip())*-1, float(x[1].strip()) ] 59 | verts.append(pt) 60 | 61 | blenderMats = bpy.data.materials[:] 62 | blenderMatsNames = [] 63 | for bm in blenderMats: 64 | blenderMatsNames.append(bm.name) 65 | 66 | for polygons in polyline: 67 | faces = [] 68 | facesMat = [] 69 | objMats = [] 70 | for i in range(polygons[1] + 1, polygons[1] + polygons[0] + 1): 71 | pts = [] 72 | surf = (lines[i].split(";;")[1]).strip() 73 | for x in (lines[i].split(";;")[0]).strip().split(","): 74 | pts.append(int(x.strip())) 75 | faces.append(pts) 76 | if surf not in blenderMatsNames: 77 | blenderMatsNames.append(surf) 78 | bpy.data.materials.new(surf) 79 | #obj.data.materials.append(blenderSurf) 80 | if surf not in objMats: 81 | objMats.append(surf) 82 | facesMat.append(surf) 83 | 84 | #remove old object first 85 | obj = bpy.context.active_object 86 | if obj != None: 87 | me = obj.data 88 | bpy.ops.object.mode_set(mode = 'OBJECT') 89 | facesr = me.polygons 90 | for f in facesr: f.select = 1 91 | bpy.ops.object.mode_set(mode = 'EDIT') 92 | bpy.ops.mesh.delete(type='FACE') 93 | bpy.ops.object.mode_set(mode = 'OBJECT') 94 | mesh = me 95 | mesh.from_pydata(verts, [], faces) 96 | mesh.update() 97 | mesh.update() 98 | else: 99 | # the rest keep like in this example 100 | # here the mesh data is constructed 101 | mesh = bpy.data.meshes.new(_name) 102 | mesh.from_pydata(verts, [], faces) 103 | mesh.update() 104 | mesh.update() 105 | # now generate an object to hold this data 106 | obj = bpy.data.objects.new(_name, mesh) 107 | # link the object to the scene (it is not visible so far!) 108 | bpy.context.scene.collection.objects.link(obj) 109 | 110 | for i in range(len(obj.material_slots)): 111 | bpy.ops.object.material_slot_remove({'object': obj}) 112 | for mat in objMats: 113 | obj.data.materials.append(bpy.data.materials.get(mat)) 114 | 115 | for i in range(len(faces)): 116 | obj.data.polygons[i].material_index = objMats.index(facesMat[i]) 117 | 118 | # create vertex group lookup dictionary for names 119 | vgroup_names = {vgroup.index: vgroup.name for vgroup in obj.vertex_groups} 120 | 121 | # create dictionary of vertex group assignments per vertex 122 | vgroups = {v.index: [vgroup_names[g.group] for g in v.groups] for v in obj.data.vertices} 123 | 124 | for x in obj.vertex_groups: 125 | obj.vertex_groups.remove(x) 126 | 127 | #setup weightmaps 128 | for weightMap in weightMaps: 129 | vg = obj.vertex_groups.new(weightMap[0]) 130 | count = 0 131 | for v in range(len(verts)): 132 | if lines[weightMap[1]+1+count].strip() != "None": 133 | vg.add([v], float(lines[weightMap[1]+1+count].strip()), "ADD") 134 | count += 1 135 | 136 | if obj.data.shape_keys != None: 137 | bpy.ops.object.shape_key_remove(all=True) 138 | 139 | #create Base Shape Key 140 | if len(morphMaps) > 0: 141 | shapeKey = obj.shape_key_add(from_mix=False) 142 | #shapeKey.name = "Base" 143 | for vert in obj.data.vertices: 144 | shapeKey.data[vert.index].co = vert.co 145 | 146 | #Set Morph Map Values 147 | for morphMap in morphMaps: 148 | shapeKey = obj.shape_key_add(from_mix=False) 149 | shapeKey.name = morphMap[0] 150 | count = 0 151 | for vert in obj.data.vertices: 152 | if lines[morphMap[1]+1+count].strip() != "None": 153 | x = float(lines[morphMap[1]+1+count].split(" ")[0]) 154 | y = float(lines[morphMap[1]+1+count].split(" ")[1]) 155 | z = float(lines[morphMap[1]+1+count].split(" ")[2])*-1 156 | newVert = Vector((vert.co[0] + x, vert.co[1] + z, vert.co[2]+y)) 157 | shapeKey.data[vert.index].co = newVert 158 | count += 1 159 | 160 | for x in mesh.uv_layers: 161 | mesh.uv_layers.remove(x) 162 | 163 | for uvMap in uvMaps: 164 | uv = mesh.uv_layers.new(name=uvMap[0][0]) 165 | bm = bmesh.new() 166 | bm.from_mesh(mesh) 167 | bm.faces.ensure_lookup_table() 168 | uv_layer = bm.loops.layers.uv[uv.name] 169 | 170 | count = 0 171 | for i in range(int(uvMap[0][1])): 172 | line = lines[uvMap[1]+1+count] 173 | split = line.split(":") 174 | if len(split) > 3: #check the format to see if it has a point and poly classifier, determining with that, whether the uv is discontinuous or continuous 175 | face = (bm.faces[int(split[2])].loops[count%(len(bm.faces[int(split[2])].loops))])[uv_layer].uv = [float(split[0].split(" ")[0]), float(split[0].split(" ")[1])] 176 | else: 177 | pass 178 | count +=1 179 | bm.to_mesh(mesh) 180 | 181 | bpy.context.view_layer.update() 182 | 183 | # return the object to the function caller for further stuff 184 | return obj 185 | 186 | # call the function 187 | new_mesh = OD_PasteFromExternal('ODCopy', 1) 188 | return {'FINISHED'} 189 | 190 | 191 | def menu_func(self, context): 192 | self.layout.operator(OD_OT_PasteFromExternal.bl_idname) 193 | 194 | def register(): 195 | bpy.utils.register_class(OD_OT_PasteFromExternal) 196 | bpy.types.VIEW3D_MT_object.append(menu_func) 197 | 198 | def unregister(): 199 | bpy.utils.unregister_class(OD_OT_PasteFromExternal) 200 | bpy.types.VIEW3D_MT_object.remove(menu_func) 201 | 202 | if __name__ == "__main__": 203 | register() -------------------------------------------------------------------------------- /Blender/Blender310/BLENDER_ExportToExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Copy To External", 3 | "version": (1, 0), 4 | "blender": (3, 00, 0), 5 | "author": "Oliver Hotz", 6 | "description": "Copies current object to clipboard for use in other applications / instances", 7 | "category": "Object" 8 | } 9 | 10 | import bpy, tempfile, os 11 | from mathutils import Vector 12 | 13 | class OD_OT_CopyToExternal(bpy.types.Operator): 14 | """Object Cursor Array""" 15 | bl_idname = "object.copy_to_external" 16 | bl_label = "Copy To External" 17 | bl_options = {'REGISTER', 'UNDO'} 18 | 19 | def execute(self, context): 20 | 21 | def OD_CopyToExternal(_name, size): 22 | 23 | def mesh_to_weight_list(ob, me): 24 | # clear the vert group. 25 | group_names = [g.name for g in ob.vertex_groups] 26 | group_names_tot = len(group_names) 27 | if not group_names_tot: 28 | # no verts? return a vert aligned empty list 29 | return [[] for i in range(len(me.vertices))], [] 30 | else: 31 | weight_ls = [[0.0] * group_names_tot for i in range(len(me.vertices))] 32 | for i, v in enumerate(me.vertices): 33 | for g in v.groups: 34 | # possible weights are out of range 35 | index = g.group 36 | if index < group_names_tot: 37 | weight_ls[i][index] = g.weight 38 | return group_names, weight_ls 39 | 40 | # get active object 41 | obj = bpy.context.active_object 42 | mesh = obj.data 43 | 44 | point_count = len(obj.data.vertices) 45 | poly_count = len(obj.data.polygons) 46 | 47 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 48 | f = open(file, "w") 49 | f.write ("VERTICES:" + str(point_count) + "\n") 50 | 51 | #write Vertices 52 | for vert in obj.data.vertices: 53 | f.write(str(vert.co[0]) + " " + str(vert.co[2]) + " " + str(vert.co[1]*-1) + "\n") 54 | 55 | #write polygons-point connection for poly reconstructions 56 | f.write("POLYGONS:" + str(poly_count) + "\n") 57 | for poly in obj.data.polygons: 58 | surf = "Default" 59 | if len(obj.material_slots)!= 0: 60 | slot = obj.material_slots[poly.material_index] 61 | surf = slot.name 62 | ppoint = "" 63 | polytype = "FACE" 64 | for idx in poly.vertices: 65 | ppoint += "," + str(obj.data.vertices[idx].index) 66 | f.write(ppoint[1:] + ";;" + str(surf) + ";;" + polytype + "\n") 67 | 68 | #write all weights 69 | result1, result2 = mesh_to_weight_list(obj, mesh) 70 | if len(result1[0]) > 0: 71 | count = 0 72 | for weight in result1: 73 | f.write("WEIGHT:" + weight + "\n") 74 | for r in result2: 75 | f.write(str(r[count]) + "\n") 76 | count += 1 77 | 78 | #write object morphs 79 | keys = obj.data.shape_keys 80 | if keys: 81 | for key in keys.key_blocks[1:]: 82 | f.write("MORPH:" + key.name + "\n") 83 | basis_verts = keys.key_blocks[0].data 84 | for j, kv in enumerate(key.data): 85 | delta = kv.co - basis_verts[j].co 86 | f.write(str(delta[0]) + " " + str(delta[2]) + " " + str(delta[1]*-1) + "\n") 87 | 88 | #UVs 89 | for j, ul in enumerate(mesh.uv_layers): 90 | uv = [] 91 | for poly in mesh.polygons: 92 | for i in poly.loop_indices: 93 | l = mesh.loops[i] 94 | v = mesh.vertices[l.vertex_index] 95 | uv.append([str(ul.data[l.index].uv[0]), str(ul.data[l.index].uv[1]), str(poly.index), str(l.vertex_index) ]) 96 | f.write("UV:" + ul.name + ":" + str(len(uv)) + "\n") 97 | for entry in uv: 98 | f.write(entry[0] + " " + entry[1] + ":PLY:" + entry[2] + ":PNT:" + entry[3] + "\n") 99 | 100 | # call the function 101 | new_mesh = OD_CopyToExternal('ODCopy', 1) 102 | 103 | return {'FINISHED'} 104 | 105 | 106 | def menu_func(self, context): 107 | self.layout.operator(OD_OT_CopyToExternal.bl_idname) 108 | 109 | def register(): 110 | bpy.utils.register_class(OD_OT_CopyToExternal) 111 | bpy.types.VIEW3D_MT_object.append(menu_func) 112 | 113 | def unregister(): 114 | bpy.utils.unregister_class(OD_OT_CopyToExternal) 115 | bpy.types.VIEW3D_MT_object.remove(menu_func) 116 | 117 | if __name__ == "__main__": 118 | register() -------------------------------------------------------------------------------- /Blender/Blender310/BLENDER_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Paste From External", 3 | "version": (1, 0), 4 | "blender": (3, 00, 0), 5 | "author": "Oliver Hotz", 6 | "description": "Paste from an external Object of other applications / instances to a current mesh", 7 | "category": "Object" 8 | } 9 | 10 | import bpy, tempfile, os 11 | from mathutils import Vector 12 | import bmesh 13 | 14 | class OD_OT_PasteFromExternal(bpy.types.Operator): 15 | """Object Cursor Array""" 16 | bl_idname = "object.paste_from_external" 17 | bl_label = "Paste From External" 18 | bl_options = {'REGISTER', 'UNDO'} 19 | 20 | def execute(self, context): 21 | 22 | def OD_PasteFromExternal(_name, size): 23 | 24 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 25 | 26 | if os.path.exists(file): 27 | f = open(file) 28 | lines = f.readlines() 29 | f.close() 30 | else: 31 | print("Cannot find file") 32 | 33 | vertline = [] 34 | polyline = [] 35 | uvMaps = [] 36 | morphMaps = [] 37 | weightMaps = [] 38 | count = 0 39 | #Parse File to see what Data we have here 40 | for line in lines: 41 | if line.startswith("VERTICES:"): 42 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 43 | if line.startswith("POLYGONS:"): 44 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 45 | if line.startswith("UV:"): 46 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 47 | if line.startswith("MORPH"): 48 | morphMaps.append([line.split(":")[1].strip(), count]) 49 | if line.startswith("WEIGHT"): 50 | weightMaps.append([line.split(":")[1].strip(), count]) 51 | count += 1 52 | 53 | #create Points 54 | for v in vertline: 55 | verts = [] 56 | for i in range(v[1] + 1, v[1] + v[0] + 1): 57 | x = lines[i].split(" ") 58 | pt = [ float(x[0].strip()), float(x[2].strip())*-1, float(x[1].strip()) ] 59 | verts.append(pt) 60 | 61 | blenderMats = bpy.data.materials[:] 62 | blenderMatsNames = [] 63 | for bm in blenderMats: 64 | blenderMatsNames.append(bm.name) 65 | 66 | for polygons in polyline: 67 | faces = [] 68 | facesMat = [] 69 | objMats = [] 70 | for i in range(polygons[1] + 1, polygons[1] + polygons[0] + 1): 71 | pts = [] 72 | surf = (lines[i].split(";;")[1]).strip() 73 | for x in (lines[i].split(";;")[0]).strip().split(","): 74 | pts.append(int(x.strip())) 75 | faces.append(pts) 76 | if surf not in blenderMatsNames: 77 | blenderMatsNames.append(surf) 78 | bpy.data.materials.new(surf) 79 | #obj.data.materials.append(blenderSurf) 80 | if surf not in objMats: 81 | objMats.append(surf) 82 | facesMat.append(surf) 83 | 84 | #remove old object first 85 | obj = bpy.context.active_object 86 | if obj != None: 87 | me = obj.data 88 | bpy.ops.object.mode_set(mode = 'OBJECT') 89 | facesr = me.polygons 90 | for f in facesr: f.select = 1 91 | bpy.ops.object.mode_set(mode = 'EDIT') 92 | bpy.ops.mesh.delete(type='FACE') 93 | bpy.ops.object.mode_set(mode = 'OBJECT') 94 | mesh = me 95 | mesh.from_pydata(verts, [], faces) 96 | mesh.update() 97 | mesh.update() 98 | else: 99 | # the rest keep like in this example 100 | # here the mesh data is constructed 101 | mesh = bpy.data.meshes.new(_name) 102 | mesh.from_pydata(verts, [], faces) 103 | mesh.update() 104 | mesh.update() 105 | # now generate an object to hold this data 106 | obj = bpy.data.objects.new(_name, mesh) 107 | # link the object to the scene (it is not visible so far!) 108 | bpy.context.scene.collection.objects.link(obj) 109 | 110 | for i in range(len(obj.material_slots)): 111 | bpy.ops.object.material_slot_remove({'object': obj}) 112 | for mat in objMats: 113 | obj.data.materials.append(bpy.data.materials.get(mat)) 114 | 115 | for i in range(len(faces)): 116 | obj.data.polygons[i].material_index = objMats.index(facesMat[i]) 117 | 118 | # create vertex group lookup dictionary for names 119 | vgroup_names = {vgroup.index: vgroup.name for vgroup in obj.vertex_groups} 120 | 121 | # create dictionary of vertex group assignments per vertex 122 | vgroups = {v.index: [vgroup_names[g.group] for g in v.groups] for v in obj.data.vertices} 123 | 124 | for x in obj.vertex_groups: 125 | obj.vertex_groups.remove(x) 126 | 127 | #setup weightmaps 128 | for weightMap in weightMaps: 129 | vg = obj.vertex_groups.new(weightMap[0]) 130 | count = 0 131 | for v in range(len(verts)): 132 | if lines[weightMap[1]+1+count].strip() != "None": 133 | vg.add([v], float(lines[weightMap[1]+1+count].strip()), "ADD") 134 | count += 1 135 | 136 | if obj.data.shape_keys != None: 137 | bpy.ops.object.shape_key_remove(all=True) 138 | 139 | #create Base Shape Key 140 | if len(morphMaps) > 0: 141 | shapeKey = obj.shape_key_add(from_mix=False) 142 | #shapeKey.name = "Base" 143 | for vert in obj.data.vertices: 144 | shapeKey.data[vert.index].co = vert.co 145 | 146 | #Set Morph Map Values 147 | for morphMap in morphMaps: 148 | shapeKey = obj.shape_key_add(from_mix=False) 149 | shapeKey.name = morphMap[0] 150 | count = 0 151 | for vert in obj.data.vertices: 152 | if lines[morphMap[1]+1+count].strip() != "None": 153 | x = float(lines[morphMap[1]+1+count].split(" ")[0]) 154 | y = float(lines[morphMap[1]+1+count].split(" ")[1]) 155 | z = float(lines[morphMap[1]+1+count].split(" ")[2])*-1 156 | newVert = Vector((vert.co[0] + x, vert.co[1] + z, vert.co[2]+y)) 157 | shapeKey.data[vert.index].co = newVert 158 | count += 1 159 | 160 | for x in mesh.uv_layers: 161 | mesh.uv_layers.remove(x) 162 | 163 | for uvMap in uvMaps: 164 | uv = mesh.uv_layers.new(name=uvMap[0][0]) 165 | bm = bmesh.new() 166 | bm.from_mesh(mesh) 167 | bm.faces.ensure_lookup_table() 168 | uv_layer = bm.loops.layers.uv[uv.name] 169 | 170 | count = 0 171 | for i in range(int(uvMap[0][1])): 172 | line = lines[uvMap[1]+1+count] 173 | split = line.split(":") 174 | if len(split) > 3: #check the format to see if it has a point and poly classifier, determining with that, whether the uv is discontinuous or continuous 175 | face = (bm.faces[int(split[2])].loops[count%(len(bm.faces[int(split[2])].loops))])[uv_layer].uv = [float(split[0].split(" ")[0]), float(split[0].split(" ")[1])] 176 | else: 177 | pass 178 | count +=1 179 | bm.to_mesh(mesh) 180 | 181 | bpy.context.view_layer.update() 182 | 183 | # return the object to the function caller for further stuff 184 | return obj 185 | 186 | # call the function 187 | new_mesh = OD_PasteFromExternal('ODCopy', 1) 188 | return {'FINISHED'} 189 | 190 | 191 | def menu_func(self, context): 192 | self.layout.operator(OD_OT_PasteFromExternal.bl_idname) 193 | 194 | def register(): 195 | bpy.utils.register_class(OD_OT_PasteFromExternal) 196 | bpy.types.VIEW3D_MT_object.append(menu_func) 197 | 198 | def unregister(): 199 | bpy.utils.unregister_class(OD_OT_PasteFromExternal) 200 | bpy.types.VIEW3D_MT_object.remove(menu_func) 201 | 202 | if __name__ == "__main__": 203 | register() -------------------------------------------------------------------------------- /C4D/C4D_CopyToExternal.py: -------------------------------------------------------------------------------- 1 | import c4d 2 | import tempfile, os 3 | from c4d import documents, plugins 4 | #Welcome to the world of Python 5 | 6 | def objToVertData(inputfile): 7 | output = "" 8 | file = open(inputfile, "r") 9 | lines = file.readlines() 10 | file.close() 11 | points = [] 12 | polygons = [] 13 | uvs = [] 14 | vertexnormals = [] 15 | count = 0 16 | for line in lines: 17 | if line.startswith("v "): 18 | points.append(line.strip()[2:]) 19 | if line.startswith("f "): 20 | polygons.append([line.strip()[2:], count]) 21 | if line.startswith("vt "): 22 | uvs.append(line.strip()[2:]) 23 | if line.startswith("vn "): 24 | vertexnormals.append(line.strip()[2:]) 25 | count += 1 26 | 27 | output += "VERTICES:" + str(len(points)) + "\n" 28 | for p in points: 29 | output += p + "\n" 30 | 31 | output += "POLYGONS:" + str(len(polygons)) + "\n" 32 | count = 0 33 | uvinfo = [] 34 | mat = "Default" 35 | for poly in polygons: 36 | pts = poly[0].split(" ") 37 | newpts = [] 38 | #indices in an vertdata start at 0, so we gotta subtract one from each index 39 | for p in pts: 40 | if "/" in p: 41 | newpts.append(str(int(p.split("/")[0]) - 1)) 42 | uvinfo.append([count, int(p.split("/")[1]), int(p.split("/")[0]) - 1]) 43 | else: 44 | newpts.append(str(int(p) - 1)) 45 | count += 1 46 | if "usemtl" in lines[poly[1]-1]: 47 | mat = lines[poly[1]-1].split(" ")[1].strip() 48 | output += ",".join(newpts) + ";;" + mat + ";;FACE\n" 49 | 50 | if len(uvinfo) > 0: 51 | output += "UV:Default:" + str(len(uvinfo)) + "\n" 52 | for info in uvinfo: 53 | output += uvs[info[1]-1][1:] + ":PLY:" + str(info[0]) + ":PNT:" + str(info[2]) + "\n" 54 | 55 | if len(vertexnormals) > 0: 56 | output += "VERTEXNORMALS:" + str(len(vertexnormals)) + "\n" 57 | for normal in vertexnormals: 58 | output += normal + "\n" 59 | 60 | #writing output file 61 | f = open(tempfile.gettempdir() + os.sep + "ODVertexData.txt", "w") 62 | f.write(output) 63 | f.close() 64 | 65 | def main(): 66 | document = c4d.documents.GetActiveDocument() 67 | objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN) 68 | if objs == None: 69 | return 70 | if len(objs) > 1: 71 | return 72 | 73 | # Get a fresh, temporary document with only the selected objects 74 | docTemp = c4d.documents.IsolateObjects(doc, objs) 75 | if docTemp == None: 76 | return 77 | 78 | obj = os.path.dirname(os.path.realpath(__file__)) + os.sep + "1.obj" 79 | 80 | if documents.SaveDocument(docTemp, obj, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, 1030178): 81 | objToVertData(obj) 82 | 83 | if __name__=='__main__': 84 | main() 85 | c4d.EventAdd() -------------------------------------------------------------------------------- /C4D/C4D_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | import c4d 2 | import tempfile, os 3 | from c4d import documents, plugins 4 | #Welcome to the world of Python 5 | 6 | def vertDataToObj(outputfile): 7 | 8 | output = "" 9 | inputfile = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 10 | file = open(inputfile, "r") 11 | lines = file.readlines() 12 | file.close() 13 | 14 | #Parse File to see what Data we have 15 | vertline = []; polyline = []; vtxnormals = []; uvMaps = []; morphMaps = []; weightMaps = [] 16 | count = 0 17 | for line in lines: 18 | if line.startswith("VERTICES:"): 19 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 20 | if line.startswith("POLYGONS:"): 21 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 22 | if line.startswith("VERTEXNORMALS:"): 23 | vtxnormals.append([int(line.strip().split(":")[1].strip()), count]) 24 | if line.startswith("UV:"): 25 | if line.strip().split(":")[1:][1] != "0": 26 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 27 | count += 1 28 | 29 | #write header 30 | output += "o ODVertexData.obj\n" 31 | output += "g default\n" 32 | 33 | #rewrite verts 34 | for verts in vertline: 35 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 36 | x = map(float, lines[i].split()) 37 | output += "v " + str(x[0]) + " " + str(x[1]) + " " + str(x[2]) + "\n" 38 | uvforobj = [] 39 | values = [] 40 | assignment = [] 41 | for uvMap in uvMaps: 42 | count = 0 43 | for i in range(int(uvMap[0][1])): 44 | split = lines[uvMap[1]+1+count].split(":") 45 | if str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1])) not in values: 46 | values.append(str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1]))) 47 | assignment.append(str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1]))) 48 | count +=1 49 | 50 | values.sort() 51 | for val in values: 52 | output += "vt " + val + "\n" 53 | 54 | 55 | for norm in vtxnormals: 56 | for i in xrange(norm[1] + 1, norm[1] + norm[0] + 1): 57 | x = map(float, lines[i].split()) 58 | output += "vn " + str(x[0]) + " " + str(x[1]) + " " + str(x[2]) + "\n" 59 | 60 | #create Polygons 61 | for polygons in polyline: 62 | polys = [] 63 | count = 0 64 | ncount = 0 65 | mat = "" 66 | testnorm = [] 67 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 68 | pts = lines[i].split(";;")[0].split(",") 69 | newpts = [] 70 | #indices in an obj start at 1, so we gotta add one to each index 71 | testpts = [] 72 | testidx = [] 73 | for p in range(len(pts)): 74 | if len(uvMaps) < 1: 75 | newpts.append(str(int(pts[p]) + 1)) 76 | if len(vtxnormals) > 0: 77 | newpts[-1] = str(newpts[-1]) + "//" + str(count+1) 78 | else: 79 | testpts.append(str(int(pts[p])+1)) 80 | testidx.append(str(values.index(assignment[count])+1)) 81 | if len(vtxnormals) > 0: 82 | testnorm.append(count) 83 | count += 1 84 | string = "" 85 | for t in range(len(testpts)): 86 | string += " " + testpts[t] + "/" + testidx[len(testpts)-1-t] 87 | if len(testnorm) > 0: 88 | string += "/" + str(testnorm[ncount]+1) 89 | ncount += 1 90 | if lines[i].split(";;")[1].strip() != mat: 91 | output += "g " + lines[i].split(";;")[1].strip() + "\n" 92 | output += "usemtl " + lines[i].split(";;")[1].strip() + "\n" 93 | #output += "s 1\n" 94 | mat = lines[i].split(";;")[1].strip() 95 | if string != "": 96 | output += "f " + string.strip() + "\n" 97 | else: 98 | output += "f " + " ".join(newpts) + "\n" 99 | 100 | #writing output file 101 | f = open(outputfile, "w") 102 | f.write(output) 103 | f.close() 104 | 105 | def main(): 106 | document = c4d.documents.GetActiveDocument() 107 | obj = os.path.dirname(os.path.realpath(__file__)) + os.sep + "1.obj" 108 | vertDataToObj(obj) 109 | documents.LoadFile(obj) 110 | 111 | if __name__=='__main__': 112 | main() 113 | c4d.EventAdd() -------------------------------------------------------------------------------- /Houdini/Houdini_CopyToExternal.py: -------------------------------------------------------------------------------- 1 | selnode = hou.selectedNodes() 2 | 3 | if len(selnode) != 1: 4 | print ("You need to have a SOP Selected that you want to export.") 5 | else: 6 | for node in hou.selectedNodes(): 7 | selPath = node.path() 8 | sel = selPath.split("/")[-2] 9 | 10 | if len(selPath.split("/")) > 3: 11 | hou.node('obj/'+sel).createNode("python", "ExportScript" ) 12 | hou.node('obj/'+sel+'/ExportScript/').setParms({"python": ''' 13 | # encoding: utf-8 14 | import tempfile, os, random, sys, re 15 | 16 | filePath = tempfile.gettempdir() + os.sep + ".." + os.sep + "ODVertexData.txt" 17 | 18 | node = hou.pwd() 19 | geo = node.geometry() 20 | 21 | if len(geo.points()) > 0: 22 | f = open(filePath, "w") 23 | 24 | f.write("VERTICES:"+str(len(geo.points())) + "\\n") 25 | for point in geo.points(): 26 | pos = point.position() 27 | f.write(str(pos[0]) + " " + str(pos[1]) + " " + str(pos[2]) + "\\n") 28 | 29 | uvs = [] 30 | check = geo.findVertexAttrib("uv") 31 | f.write("POLYGONS:"+str(len(geo.prims())) + "\\n") 32 | count = 0 33 | surfaces = [] 34 | for attr in geo.primAttribs(): 35 | surfaces.append(attr.name()) 36 | for (fid, prim) in enumerate(geo.prims()): 37 | ppoint = "" 38 | for point in reversed(prim.vertices()): 39 | ppoint += "," + str(hou.Vertex.point(point).number()) 40 | if check != None: 41 | uvs.append(str(point.attribValue("uv")[0]) + " " + str(point.attribValue("uv")[1]) + ":PLY:" + str(count) + ":PNT:" + str(hou.Vertex.point(point).number()) + "\\n") 42 | surf = "Default" 43 | for surface in surfaces: 44 | if prim.attribValue(surface) == 1: 45 | surf = surface 46 | break 47 | polytype = "FACE" 48 | 49 | transform = ppoint[1:].split(",") 50 | transform.insert(0, transform[-1]) 51 | transform = transform[:-1] 52 | ppoint = ",".join(transform) 53 | 54 | f.write(ppoint + ";;" + surf + ";;" + polytype + "\\n") 55 | count += 1 56 | 57 | attribs = geo.pointAttribs() 58 | weights = [] 59 | for attrib in attribs: 60 | if attrib.type() == hou.attribType.Point: 61 | if attrib.dataType() == hou.attribData.Float and attrib.size() == 1: 62 | weights.append(attrib.name()) 63 | 64 | if len(weights) > 0: 65 | for wmap in weights: 66 | wmapName = re.sub(r"_..", lambda m: chr(int(m.group()[1:], 16)), wmap) 67 | attrib = wmap 68 | f.write("WEIGHT:" + wmapName + "\\n") 69 | for p in geo.points(): 70 | f.write(str(p.attribValue(wmap))+ "\\n") 71 | 72 | if len(uvs) > 0: 73 | f.write("UV:UVMap:"+ str(len(uvs)) + "\\n") 74 | for uv in uvs: 75 | f.write(uv) 76 | f.close() 77 | '''}) 78 | 79 | hou.node('obj/'+sel).createNode("convert", "ODConvertToPolygon" ) 80 | hou.node('obj/'+sel+'/ODConvertToPolygon/').setInput(0, hou.node(selPath)) 81 | hou.node('obj/'+sel+'/ExportScript/').setInput(0, hou.node('obj/'+sel+'/ODConvertToPolygon/')) 82 | 83 | 84 | #hou.node('obj/'+sel+'/ExportScript/').setInput(0, hou.node(selPath)) 85 | hou.node('obj/'+sel+'/ExportScript/').setDisplayFlag(True) 86 | hou.node('obj/'+sel+'/ExportScript/').setRenderFlag(True) 87 | hou.node('obj/'+sel+'/ExportScript/').setCurrent(1, False) 88 | hou.node('obj/'+sel+'/ExportScript/').cook(force=True, frame_range=(int(hou.frame()),int(hou.frame()))) 89 | hou.node('obj/'+sel+'/ExportScript/').destroy() 90 | hou.node('obj/'+sel+'/ODConvertToPolygon/').destroy() 91 | else: 92 | print ("Need to select at SOP Level") 93 | -------------------------------------------------------------------------------- /Houdini/Houdini_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | import random 2 | offset = random.randint(0, 1000000) 3 | 4 | hou.node('obj/').createNode("geo", 'geoIn'+str(offset)+'', run_init_scripts = False) 5 | hou.node('obj/geoIn'+str(offset)+'/').createNode("python", "ImportScript" ) 6 | hou.node('obj/geoIn'+str(offset)+'/ImportScript/').setParms({"python": ''' 7 | # encoding: utf-8 8 | import tempfile, os, random, sys, re 9 | 10 | filePath = tempfile.gettempdir() + os.sep + ".." + os.sep + "ODVertexData.txt" #this is the temp file where everything is stored 11 | #print filePath 12 | 13 | f = open(filePath, "r") 14 | lines = f.readlines() 15 | f.close() 16 | 17 | node = hou.pwd() 18 | geo = hou.pwd().geometry() 19 | 20 | vertline = []; polyline = []; uvMaps = []; morphMaps = []; weightMaps = [] 21 | 22 | #Parse File to see what Data we have 23 | count = 0 24 | for line in lines: 25 | if line.startswith("VERTICES:"): 26 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 27 | if line.startswith("POLYGONS:"): 28 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 29 | if line.startswith("UV:"): 30 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 31 | if line.startswith("MORPH"): 32 | morphMaps.append([line.split(":")[1].strip(), count]) 33 | if line.startswith("WEIGHT"): 34 | weightMaps.append([line.split(":")[1].strip(), count]) 35 | count += 1 36 | 37 | #Create Points 38 | points = [] 39 | for verts in vertline: 40 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 41 | x = lines[i].split(" ") 42 | pos = [ float(x[0]), float(x[1]), float(x[2].strip()) ] 43 | pt = geo.createPoint() 44 | pt.setPosition(pos) 45 | points.append(pt) 46 | 47 | #create Polygons 48 | surfList = [] 49 | pVertex = [] 50 | ppVertex = {} 51 | for polygons in polyline: 52 | cnt = 0 53 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 54 | pts = [] 55 | surf = (lines[i].split(";;")[1]).strip() 56 | surf = re.sub(r"[^a-zA-Z0-9]", lambda m: "_{:02x}".format(ord(m.group())), surf) 57 | polytype = (lines[i].split(";;")[2]).strip() 58 | for x in (lines[i].split(";;")[0]).strip().split(","): 59 | pts.append(int(x.strip())) 60 | pts.insert(len(pts), pts[0]) 61 | pts.pop(0) 62 | pts = pts[::-1] 63 | poly = geo.createPolygon()#makes the Poly 64 | for p in pts: 65 | ppVertex[str(cnt) + "," + str(p)] = poly.addVertex(points[p]) 66 | if surf not in surfList: 67 | attrGroup = geo.addAttrib(hou.attribType.Prim, surf, 0)#Creates surface attributes 68 | surfList.append(surf) 69 | poly.setAttribValue(surf, (1))#gives it the surface name 70 | cnt += 1 71 | 72 | #Create Weights 73 | for weightMap in weightMaps: 74 | weightMap[0] = re.sub(r"[^a-zA-Z0-9]", lambda m: "_{:02x}".format(ord(m.group())), weightMap[0]) 75 | geo.addAttrib(hou.attribType.Point, weightMap[0], 0.0) 76 | count = 0 77 | for point in points: 78 | if lines[weightMap[1]+1+count].strip() != "None": 79 | point.setAttribValue(weightMap[0], float(lines[weightMap[1]+1+count].strip()))#set point weight 80 | count += 1 81 | 82 | for uvMap in uvMaps: 83 | attrUV = geo.addAttrib(hou.attribType.Vertex, "uv", (0.0, 0.0, 0.0))#Creates UV attributre 84 | count = 0 85 | for i in range(int(uvMap[0][1])): 86 | line = lines[uvMap[1]+1+count] 87 | split = line.split(":") 88 | if len(split) > 3: #check the format to see if it has a point and poly classifier, determining with that, whether the uv is discontinuous or continuous 89 | ppVertex[split[2] + "," + split[4].strip("\\n")].setAttribValue(attrUV, (float(split[0].split(" ")[0]), float(split[0].split(" ")[1]), 1.0))#Adds UV attribute info 90 | #else: 91 | ppVertex[split[2] + "," + split[4].strip("\\n")].setAttribValue(attrUV, (float(split[0].split(" ")[0]), float(split[0].split(" ")[1]), 1.0))#Adds UV attribute info 92 | count +=1 93 | 94 | 95 | '''}) 96 | 97 | hou.node('obj/geoIn'+str(offset)+'/ImportScript/').setHardLocked(1) -------------------------------------------------------------------------------- /Lightwave/Layout_MenuBranch.cfg: -------------------------------------------------------------------------------- 1 | BranchEntry 65536 CopyPasteExternal _ 2 | BranchEntry 3 "Paste From External" Generic_OD_LayoutPasteFromExternal 3 | -------------------------------------------------------------------------------- /Lightwave/Lightwave_Pre_2015/LW_CopyToExternal.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- Mode: Python -*- 3 | # -*- coding: ascii -*- 4 | 5 | __author__ = "Oliver Hotz" 6 | __date__ = "April 27, 2017" 7 | __copyright__ = "" 8 | __version__ = "1.0" 9 | __maintainer__ = "Oliver Hotz" 10 | __email__ = "oliver@origamidigital.com" 11 | __status__ = "Copies / Pastes Objects between various 3d applications" 12 | __lwver__ = "9.6" 13 | 14 | try: 15 | import lwsdk, os, tempfile, sys 16 | except ImportError: 17 | raise Exception("The LightWave Python module could not be loaded.") 18 | 19 | ########################################################################## 20 | # copys current mesh to temporary file for data exchange # 21 | ########################################################################## 22 | 23 | class OD_LWCopyToExternal(lwsdk.ICommandSequence): 24 | def __init__(self, context): 25 | super(OD_LWCopyToExternal, self).__init__() 26 | self.pidx=0 27 | self.poidx=0 28 | self.pointidxmap = {} 29 | self.polyidxmap = {} 30 | 31 | def fast_point_scan(self, point_list, point_id): 32 | point_list.append(point_id) 33 | self.pointidxmap[str(point_id)] = self.pidx 34 | self.pidx+=1 35 | return lwsdk.EDERR_NONE 36 | 37 | def fast_poly_scan(self, poly_list, poly_id): 38 | poly_list.append(poly_id) 39 | self.polyidxmap[str(poly_id)] = self.poidx 40 | self.poidx+=1 41 | return lwsdk.EDERR_NONE 42 | 43 | # LWCommandSequence ----------------------------------- 44 | def process(self, mod_command): 45 | 46 | #deselect any Morph Targets 47 | command = mod_command.lookup(mod_command.data, "SELECTVMAP") 48 | cs_options = lwsdk.marshall_dynavalues(("MORF")) 49 | result = mod_command.execute(mod_command.data, command, cs_options, lwsdk.OPSEL_USER) 50 | 51 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 52 | 53 | #find existing Vmaps 54 | loaded_weight = []; loaded_uv = []; loaded_morph = [] 55 | for u in range(0, lwsdk.LWObjectFuncs().numVMaps( lwsdk.LWVMAP_WGHT )): 56 | loaded_weight.append(lwsdk.LWObjectFuncs().vmapName(lwsdk.LWVMAP_WGHT, u)) 57 | for u in range(0, lwsdk.LWObjectFuncs().numVMaps( lwsdk.LWVMAP_TXUV )): 58 | loaded_uv.append(lwsdk.LWObjectFuncs().vmapName(lwsdk.LWVMAP_TXUV, u)) 59 | for u in range(0, lwsdk.LWObjectFuncs().numVMaps( lwsdk.LWVMAP_MORF )): 60 | loaded_morph.append(lwsdk.LWObjectFuncs().vmapName(lwsdk.LWVMAP_MORF, u)) 61 | 62 | mesh_edit_op = mod_command.editBegin(0, 0, lwsdk.OPLYR_FG) 63 | if not mesh_edit_op: 64 | print >>sys.stderr, 'Failed to engage mesh edit operations!' 65 | return lwsdk.AFUNC_OK 66 | 67 | try: 68 | # Getting Point ID of selected Point 69 | points = [] 70 | edit_op_result = mesh_edit_op.fastPointScan(mesh_edit_op.state, self.fast_point_scan, (points,), lwsdk.OPLYR_FG, 0) 71 | if edit_op_result != lwsdk.EDERR_NONE: 72 | mesh_edit_op.done(mesh_edit_op.state, edit_op_result, 0) 73 | return lwsdk.AFUNC_OK 74 | point_count = len(points) 75 | edit_op_result = lwsdk.EDERR_NONE 76 | 77 | polys = [] 78 | edit_op_result = mesh_edit_op.fastPolyScan(mesh_edit_op.state, self.fast_poly_scan, (polys,), lwsdk.OPLYR_FG, 0) 79 | if edit_op_result != lwsdk.EDERR_NONE: 80 | mesh_edit_op.done(mesh_edit_op.state, edit_op_result, 0) 81 | return lwsdk.AFUNC_OK 82 | poly_count = len(polys) 83 | edit_op_result = lwsdk.EDERR_NONE 84 | 85 | #if there's no points, then we dont need to do anything 86 | if point_count == 0: 87 | lwsdk.LWMessageFuncs().info("No Points.", "") 88 | return lwsdk.AFUNC_OK 89 | 90 | f = open(file, "w") 91 | f.write ("VERTICES:" + str(point_count) + "\n") 92 | 93 | positions = [] 94 | uvMaps = [] 95 | weightMaps = [] 96 | morphMaps = [] 97 | # Filling Position Array for Selected Point 98 | for point in points: 99 | pos = mesh_edit_op.pointPos(mesh_edit_op.state, point) 100 | f.write(str(pos[0]) + " " + str(pos[1]) + " " + str(pos[2]*-1) + "\n") 101 | #write polygons-point connection for poly reconstruction 102 | f.write("POLYGONS:" + str(len(polys)) + "\n") 103 | for poly in polys: 104 | surf = mesh_edit_op.polySurface(mesh_edit_op.state,poly) 105 | ppoint = "" 106 | for point in reversed(mesh_edit_op.polyPoints(mesh_edit_op.state,poly)): 107 | ppoint += "," + str(self.pointidxmap[str(point)]) 108 | polytype = "FACE" 109 | subD = mesh_edit_op.polyType(mesh_edit_op.state, poly)# & lwsdk.LWPOLTYPE_SUBD 110 | if subD == lwsdk.LWPOLTYPE_SUBD: 111 | polytype = "CCSS" 112 | elif subD == lwsdk.LWPOLTYPE_PTCH: 113 | polytype = "SUBD" 114 | f.write(ppoint[1:] + ";;" + surf + ";;" + polytype + "\n") 115 | #grab all weights 116 | for weight in loaded_weight: 117 | mesh_edit_op.vMapSelect(mesh_edit_op.state, weight, lwsdk.LWVMAP_WGHT, 1) 118 | f.write("WEIGHT:" + weight + "\n") 119 | for point in points: 120 | if (mesh_edit_op.pointVGet(mesh_edit_op.state,point)[1]) != None: 121 | f.write(str(mesh_edit_op.pointVGet(mesh_edit_op.state,point)[1]) + "\n") 122 | else: 123 | f.write("0.0\n") 124 | #grab all UVs 125 | for uvs in loaded_uv: 126 | cont = [] 127 | discont = [] 128 | c = 0 129 | #selecting uv map 130 | mesh_edit_op.vMapSelect(mesh_edit_op.state, uvs, lwsdk.LWVMAP_TXUV, 2) 131 | #check whether we are dealing with continuous or discontinous UVs, we have to look at points per poly for this 132 | for poly in polys: 133 | for point in mesh_edit_op.polyPoints(mesh_edit_op.state,poly): 134 | #vpget gets uv coordinates based on point in poly, if that has a value, the uv is discontinuous.. if it doesnt, its continuous. 135 | pInfo = mesh_edit_op.pointVPGet(mesh_edit_op.state,point, poly)[1] 136 | if pInfo != None: #check if discontinous 137 | curPos = [pInfo[0], pInfo[1]] 138 | discont.append([curPos, str(self.polyidxmap[str(poly)]), str(self.pointidxmap[str(point)])]) 139 | c+= 1 140 | else: #otherwise, the uv coordinate is continuous 141 | if mesh_edit_op.pointVGet(mesh_edit_op.state,point)[1] != None: 142 | curPos = [mesh_edit_op.pointVGet(mesh_edit_op.state,point)[1][0], mesh_edit_op.pointVGet(mesh_edit_op.state, point)[1][1]] 143 | cont.append([curPos, str(self.pointidxmap[str(point)])]) 144 | c+= 1 145 | 146 | f.write("UV:" + uvs + ":"+str(c) + "\n") 147 | for uvpos in discont: 148 | f.write(str(uvpos[0][0]) + " " + str(uvpos[0][1]) + ":PLY:" + str(uvpos[1]) + ":PNT:" + str(uvpos[2]) + "\n") 149 | for uvpos in cont: 150 | f.write(str(uvpos[0][0]) + " " + str(uvpos[0][1]) + ":PNT:" + str(uvpos[1]) + "\n") 151 | 152 | #grab all Morphs 153 | for morph in loaded_morph: 154 | mesh_edit_op.vMapSelect(mesh_edit_op.state, morph, lwsdk.LWVMAP_MORF, 3) 155 | f.write("MORPH:" + morph + "\n") 156 | for point in points: 157 | if (mesh_edit_op.pointVGet(mesh_edit_op.state,point)[1]) != None: 158 | ms = mesh_edit_op.pointVGet(mesh_edit_op.state,point)[1] 159 | f.write(str(ms[0]) + " " + str(ms[1]) + " " + str(ms[2]*-1) + "\n") 160 | else: 161 | f.write("None\n") 162 | except: 163 | edit_op_result = lwsdk.EDERR_USERABORT 164 | raise 165 | finally: 166 | mesh_edit_op.done(mesh_edit_op.state, edit_op_result, 0) 167 | 168 | f.close() 169 | 170 | return lwsdk.AFUNC_OK 171 | 172 | 173 | ServerTagInfo_OD_LWCopyToExternal = [ 174 | ( "OD_LWCopyToExternal", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ), 175 | ( "OD_LWCopyToExternal", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH ) 176 | ] 177 | 178 | ServerRecord = { lwsdk.CommandSequenceFactory("OD_LWCopyToExternal", OD_LWCopyToExternal) : ServerTagInfo_OD_LWCopyToExternal } -------------------------------------------------------------------------------- /Lightwave/Lightwave_Pre_2015/LW_LayoutPasteFromExternal.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- Mode: Python -*- 3 | # -*- coding: ascii -*- 4 | 5 | __author__ = "Oliver Hotz" 6 | __date__ = "April 27, 2017" 7 | __copyright__ = "" 8 | __version__ = "1.0" 9 | __maintainer__ = "Oliver Hotz" 10 | __email__ = "oliver@origamidigital.com" 11 | __status__ = "Copies / Pastes Objects between various 3d applications" 12 | __lwver__ = "9.6" 13 | 14 | try: 15 | import lwsdk, os, tempfile, sys 16 | except ImportError: 17 | raise Exception("The LightWave Python module could not be loaded.") 18 | 19 | ################################################################ 20 | # Layout Surface Extraction geometry # 21 | ################################################################ 22 | 23 | class OD_LayoutPasteFromExternal(lwsdk.IGeneric): 24 | def __init__(self, context): 25 | super(OD_LayoutPasteFromExternal, self).__init__() 26 | return 27 | 28 | def process(self, ga): 29 | lwsdk.command('AddNull ODCopy') 30 | lwsdk.command('ModCommand_OD_LWPasteFromExternal Layout') 31 | return lwsdk.AFUNC_OK 32 | 33 | ServerTagInfo_OD_LayoutPasteFromExternal = [ 34 | ( "OD_LayoutPasteFromExternal", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ), 35 | ( "OD_LayoutPasteFromExternal", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH ) 36 | ] 37 | 38 | ServerRecord = { lwsdk.GenericFactory("OD_LayoutPasteFromExternal", OD_LayoutPasteFromExternal) : ServerTagInfo_OD_LayoutPasteFromExternal } -------------------------------------------------------------------------------- /Lightwave/Lightwave_Pre_2015/LW_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- Mode: Python -*- 3 | # -*- coding: ascii -*- 4 | 5 | __author__ = "Oliver Hotz" 6 | __date__ = "April 27, 2017" 7 | __copyright__ = "" 8 | __version__ = "1.0" 9 | __maintainer__ = "Oliver Hotz" 10 | __email__ = "oliver@origamidigital.com" 11 | __status__ = "Copies / Pastes Objects between various 3d applications" 12 | __lwver__ = "11" 13 | 14 | try: 15 | import lwsdk, os, tempfile, sys 16 | except ImportError: 17 | raise Exception("The LightWave Python module could not be loaded.") 18 | 19 | ########################################################################## 20 | # Pastes temporary data exchange file to current layer # 21 | ########################################################################## 22 | 23 | class OD_LWPasteFromExternal(lwsdk.ICommandSequence): 24 | def __init__(self, context): 25 | super(OD_LWPasteFromExternal, self).__init__() 26 | 27 | def fast_point_scan(self, point_list, point_id): 28 | point_list.append(point_id) 29 | return lwsdk.EDERR_NONE 30 | 31 | # LWCommandSequence ----------------------------------- 32 | def process(self, mod_command): 33 | 34 | #get the command arguments (so that we can also run this from layout) 35 | cmd = mod_command.argument.replace('"', '') 36 | 37 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 38 | 39 | #open the temp file 40 | if os.path.exists(file): 41 | f = open(file) 42 | lines = f.readlines() 43 | f.close() 44 | else: 45 | lwsdk.LWMessageFuncs().info("Storage File does not exist. Needs to be created via the Layout CopyTransform counterpart", "") 46 | return 0 47 | 48 | #get the pointcount from the file 49 | pntCount = int(lines[0].split(":")[1].strip()) 50 | 51 | #find existing Vmaps 52 | loaded_weight = []; loaded_uv = []; loaded_morph = [] 53 | for u in range(0, lwsdk.LWObjectFuncs().numVMaps( lwsdk.LWVMAP_WGHT )): 54 | loaded_weight.append(lwsdk.LWObjectFuncs().vmapName(lwsdk.LWVMAP_WGHT, u)) 55 | for u in range(0, lwsdk.LWObjectFuncs().numVMaps( lwsdk.LWVMAP_TXUV )): 56 | loaded_uv.append(lwsdk.LWObjectFuncs().vmapName(lwsdk.LWVMAP_TXUV, u)) 57 | for u in range(0, lwsdk.LWObjectFuncs().numVMaps( lwsdk.LWVMAP_MORF )): 58 | loaded_morph.append(lwsdk.LWObjectFuncs().vmapName(lwsdk.LWVMAP_MORF, u)) 59 | 60 | #check if we are in modeler, if so, clear polys 61 | # if cmd == "": 62 | # #Remove Current mesh from layer 63 | # command = mod_command.lookup(mod_command.data, "CUT") 64 | # result = mod_command.execute(mod_command.data, command, None, lwsdk.OPLYR_FG) 65 | 66 | edit_op_result = lwsdk.EDERR_NONE 67 | mesh_edit_op = mod_command.editBegin(0, 0, lwsdk.OPSEL_USER) 68 | if not mesh_edit_op: 69 | print >>sys.stderr, 'Failed to engage mesh edit operations!' 70 | return lwsdk.AFUNC_OK 71 | 72 | try: 73 | vertline = [] 74 | polyline = [] 75 | uvMaps = [] 76 | morphMaps = [] 77 | weightMaps = [] 78 | count = 0 79 | #Parse File to see what Data we have 80 | for line in lines: 81 | if line.startswith("VERTICES:"): 82 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 83 | if line.startswith("POLYGONS:"): 84 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 85 | if line.startswith("UV:"): 86 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 87 | if line.startswith("MORPH"): 88 | morphMaps.append([line.split(":")[1].strip(), count]) 89 | if line.startswith("WEIGHT"): 90 | weightMaps.append([line.split(":")[1].strip(), count]) 91 | count += 1 92 | #create Points 93 | for verts in vertline: 94 | points = [] 95 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 96 | x = lines[i].split(" ") 97 | pt = [ float(x[0]), float(x[1]), float(x[2].strip())*-1 ] 98 | points.append(mesh_edit_op.addPoint(mesh_edit_op.state, pt)) 99 | #create Polygons 100 | for polygons in polyline: 101 | polys = [] 102 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 103 | pts = [] 104 | surf = (lines[i].split(";;")[1]).strip() 105 | polytype = (lines[i].split(";;")[2]).strip() 106 | for x in (lines[i].split(";;")[0]).strip().split(","): 107 | pts.insert(0, (points[int(x.strip())])) 108 | ptype = lwsdk.LWPOLTYPE_FACE 109 | if polytype == "CCSS": ptype = lwsdk.LWPOLTYPE_SUBD 110 | elif polytype == "SUBD": ptype = lwsdk.LWPOLTYPE_PTCH 111 | polys.append(mesh_edit_op.addPoly(mesh_edit_op.state, ptype, None, surf, pts)) 112 | #setup weightmaps 113 | for weightMap in weightMaps: 114 | mesh_edit_op.vMapSelect(mesh_edit_op.state, weightMap[0], lwsdk.LWVMAP_WGHT, 1) 115 | count = 0 116 | for point in points: 117 | if lines[weightMap[1]+1+count].strip() != "None": 118 | mesh_edit_op.pntVMap(mesh_edit_op.state, point, lwsdk.LWVMAP_WGHT, weightMap[0], [float(lines[weightMap[1]+1+count].strip())]) 119 | count += 1 120 | #Set Morph Map Values 121 | for morphMap in morphMaps: 122 | mesh_edit_op.vMapSelect(mesh_edit_op.state, morphMap[0], lwsdk.LWVMAP_MORF, 3) 123 | count = 0 124 | for point in points: 125 | if lines[morphMap[1]+1+count].strip() != "None": 126 | mesh_edit_op.pntVMap(mesh_edit_op.state, point, lwsdk.LWVMAP_MORF, morphMap[0], [float(lines[morphMap[1]+1+count].split(" ")[0]), float(lines[morphMap[1]+1+count].split(" ")[1]), float(lines[morphMap[1]+1+count].split(" ")[2])*-1]) 127 | count += 1 128 | #Set UV Map Values 129 | for uvMap in uvMaps: 130 | mesh_edit_op.vMapSelect(mesh_edit_op.state, uvMap[0][0], lwsdk.LWVMAP_TXUV, 2) 131 | count = 0 132 | for i in range(int(uvMap[0][1])): 133 | line = lines[uvMap[1]+1+count] 134 | split = line.split(":") 135 | #if len(split) > 3: #check the format to see if it has a point and poly classifier, determining with that, whether the uv is discontinuous or continuous 136 | #mesh_edit_op.pntVPMap(mesh_edit_op.state, points[int(split[4])], polys[int(split[2])], lwsdk.LWVMAP_TXUV, uvMap[0][0], [float(split[0].split(" ")[0]), float(split[0].split(" ")[1])]) 137 | #else: 138 | mesh_edit_op.pntVMap(mesh_edit_op.state, points[int(split[2])], lwsdk.LWVMAP_TXUV, uvMap[0][0], [float(split[0].split(" ")[0]), float(split[0].split(" ")[1])]) 139 | count +=1 140 | 141 | # #remove unused UVMaps 142 | # for m in loaded_uv: 143 | # if m not in str(uvMaps): 144 | # mesh_edit_op.vMapSelect(mesh_edit_op.state, m, lwsdk.LWVMAP_TXUV, 2) 145 | # mesh_edit_op.vMapRemove(mesh_edit_op.state) 146 | 147 | # # #remove unused UVMaps 148 | # for m in loaded_weight: 149 | # if m not in str(weightMaps): 150 | # mesh_edit_op.vMapSelect(mesh_edit_op.state, m, lwsdk.LWVMAP_WGHT, 1) 151 | # mesh_edit_op.vMapRemove(mesh_edit_op.state) 152 | 153 | # # #remove unused UVMaps 154 | # for m in loaded_morph: 155 | # if m not in str(morphMaps): 156 | # mesh_edit_op.vMapSelect(mesh_edit_op.state, m, lwsdk.LWVMAP_MORF, 3) 157 | # mesh_edit_op.vMapRemove(mesh_edit_op.state) 158 | 159 | except: 160 | edit_op_result = lwsdk.EDERR_USERABORT 161 | raise 162 | finally: 163 | mesh_edit_op.done(mesh_edit_op.state, edit_op_result, 0) 164 | 165 | return lwsdk.AFUNC_OK 166 | 167 | ServerTagInfo_OD_LWPasteFromExternal = [ 168 | ( "OD_LWPasteFromExternal", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ), 169 | ( "OD_LWPasteFromExternal", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH ) 170 | ] 171 | 172 | ServerRecord = { lwsdk.CommandSequenceFactory("OD_LWPasteFromExternal", OD_LWPasteFromExternal) : ServerTagInfo_OD_LWPasteFromExternal } -------------------------------------------------------------------------------- /Lightwave/Modeler_MenuBranch.cfg: -------------------------------------------------------------------------------- 1 | BranchEntry 65536 CopyPasteExternal _ 2 | BranchEntry 3 CopyToExternal cmd$OD_LWCopyToExternal 3 | BranchEntry 3 PasteFromExternal cmd$OD_LWPasteFromExternal 4 | -------------------------------------------------------------------------------- /Maya/maya_ExportToExternal.py: -------------------------------------------------------------------------------- 1 | import os 2 | import maya.cmds as cmds 3 | import tempfile 4 | 5 | 6 | def main(): 7 | exportFilename = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 8 | 9 | global exportedObj 10 | 11 | class iobject_def: 12 | name = "" 13 | vertexCount = 0 14 | polyCount = 0 15 | vertices = [] 16 | polys = [] 17 | materials = [] 18 | weightMap = [] 19 | omVertices = [] 20 | loaded_data = [] 21 | 22 | def fn_getObjectData(): 23 | global exportedObj 24 | curSel = cmds.ls(selection=True) 25 | if len(curSel) > 0: 26 | exportedObj.name = curSel[0] 27 | exportedObj.vertexCount = cmds.polyEvaluate(exportedObj.name, vertex=True) 28 | exportedObj.polyCount = cmds.polyEvaluate(exportedObj.name, face=True) 29 | 30 | exportedObj.vertices = [] 31 | exportedObj.polys = [] 32 | exportedObj.weightMap = [] 33 | 34 | for v in range(0, exportedObj.vertexCount - 0, 1): 35 | vStr = exportedObj.name + ".vtx[" + str(v) + "]" 36 | vPos = cmds.xform(vStr, q=True, os=True, translation=True) 37 | exportedObj.vertices.append(vPos) 38 | try: 39 | w = cmds.polyColorPerVertex(vStr, q=True, r=True)[0] 40 | except: 41 | w = -1 42 | 43 | exportedObj.weightMap.append(w) 44 | 45 | for f in range(0, exportedObj.polyCount - 0, 1): 46 | vStr = exportedObj.name + ".f[" + str(f) + "]" 47 | cmds.select(vStr, replace=True) 48 | verts = cmds.polyInfo(fv=True) 49 | vertsTemp = verts[0].split(":") 50 | vertsTemp = vertsTemp[1].split(" ") 51 | vList = [] 52 | for fv in vertsTemp: 53 | if fv.strip() != "": 54 | vList.append(int(fv)) 55 | exportedObj.polys.append(vList) 56 | 57 | cmds.select(curSel, replace=True) 58 | return True 59 | else: 60 | cmds.confirmDialog( 61 | title="Error:", message="No object selected!", button="Ok" 62 | ) 63 | print("Nothing selected!") 64 | return False 65 | 66 | def fn_saveTempObject(): 67 | global exportedObj 68 | 69 | f = open(exportFilename, "w") 70 | sname = cmds.file(q=True, sceneName=True) 71 | 72 | f.write(sname) 73 | f.write("VERTICES:") 74 | f.write(str(exportedObj.vertexCount)) 75 | f.write("\n") 76 | for v in exportedObj.vertices: 77 | f.write(str(v[0]) + " ") 78 | f.write(str(v[1]) + " ") 79 | f.write(str(v[2])) 80 | f.write("\n") 81 | f.write("POLYGONS:" + str(exportedObj.polyCount) + "\n") 82 | 83 | for p in exportedObj.polys: 84 | count = 0 85 | for v in p: 86 | f.write(str(v)) 87 | if count < (len(p) - 1): 88 | f.write(",") 89 | count += 1 90 | polytype = "FACE" 91 | f.write(";;Default;;" + polytype + "\n") 92 | 93 | if exportedObj.weightMap[0] != -1: 94 | f.write("WEIGHT:myweightmap\n") 95 | for w in exportedObj.weightMap: 96 | f.write(str(w) + "\n") 97 | 98 | f.close() 99 | 100 | exportedObj = iobject_def() 101 | objectOK = fn_getObjectData() 102 | if objectOK == True: 103 | fn_saveTempObject() 104 | -------------------------------------------------------------------------------- /Maya/maya_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pymel.core as pm 3 | import maya.cmds as cmds 4 | import tempfile 5 | import maya.OpenMaya as om 6 | 7 | 8 | class IObjectDef: 9 | name = "" 10 | vertexCount = 0 11 | vertexNormalsCount = 0 12 | polyCount = 0 13 | vertices = [] 14 | polys = [] 15 | materials = [] 16 | weightMap = [] 17 | vertexNormals = [] 18 | omVertices = [] 19 | loaded_data = [] 20 | 21 | 22 | def main(): 23 | import_filename = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 24 | import_object_name = "tempObject" 25 | 26 | global imported_object 27 | 28 | def load_object_from_text_file(): 29 | global imported_object 30 | imported_object.loaded_data = [] 31 | if not os.path.exists(import_filename): 32 | print("Cant find file") 33 | cmds.confirmDialog( 34 | title="Error:", 35 | message="Cant find file:\n" + import_filename, 36 | button="Ok", 37 | ) 38 | return False 39 | else: 40 | f = open(import_filename) 41 | imported_object.loaded_data = f.readlines() 42 | f.close() 43 | return True 44 | 45 | def parse_text_data(): 46 | global imported_object 47 | 48 | imported_object.name = "ODCOPY" 49 | 50 | # parse vertices: 51 | imported_object.vertexCount = int( 52 | imported_object.loaded_data[0].split(":")[1].strip() 53 | ) 54 | imported_object.vertices = [] 55 | imported_object.omVertices = [] 56 | 57 | for v in range(1, imported_object.vertexCount + 1, 1): 58 | new_vert_string = imported_object.loaded_data[v].split(" ") 59 | new_vert = [ 60 | float(new_vert_string[0]), 61 | float(new_vert_string[1]), 62 | float(new_vert_string[2].rstrip()), 63 | ] 64 | imported_object.vertices.append(new_vert) 65 | imported_object.omVertices.append( 66 | om.MPoint(new_vert[0], new_vert[1], new_vert[2]) 67 | ) 68 | 69 | # parse polys 70 | 71 | poly_line = -1 72 | count = 0 73 | 74 | for line in imported_object.loaded_data: 75 | if line.startswith("POLYGONS:"): 76 | poly_line = count 77 | break 78 | count += 1 79 | 80 | if poly_line == -1: 81 | cmds.confirmDialog( 82 | title="Error:", 83 | message="Error reading file\nNo polygons found!", 84 | button="Ok", 85 | ) 86 | return False 87 | 88 | imported_object.polyCount = int( 89 | imported_object.loaded_data[poly_line].split(":")[1] 90 | ) 91 | imported_object.polys = [] 92 | imported_object.materials = [] 93 | poly_line += 1 94 | 95 | for p in range(poly_line, poly_line + imported_object.polyCount, 1): 96 | new_poly_string = imported_object.loaded_data[p].split(";")[0].split(",") 97 | new_poly = [] 98 | for vs in new_poly_string: 99 | new_poly.append(int(vs)) 100 | imported_object.polys.append(new_poly) 101 | poly_material = imported_object.loaded_data[p].split(";")[2].rstrip() 102 | imported_object.materials.append(poly_material) 103 | 104 | # parse weights 105 | 106 | imported_object.weights = [] 107 | weight_line = -1 108 | count = 0 109 | 110 | for line in imported_object.loaded_data: 111 | if line.startswith("WEIGHT:"): 112 | weight_line = count 113 | break 114 | count += 1 115 | 116 | if weight_line != -1: 117 | weight_line += 1 118 | for w in range(weight_line, weight_line + imported_object.vertexCount, 1): 119 | new_weight_string = imported_object.loaded_data[w].rstrip() 120 | imported_object.weightMap.append(float(new_weight_string)) 121 | 122 | # Parse Vertex Normal Maps 123 | imported_object.vertexNormals = [] 124 | _count = 0 125 | normal_line = -1 126 | for line in imported_object.loaded_data: 127 | if line.startswith("VERTEXNORMALS:"): 128 | imported_object.vertexNormalsCount = int(line.split(":")[2]) 129 | normal_line = _count 130 | _count += 1 131 | 132 | if normal_line != -1: 133 | normal_line += 1 134 | for n in range( 135 | normal_line, normal_line + imported_object.vertexNormalsCount, 1 136 | ): 137 | values = imported_object.loaded_data[n].rstrip().split(":") 138 | polygon_id = values[2] 139 | vertex_id = values[4] 140 | normal_vector = tuple(float(x) for x in values[0].split(" ")) 141 | imported_object.vertexNormals.append( 142 | [normal_vector, polygon_id, vertex_id] 143 | ) 144 | 145 | return True 146 | 147 | def create_object_openmaya(): 148 | global imported_object 149 | 150 | cmds.select(all=True, hierarchy=True) 151 | current_objs = cmds.ls(selection=True) 152 | 153 | new_mesh = om.MFnMesh() 154 | 155 | merge_vertices = True 156 | point_tolerance = 0.0001 157 | 158 | # create polys 159 | for p in range(0, len(imported_object.polys), 1): 160 | poly_list = [] 161 | v_count = len(imported_object.polys[p]) 162 | poly_list = om.MPointArray() 163 | poly_list.setLength(v_count) 164 | for i in range(v_count): 165 | poly_list.set( 166 | imported_object.omVertices[int(imported_object.polys[p][i])], i 167 | ) 168 | new_mesh.addPolygon(poly_list, merge_vertices, point_tolerance) 169 | 170 | # create weightmaps 171 | if len(imported_object.weightMap) > 0: 172 | for v in range(0, imported_object.vertexCount, 1): 173 | c = imported_object.weightMap[v] 174 | vColor = om.MColor(c, c, c, c) 175 | new_mesh.setVertexColor(vColor, v) 176 | 177 | # Set mesh edits 178 | new_mesh.updateSurface() 179 | 180 | cmds.select(all=True, hierarchy=True) 181 | cmds.select(current_objs, deselect=True) 182 | mesh = pm.selected()[0] 183 | # create vertex normal map 184 | if len(imported_object.vertexNormals) > 0: 185 | for v in range(0, imported_object.vertexNormalsCount, 1): 186 | values = imported_object.vertexNormals[v] 187 | vertex_normal_vector = values[0] 188 | polygon_id = int(values[1]) 189 | vert_id = int(values[2]) 190 | try: 191 | pm.select(mesh.vtxFace[vert_id][polygon_id]) 192 | pm.polyNormalPerVertex(xyz=vertex_normal_vector) 193 | except IndexError, e: 194 | print e 195 | 196 | cmds.select(all=True, hierarchy=True) 197 | cmds.select(current_objs, deselect=True) 198 | new_objs = cmds.ls(selection=True, transforms=True) 199 | cmds.select(new_objs, replace=True) 200 | # cmds.sets(new_objs, e=True, forceElement="initialShadingGroup") 201 | cmds.rotate('90deg', 0, 0, r=True) 202 | pm.general.makeIdentity(apply=True, r=1) 203 | cmds.rename(new_objs, import_object_name) 204 | 205 | imported_object = IObjectDef() 206 | load_success = load_object_from_text_file() 207 | if load_success: 208 | parse_success = parse_text_data() 209 | if parse_success: 210 | create_object_openmaya() 211 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/Modo/Kits/OD_ModoCopyPasteExternal/.DS_Store -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/ModesTailMenu.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OD_CopyPaste 6 | htoolbar 7 | left 8 | icon 9 | small 10 | 11 | 12 | 49.48.51 13 | 14 | 15 | copyPaste 16 | popover 17 | item.create 18 | 93466385120:sheet 19 | 20 | 21 | 22 | copyPaste 23 | popover 24 | htoolbar 25 | OD.modesBar 26 | 27 | COPY 28 | 29 | 30 | PASTE 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/hotkeys.CFG: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 6 | 7 | OD_copyToExternal 8 | OD_pasteFromExternal 9 | 10 | 11 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/icons.CFG: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | kit_OD_ModoCopyPasteExternal:images/icons_20.png 5 | 6 | OD_ModoCopyPasteExternal_icons_med 7 | 0 0 20 20 8 | 9 | 10 | kit_OD_ModoCopyPasteExternal:images/icons_32.png 11 | 12 | OD_ModoCopyPasteExternal_icons_lge 13 | 0 0 32 32 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/images/icons.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/Modo/Kits/OD_ModoCopyPasteExternal/images/icons.psd -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/images/icons_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/Modo/Kits/OD_ModoCopyPasteExternal/images/icons_20.png -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/images/icons_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/Modo/Kits/OD_ModoCopyPasteExternal/images/icons_32.png -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/index.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/lxserv/cmd_copyToExternal.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # cmd_copyToExternal.py 4 | # 5 | # Author: Oliver Hotz | Chris Sprance 6 | # 7 | # Description: Copies Geo/Weights/Morphs/UV's to External File 8 | # 9 | # Last Update: 10 | # 11 | ################################################################################ 12 | 13 | import lx 14 | import lxifc 15 | import lxu.command 16 | from od_copy_paste_external import copy_to_external 17 | 18 | 19 | class ODCopyToExternal(lxu.command.BasicCommand): 20 | 21 | def __init__(self): 22 | lxu.command.BasicCommand.__init__(self) 23 | 24 | def cmd_Flags(self): 25 | return lx.symbol.fCMD_MODEL | lx.symbol.fCMD_UNDO 26 | 27 | def basic_Enable(self, msg): 28 | return True 29 | 30 | def cmd_Interact(self): 31 | pass 32 | 33 | def basic_Execute(self, msg, flags): 34 | # TODO: Disable reload for release 35 | reload(copy_to_external) 36 | copy_to_external.execute() 37 | 38 | def cmd_Query(self, index, vaQuery): 39 | lx.notimpl() 40 | 41 | 42 | lx.bless(ODCopyToExternal, "OD_CopyToExternal") 43 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/lxserv/cmd_pasteFromExternal.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # cmd_pasteFromExternal 4 | # 5 | # Author: Oliver Hotz | Chris Sprance 6 | # 7 | # Description: Pastes Geo/Weights/Morphs/UV's from external file 8 | # 9 | # Last Update: 10 | # 11 | ################################################################################ 12 | 13 | import lx 14 | import lxifc 15 | import lxu.command 16 | from od_copy_paste_external import paste_from_external 17 | 18 | 19 | class ODPasteFromExternal(lxu.command.BasicCommand): 20 | 21 | def __init__(self): 22 | lxu.command.BasicCommand.__init__(self) 23 | 24 | def cmd_Flags(self): 25 | return lx.symbol.fCMD_MODEL | lx.symbol.fCMD_UNDO 26 | 27 | def basic_Enable(self, msg): 28 | return True 29 | 30 | def cmd_Interact(self): 31 | pass 32 | 33 | def basic_Execute(self, msg, flags): 34 | # TODO: Disable reload for release 35 | reload(paste_from_external) 36 | paste_from_external.execute() 37 | 38 | def cmd_Query(self, index, vaQuery): 39 | lx.notimpl() 40 | 41 | 42 | lx.bless(ODPasteFromExternal, "OD_PasteFromExternal") 43 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/od_copy_paste_external/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/Modo/Kits/OD_ModoCopyPasteExternal/od_copy_paste_external/__init__.py -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/od_copy_paste_external/copy_to_external.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # copy_to_external.py 4 | # 5 | # Author: Oliver Hotz | Chris Sprance 6 | # 7 | # Description: Copies Geo/Weights/Morphs/UV's to External File 8 | # 9 | # Last Update: 10 | # 11 | ################################################################################ 12 | import lx 13 | import modo 14 | import tempfile 15 | import os 16 | 17 | 18 | def execute(): 19 | scene = modo.Scene() 20 | # Setup File/path to where we store the temporary Data 21 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 22 | 23 | fusion = 0 24 | replicator = 0 25 | selmeshes = scene.selected 26 | if selmeshes[0].type == "mesh": 27 | selmeshes = selmeshes 28 | elif selmeshes[0].type == "sdf.item": 29 | fusion = 1 30 | # get original name 31 | itemname = selmeshes[0].name 32 | # duplicate meshfusion item 33 | lx.eval("item.duplicate false locator false true") 34 | # select original meshfusion item 35 | scene.select(selmeshes[0]) 36 | # convert original meshfusion item to mesh, as we cannot convert the duplicate 37 | # - creates empty item on duplicate 38 | lx.eval("item.setType mesh sdf.item") 39 | selmeshes = scene.selected 40 | elif selmeshes[0].type == "replicator": 41 | replicator = 1 42 | itemname = selmeshes[0].name 43 | lx.eval("item.duplicate false locator false true") 44 | new = scene.selected 45 | # freeze Replicators 46 | lx.eval("replicator.freeze") 47 | # select whole Hierarchy 48 | scene.select(new[0].name + " (2)") 49 | lx.eval("select.itemHierarchy") 50 | # convert to mesh 51 | lx.eval("item.setType mesh locator") 52 | lx.eval("layer.mergeMeshes true") 53 | selmeshes = scene.selected 54 | 55 | if len(selmeshes) > 0: 56 | mesh = selmeshes[0] 57 | geo = mesh.geometry 58 | 59 | # Deselect all Morphs 60 | lx.eval("vertMap.list morf _____n_o_n_e_____") 61 | 62 | if len(geo.vertices) > 0: 63 | f = open(file, "w") 64 | # write Header 65 | f.write("VERTICES:" + str(len(geo.vertices)) + "\n") 66 | # Write Point/Vertex Position 67 | points = [] 68 | for i in range(len(geo.vertices)): 69 | pos = geo.vertices[i].position 70 | points.append(geo.vertices[i]) 71 | f.write(str(pos[0]) + " " + str(pos[1]) + " " + str(pos[2] * 1) + "\n") 72 | 73 | # Write Polygons 74 | f.write("POLYGONS:" + str(len(geo.polygons)) + "\n") 75 | for p in range(len(geo.polygons)): 76 | surf = geo.polygons[p].materialTag 77 | ptype = geo.polygons[p].Type() 78 | polytype = "FACE" 79 | if ptype == lx.symbol.iPTYP_PSUB: 80 | polytype = "CCSS" 81 | elif ptype == lx.symbol.iPTYP_SUBD: 82 | polytype = "SUBD" 83 | 84 | ppoint = "" 85 | for vert in geo.polygons[p].vertices: 86 | ppoint += "," + str(vert.index) 87 | f.write(ppoint[1:] + ";;" + surf + ";;" + polytype + "\n") 88 | 89 | # WeightMaps: 90 | weightMaps = mesh.geometry.vmaps.weightMaps 91 | for weightMap in weightMaps: 92 | f.write("WEIGHT:" + weightMap.name + "\n") 93 | for i in range(len(geo.vertices)): 94 | weight = weightMap[i] 95 | if weight != None: 96 | f.write(str(weight[0]) + "\n") 97 | else: 98 | f.write("None\n") 99 | 100 | # MorphMaps 101 | morphMaps = mesh.geometry.vmaps.morphMaps 102 | for morphMap in morphMaps: 103 | f.write("MORPH:" + morphMap.name + "\n") 104 | for i in range(len(geo.vertices)): 105 | morph = morphMap[i] 106 | if morph != None: 107 | f.write( 108 | str(morph[0]) 109 | + " " 110 | + str(morph[1]) 111 | + " " 112 | + str(morph[2]) 113 | + "\n" 114 | ) 115 | else: 116 | f.write("None\n") 117 | 118 | # UVMaps 119 | uvMaps = mesh.geometry.vmaps.uvMaps 120 | for uvMap in uvMaps: 121 | uvs = [] 122 | for p in range(len(geo.polygons)): 123 | for vert in geo.polygons[p].vertices: 124 | uvs.append([geo.polygons[p].getUV(vert, uvMap), p, vert.index]) 125 | f.write("UV:" + uvMap.name + ":" + str(len(uvs)) + "\n") 126 | for uv in uvs: 127 | f.write( 128 | str(uv[0][0]) 129 | + " " 130 | + str(uv[0][1]) 131 | + ":PLY:" 132 | + str(uv[1]) 133 | + ":PNT:" 134 | + str(uv[2]) 135 | + "\n" 136 | ) 137 | 138 | # vertex Normal 139 | vertexnormals = [] 140 | for p in range(len(geo.polygons)): 141 | for index, vert in enumerate(geo.polygons[p].vertices): 142 | vertexnormals.append( 143 | [geo.polygons[p].vertexNormal(index), p, vert.index] 144 | ) 145 | f.write( 146 | "VERTEXNORMALS:" 147 | + str('VertexNormals') 148 | + ":" 149 | + str(len(vertexnormals)) 150 | + "\n" 151 | ) 152 | for normal in vertexnormals: 153 | f.write( 154 | str(normal[0][0]) 155 | + " " 156 | + str(normal[0][1]) 157 | + " " 158 | + str(normal[0][2]) 159 | + ":PLY:" 160 | + str(normal[1]) 161 | + ":PNT:" 162 | + str(normal[2]) 163 | + "\n" 164 | ) 165 | 166 | # close File 167 | f.close() 168 | else: 169 | modo.dialogs.alert( 170 | "No Mesh Selected", 171 | "You need to select the mesh Item you want to copy", 172 | "info", 173 | ) 174 | 175 | if fusion == 1 or replicator == 1: 176 | # delete converted item 177 | scene.removeItems(scene.selected[0]) 178 | # select the duplicated meshfusion item 179 | x = scene.select(itemname) 180 | # change name of of the duplicate to the original meshfusion name 181 | scene.selected[0].SetName(itemname) 182 | -------------------------------------------------------------------------------- /Modo/Kits/OD_ModoCopyPasteExternal/od_copy_paste_external/paste_from_external.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # paste_from_external.py 4 | # 5 | # Author: Oliver Hotz | Chris Sprance 6 | # 7 | # Description: Pastes Geo/Weights/Morphs/UV's from external file 8 | # 9 | # Last Update: 10 | # 11 | ################################################################################ 12 | import lx 13 | import modo 14 | import tempfile 15 | import os 16 | 17 | 18 | def execute(): 19 | scene = modo.Scene() 20 | # Read temporary Data File 21 | od_data_file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 22 | if os.path.exists(od_data_file): 23 | f = open(od_data_file, "r") 24 | lines = f.readlines() 25 | f.close() 26 | up_axis = {0: "x", 1: "y", 2: "z"}[scene.sceneItem.channel("upAxis").get()] 27 | vert_line = [] 28 | poly_line = [] 29 | uv_maps = [] 30 | morph_maps = [] 31 | weight_maps = [] 32 | vertex_normals = [] 33 | count = 0 34 | # Parse File to see what Data we have 35 | for line in lines: 36 | if line.startswith("VERTICES:"): 37 | vert_line.append([int(line.strip().split(":")[1].strip()), count]) 38 | if line.startswith("POLYGONS:"): 39 | poly_line.append([int(line.strip().split(":")[1].strip()), count]) 40 | if line.startswith("UV:"): 41 | uv_maps.append( 42 | [line.strip().split(":")[1:], count] 43 | ) # changed this to add the # of uv coordinates into the mix 44 | if line.startswith("MORPH"): 45 | morph_maps.append([line.split(":")[1].strip(), count]) 46 | if line.startswith("WEIGHT"): 47 | weight_maps.append([line.split(":")[1].strip(), count]) 48 | if line.startswith("VERTEXNORMALS"): 49 | vertex_normals.append([line.split(":")[1].strip(), count]) 50 | count += 1 51 | 52 | # Add a new mesh object to the scene and grab the geometry object 53 | mesh = scene.selectedByType("mesh") 54 | if mesh: 55 | mesh = mesh[0] 56 | if len(mesh.geometry.vertices) > 0: 57 | mesh.geometry.internalMesh.Clear() 58 | else: 59 | mesh = scene.addMesh("ODCopy") 60 | 61 | # select new empty mesh 62 | scene.select(mesh) 63 | geo = mesh.geometry 64 | 65 | # generate points 66 | for verts in vert_line: 67 | points = [] 68 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 69 | x = lines[i].split(" ") 70 | points.append( 71 | geo.vertices.new((float(x[0]), float(x[1]), float(x[2].strip()))) 72 | ) 73 | 74 | # Query Existing Materials 75 | all_surfaces = [] 76 | for material in scene.items("advancedMaterial"): 77 | all_surfaces.append(material.name) 78 | 79 | # generate Polys from the Points and assign materials 80 | for polygons in poly_line: 81 | polys = [] 82 | count = 0 83 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 84 | pts = [] 85 | surf = (lines[i].split(";;")[1]).strip() 86 | ptch = (lines[i].split(";;")[2]).strip() 87 | if surf not in all_surfaces: 88 | all_surfaces.append(surf) 89 | scene.addMaterial(name=surf) 90 | for x in (lines[i].split(";;")[0]).strip().split(","): 91 | pts.append(int(x.strip())) 92 | ptype = lx.symbol.iPTYP_FACE 93 | if ptch == "CCSS": 94 | ptype = lx.symbol.iPTYP_PSUB 95 | elif ptch == "SUBD": 96 | ptype = lx.symbol.iPTYP_SUBD 97 | geo.polygons.new(vertices=(pts), reversed=False, polyType=ptype) 98 | geo.polygons[count].materialTag = surf 99 | count += 1 100 | 101 | # Apply Weights 102 | for weight_map in weight_maps: 103 | weight = geo.vmaps.addMap(lx.symbol.i_VMAP_WEIGHT, weight_map[0]) 104 | for i in range(len(geo.vertices)): 105 | if lines[weight_map[1] + 1 + i].strip() != "None": 106 | weight[i] = float(lines[weight_map[1] + 1 + i].strip()) 107 | 108 | # Apply Morphs 109 | for morph_map in morph_maps: 110 | mo = geo.vmaps.addMorphMap(morph_map[0], False) 111 | for i in range(len(geo.vertices)): 112 | if lines[morph_map[1] + 1 + i].strip() != "None": 113 | mo.setAbsolutePosition( 114 | i, 115 | [ 116 | float(lines[i + 1].split(" ")[0]) 117 | + float(lines[morph_map[1] + 1 + i].split(" ")[0]), 118 | float(lines[i + 1].split(" ")[1]) 119 | + float(lines[morph_map[1] + 1 + i].split(" ")[1]), 120 | float(lines[i + 1].split(" ")[2]) 121 | + float(lines[morph_map[1] + 1 + i].split(" ")[2]), 122 | ], 123 | ) 124 | 125 | # Apply UV Maps 126 | for uv_map in uv_maps: 127 | uvm = geo.vmaps.addMap(lx.symbol.i_VMAP_TEXTUREUV, uv_map[0][0]) 128 | count = 0 129 | for i in range(int(uv_map[0][1])): 130 | line = lines[uv_map[1] + 1 + count] 131 | split = line.split(":") 132 | # check the format to see if it has a point and poly classifier, 133 | # determining with that, whether the uv is discontinuous or continuous 134 | if len(split) > 3: 135 | geo.polygons[int(split[2])].setUV( 136 | (float(split[0].split(" ")[0]), float(split[0].split(" ")[1])), 137 | geo.vertices[int(split[4])], 138 | uvm, 139 | ) 140 | else: 141 | pass 142 | count += 1 143 | 144 | # Apply Vertex Normals 145 | for vertex_normal in vertex_normals: 146 | normals = geo.vmaps.addVertexNormalMap(vertex_normal[0]) 147 | line_number_start = vertex_normal[1] 148 | for i in range(int(lines[line_number_start].split(":")[2])): 149 | values = lines[line_number_start + 1 + i].split(":") 150 | normal_value = tuple(float(x) for x in values[0].split(" ")) 151 | polygon = modo.MeshPolygon(int(values[2]), geo) 152 | for i in range(polygon.numVertices): 153 | vert_number = int(values[4].replace("\n", "")) 154 | normals.setNormal( 155 | normal_value, modo.MeshVertex(vert_number, geo), polygon 156 | ) 157 | 158 | geo.setMeshEdits() 159 | vertex_normal_maps = mesh.geometry.vmaps.getMapsByType(lx.symbol.i_VMAP_NORMAL) 160 | lx.eval('select.vertexMap "%s" norm replace' % vertex_normal_maps[0].name) 161 | lx.eval("vertMap.convertToHardEdge false") 162 | else: 163 | print("No Data File Available.") 164 | -------------------------------------------------------------------------------- /Moi3D/ODCopyToExternal.js: -------------------------------------------------------------------------------- 1 | var comPath = moi.filesystem.getCommandsDir(); 2 | var obj = comPath + "1.obj"; 3 | //Export 4 | moi.geometryDatabase.fileExport( obj, 'NoUI=true' ); //also try: Output=ngons | quads | triangles 5 | //use external app to convert to vertdata 6 | moi.filesystem.shellExecute( comPath + "objToVertData.exe"); 7 | -------------------------------------------------------------------------------- /Moi3D/ODPasteFromExternal.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | -------------------------------------------------------------------------------- /Moi3D/ODPasteFromExternal.js: -------------------------------------------------------------------------------- 1 | var vertices=[], faces=[], max={ x:-100000, y:-100000, z:-100000 }, min={ x:100000, y:100000, z:100000 }, objName, errors=0, scale, normalize, faceobj = moi.geometryDatabase.createObjectList(); 2 | function cleanSpaces(str) { return str.replace(/^\s+|\s+$/g, '').replace(/ +(?= )/g,'')}; 3 | function loadObj( objPath ) 4 | { 5 | var objFile = moi.filesystem.openFileStream( objPath, 'r' ), x, y, z; 6 | while ( !objFile.AtEOF ) 7 | { 8 | var nextLine = cleanSpaces(objFile.readLine()).split(' '); 9 | if ( nextLine[0] === "v" ) 10 | { 11 | x = nextLine[1]*1; y = -nextLine[3]*1; z = nextLine[2]*1; 12 | if (xmax.x){ max.x=x; } if (y>max.y){ max.y=y; } if (z>max.z) { max.z=z; } 14 | vertices.push({x:x, y:y, z:z}); 15 | } 16 | if ( nextLine[0] === "f" ) faces.push(nextLine); 17 | } 18 | objFile.close(); 19 | objName = moi.filesystem.getFileNameFromPath(objPath); 20 | objName = objName.substr(0, objName.lastIndexOf('.')); 21 | } 22 | 23 | function normalizeObj (norm) 24 | { 25 | normalize = norm; 26 | scale = 200/(max.x-min.x+max.y-min.y+max.z-min.z)/3 27 | var scalelog = Math.pow(10, Math.round(Math.log(scale)/Math.log(10))); 28 | if (scalelog>1) { scalelog /=10 } 29 | scale = Math.round(scale/scalelog)*scalelog; 30 | if (scale == 0) scale = scalelog; 31 | if ( !normalize && scale<1 ) scale=1; 32 | scale *=100; 33 | if ( !normalize ) for ( v in vertices ) vertices[v] = moi.VectorMath.createPoint(vertices[v].x*scale, vertices[v].y*scale, vertices[v].z*scale); 34 | if ( normalize ) for ( v in vertices ) vertices[v] = moi.VectorMath.createPoint((vertices[v].x-max.x/2-min.x/2)*scale, (vertices[v].y-max.y/2-min.y/2)*scale, (vertices[v].z-min.z)*scale); 35 | scale /=100; 36 | } 37 | 38 | function processObj(startPos, endPos) 39 | { 40 | var lineF = moi.command.createFactory( 'line' ), lineV; 41 | var loftF = moi.command.createFactory( 'loft' ), loftV; 42 | var planarF = moi.command.createFactory( 'planarsrf' ), planarV; 43 | for ( var f=startPos; f 4 ) 49 | { 50 | for (var i=0; i < flen; i++) 51 | { 52 | lineF.setInput( 0, vertices[face[i]]); 53 | lineF.setInput( 1, vertices[face[(i+1)%flen]]); 54 | lineV=lineF.calculate(); 55 | edges.addObject(lineV.item(0)); 56 | } 57 | planarF.setInput( 0, edges ); 58 | planarV=planarF.calculate(); 59 | if ( planarV.length > 0 ) { faceobj.addObject(planarV.item(0)) } else { errors++ } 60 | } 61 | else if ( flen ==3 || flen == 4 ) 62 | { 63 | var sPt = 0, maxLength = 0, cLength=0, nPt; 64 | for (var i = 0; i maxLength ) { maxLength = cLength; sPt = i; } 69 | } 70 | lineF.setInput( 0, vertices[face[sPt]]); lineF.setInput( 1, vertices[face[(sPt+1)%flen]]); lineV=lineF.calculate(); edges.addObject(lineV.item(0)); 71 | lineF.setInput( 0, vertices[face[(sPt+3)%flen]]); lineF.setInput( 1, vertices[face[(sPt+2)%flen]]); lineV=lineF.calculate(); edges.addObject(lineV.item(0)); 72 | loftF.setInput( 0, edges); 73 | loftV = loftF.calculate(); 74 | if (loftV.length>0) { faceobj.addObject(loftV.item(0)) } else { errors++ } 75 | } else { errors++ } 76 | } 77 | } 78 | 79 | function showObj() 80 | { 81 | var scale3d = moi.command.createFactory( 'scale' ); 82 | scale3d.setInput( 0, faceobj ); 83 | scale3d.setInput( 1, moi.VectorMath.createPoint(0,0,0) ); 84 | scale3d.setInput( 2, (normalize)?1/100:0.01/scale ); 85 | faceobj=scale3d.calculate(); 86 | 87 | moi.geometryDatabase.addObjects(faceobj); 88 | if ( normalize ) if (scale > 1) { objName = objName + " ["+scale+":1]" } else if (scale < 1) { objName = objName + " [1:"+Math.round(100/scale)/100+"]" } 89 | if (errors>0) objName = objName + " err:"+errors; 90 | faceobj.setProperty( 'name', objName); 91 | } 92 | function joinObj(joinmax) 93 | { 94 | if (faceobj.length>joinmax) return; 95 | var joinF=moi.command.createFactory( 'join' ); 96 | joinF.setInput(0, faceobj); 97 | joinF.commit(); 98 | } 99 | 100 | var comPath = moi.filesystem.getCommandsDir(); 101 | var obj = comPath + "1.obj"; 102 | //Export 103 | moi.filesystem.shellExecute( comPath + "vertDataToObj.exe"); 104 | moi.ui.commandUI.progressinfo.innerHTML="Loading"; 105 | loadObj( obj ); 106 | moi.ui.commandUI.progressinfo.innerHTML="Normalizing"; 107 | var facesnum = faces.length; 108 | if ( moi.command.getCommandLineParams() ==='exact' ) { normalizeObj( false ) } else { normalizeObj( true ) } 109 | var cstart = 0, cend=0, cstep = 2000; 110 | do { cend = (cend+cstep>facesnum)?facesnum:cend+cstep; 111 | moi.ui.commandUI.progressinfo.innerHTML="Processing ("+cstart+"/"+facesnum+")
Press ESC to abort"; 112 | processObj(cstart, cend); 113 | cstart +=cstep; 114 | } while (cendLW-Modo Usage 179 | 180 | Pedro Alpiarça dos Santos has provided a Youtube Video showing the use between Houdini, Blender and Lightwave. 181 | 182 | Houdini-Blender-Lightwave Usage 185 | 186 | Steve Gilbert has provided a Youtube Video showing the use between 3DSMax and Blender. 187 | 188 | 3DSMax-Blender Usage 191 | 192 | # TODO: 193 | 194 | * Houdini: figure out how to get Morphs/Blendshapes integrated 195 | * Maya: figure out how to get Morphs/Blendshapes integrated 196 | * Cinema4d: C Implementation (currently only python (vertices,polys,uvs supported)) 197 | * 3DsMax: Initial Implementation as sample is complete 198 | * Sketchup: Add Copy To and finesse Paste implementation 199 | * Unreal: R&D to see if its possible to implement 200 | * Unity: Initial Implmenetaiton complete, see what else is possible 201 | * Mari: R&D to see if its possible to implement 202 | * Nuke: R&D to see if its possible to implement 203 | -------------------------------------------------------------------------------- /Rhino/Rhino_CopyToExternal.py: -------------------------------------------------------------------------------- 1 | import Rhino, tempfile, os 2 | import rhinoscriptsyntax as rs 3 | 4 | def exportODMesh(): 5 | 6 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 7 | 8 | obj = rs.GetObject("Select mesh", rs.filter.mesh, True) 9 | vertices = rs.MeshVertices(obj) 10 | faces = rs.MeshFaceVertices(obj) 11 | 12 | f = open(file, "w") 13 | 14 | f.write("VERTICES:" + str(len(vertices))+"\n") 15 | for vert in vertices: 16 | f.write(str(vert[0]) + " " + str(vert[2]) + " " + str(vert[1]*-1) + "\n") 17 | 18 | f.write("POLYGONS:" + str(len(faces)) + "\n") 19 | for face in faces: 20 | fpt = [] 21 | for p in face: 22 | if str(p) not in fpt: #need this check as when there's 3pt polys somehow, it gives 4 points 23 | fpt.append(str(p)) 24 | line = ",".join(fpt) 25 | line += ";;" + "Default" + ";;" + "FACE" + "\n" 26 | f.write(line) 27 | f.close() 28 | 29 | if __name__ == "__main__": 30 | exportODMesh() -------------------------------------------------------------------------------- /Rhino/Rhino_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | import Rhino, tempfile, os 2 | import scriptcontext 3 | import System.Guid 4 | 5 | def buildODMesh(): 6 | 7 | file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 8 | 9 | #open the temp file 10 | if os.path.exists(file): 11 | f = open(file) 12 | lines = f.readlines() 13 | f.close() 14 | 15 | vertline = [] 16 | polyline = [] 17 | uvMaps = [] 18 | morphMaps = [] 19 | weightMaps = [] 20 | count = 0 21 | #Parse File to see what Data we have 22 | for line in lines: 23 | if line.startswith("VERTICES:"): 24 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 25 | if line.startswith("POLYGONS:"): 26 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 27 | if line.startswith("UV:"): 28 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 29 | if line.startswith("MORPH"): 30 | morphMaps.append([line.split(":")[1].strip(), count]) 31 | if line.startswith("WEIGHT"): 32 | weightMaps.append([line.split(":")[1].strip(), count]) 33 | count += 1 34 | 35 | mesh = Rhino.Geometry.Mesh() 36 | 37 | #create Points 38 | for verts in vertline: 39 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 40 | x = lines[i].split(" ") 41 | pt = [ float(x[0]), float(x[2].strip())*-1, float(x[1].strip()) ] 42 | mesh.Vertices.Add(pt[0], pt[1], pt[2]) 43 | 44 | for polygons in polyline: 45 | #create Polygons 46 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 47 | pts = [] 48 | surf = (lines[i].split(";;")[1]).strip() 49 | polytype = (lines[i].split(";;")[2]).strip() 50 | for x in (lines[i].split(";;")[0]).strip().split(","): 51 | pts.append(int(x.strip())) 52 | if len(pts) == 4: 53 | mesh.Faces.AddFace(pts[0], pts[1], pts[2], pts[3]) 54 | elif len(pts) == 3: 55 | mesh.Faces.AddFace(pts[0], pts[1], pts[2]) 56 | 57 | mesh.Normals.ComputeNormals() 58 | mesh.Compact() 59 | if scriptcontext.doc.Objects.AddMesh(mesh)!=System.Guid.Empty: 60 | scriptcontext.doc.Views.Redraw() 61 | return Rhino.Commands.Result.Success 62 | return Rhino.Commands.Result.Failure 63 | 64 | if __name__ == "__main__": 65 | buildODMesh() -------------------------------------------------------------------------------- /Sketchup/SKETCHUP_PastefromExternal.rb: -------------------------------------------------------------------------------- 1 | ####################################################################### 2 | # copy and paste the contents of this script into the ruby console in # 3 | # sketchup under Windows/Ruby console # 4 | ####################################################################### 5 | 6 | require 'tmpdir' 7 | temp = Dir.tmpdir() 8 | file = temp + "/" + "ODVertexData.txt" 9 | 10 | lines = Array.new 11 | File.open(file).each { |line| lines << line } 12 | 13 | vertstart = 0 14 | vertcount = 0 15 | polystart = 0 16 | polycount = 0 17 | 18 | count = 0 19 | for line in lines do 20 | if (line.match(/^VERTICES:/)) 21 | vertstart = count 22 | vertcount = (line.split(':').last).to_i 23 | end 24 | if (line.match(/^POLYGONS:/)) 25 | polystart = count 26 | polycount = (line.split(':').last).to_i 27 | end 28 | count = count + 1 29 | end 30 | 31 | #grab the points from the File and put them in an array 32 | #I multiply the scale by 100 here from cm to meters. 33 | points = Array.new 34 | for i in vertstart+1..vertstart + vertcount do 35 | inter = lines[i].strip.split(" ") 36 | points.push([inter[0].to_f*100, inter[2].to_f*100, inter[1].to_f*-100]) 37 | end 38 | 39 | model = Sketchup.active_model 40 | entities = model.active_entities 41 | 42 | #grab the polygon description and add the faces 43 | for i in polystart+1..polystart + polycount do 44 | pts = Array.new 45 | line = lines[i].split(";;").first.split(",") 46 | for pt in line do 47 | pts.push(pt.to_i) 48 | end 49 | entities.add_face(points[pts[0]], points[pts[1]], points[pts[2]], points[pts[3]]) 50 | end 51 | -------------------------------------------------------------------------------- /SubstancePainter/ODCopyPaste/OSX_binary_vertDataToObj.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/SubstancePainter/ODCopyPaste/OSX_binary_vertDataToObj.zip -------------------------------------------------------------------------------- /SubstancePainter/ODCopyPaste/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | import Painter 1.0 3 | 4 | PainterPlugin { 5 | // starts a timer that will trigger the 'onTick' callback at regular interval 6 | tickIntervalMS: -1 // -1 mean disabled (default value) 7 | 8 | // starts a JSON server on the given port: 9 | // you send javascript that will be evaluated and you get the result in JSON format 10 | jsonServerPort: -1 // -1 mean disabled (default value) 11 | 12 | Component.onCompleted: { 13 | // Called after the object has been instantiated. 14 | // This can be used to execute script code at startup, 15 | // once the full QML environment has been established. 16 | alg.log.info("Component.onCompleted") 17 | //create a toolbar button 18 | alg.ui.addToolBarWidget("paste.qml"); 19 | alg.ui.addToolBarWidget("paste_udim.qml"); 20 | } 21 | 22 | onTick: { 23 | // Do something at each tick, depending on tickIntervalMS value 24 | alg.log.info("onTick") 25 | } 26 | 27 | onConfigure: { 28 | // Do something when the user request the plugin configuration panel 29 | alg.log.info("onConfigure") 30 | //alg.log.info(alg.plugin_root_directory + "testingoliver") 31 | } 32 | 33 | onApplicationStarted: { 34 | // Called when the application is started 35 | alg.log.info("onApplicationStarted") 36 | } 37 | 38 | onNewProjectCreated: { 39 | // Called when a new project is created, before the onProjectOpened callback 40 | alg.log.info("onNewProjectCreated") 41 | } 42 | 43 | onProjectOpened: { 44 | // Called when the project is fully loaded 45 | alg.log.info("onProjectOpened") 46 | } 47 | 48 | onProjectAboutToClose: { 49 | // Called before project unload 50 | alg.log.info("onProjectAboutToClose") 51 | } 52 | 53 | onProjectAboutToSave: { 54 | // Called before a save, 'destination_url' parameter contains the save destination 55 | alg.log.info("onProjectAboutToSave: "+destination_url) 56 | } 57 | 58 | onProjectSaved: { 59 | // Called after the project was saved 60 | alg.log.info("onProjectSaved") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /SubstancePainter/ODCopyPaste/paste.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | import QtQuick.Window 2.2 3 | import QtQuick.Layouts 1.2 4 | import QtQuick.Dialogs 1.0 5 | 6 | Rectangle { 7 | id: saveButton 8 | width: 50 9 | height: 30 10 | border.color: "white" 11 | 12 | /*set color based on if mouse is in mouseArea using Conditional (ternary) Operator 13 | since MouseArea doesn't enble hover, the color changes on click of the button */ 14 | color: buttonMouseArea.containsMouse ? "grey" : "black" 15 | 16 | Text { 17 | id: buttonLabel 18 | anchors.centerIn: parent 19 | text: "PExtNml" 20 | color: "white" 21 | } 22 | 23 | //signal - emitted when event occurs (onClicked:) 24 | signal buttonClick() 25 | 26 | //button click handler 27 | onButtonClick: { 28 | 29 | try{ 30 | if (Qt.platform.os == "windows") { 31 | alg.subprocess.check_call("\"" + alg.plugin_root_directory + "vertDataToObj.exe\"") 32 | alg.project.create("file:/" + alg.plugin_root_directory + "1.obj",[],[],{"splitMaterialsByUDIM":false}) 33 | } else { 34 | alg.subprocess.check_call("\"" + alg.plugin_root_directory + "vertDataToObj\"") 35 | alg.project.create("file:/" + alg.plugin_root_directory + "1.obj",[],[],{"splitMaterialsByUDIM":false}) 36 | } 37 | }catch (e){ 38 | alg.log.error(e.message) 39 | } 40 | } 41 | 42 | MouseArea { 43 | id: buttonMouseArea 44 | //anchor all sides of the mouse area to the rectangle's anchors 45 | anchors.fill: parent 46 | 47 | //onClicked handles valid mouse button clicks 48 | onClicked: buttonClick() 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /SubstancePainter/ODCopyPaste/paste_udim.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | import QtQuick.Window 2.2 3 | import QtQuick.Layouts 1.2 4 | import QtQuick.Dialogs 1.0 5 | 6 | Rectangle { 7 | id: saveButton 8 | width: 50 9 | height: 30 10 | border.color: "yellow" 11 | 12 | /*set color based on if mouse is in mouseArea using Conditional (ternary) Operator 13 | since MouseArea doesn't enble hover, the color changes on click of the button */ 14 | color: buttonMouseArea.containsMouse ? "grey" : "black" 15 | 16 | Text { 17 | id: buttonLabel 18 | anchors.centerIn: parent 19 | text: "PExtUDIM" 20 | color: "white" 21 | } 22 | 23 | //signal - emitted when event occurs (onClicked:) 24 | signal buttonClick() 25 | 26 | //button click handler 27 | onButtonClick: { 28 | 29 | try{ 30 | if (Qt.platform.os == "windows") { 31 | alg.subprocess.check_call("\"" + alg.plugin_root_directory + "vertDataToObj.exe\"") 32 | alg.project.create("file:/" + alg.plugin_root_directory + "1.obj",[],[],{"splitMaterialsByUDIM":true}) 33 | } else { 34 | alg.subprocess.check_call("\"" + alg.plugin_root_directory + "vertDataToObj\"") 35 | alg.project.create("file:/" + alg.plugin_root_directory + "1.obj",[],[],{"splitMaterialsByUDIM":true}) 36 | } 37 | }catch (e){ 38 | alg.log.error(e.message) 39 | } 40 | } 41 | 42 | MouseArea { 43 | id: buttonMouseArea 44 | //anchor all sides of the mouse area to the rectangle's anchors 45 | anchors.fill: parent 46 | 47 | //onClicked handles valid mouse button clicks 48 | onClicked: buttonClick() 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /SubstancePainter/ODCopyPaste/vertDataToObj.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/SubstancePainter/ODCopyPaste/vertDataToObj.exe -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6ec54ace139208845bed2c717da60288 3 | folderAsset: yes 4 | timeCreated: 1507995455 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/CopyPaste.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System; 4 | using System.Linq; 5 | using System.IO; 6 | using UnityEngine; 7 | #if UNITY_EDITOR 8 | using UnityEditor; 9 | #endif 10 | 11 | /** 12 | * todo 13 | * - deleting pasted meshes will leak in editor (but adding a DestroyImmediate will break Undo...) 14 | * - handle multiple selected meshes (by merging to a single mesh w/ transforms applied)? 15 | */ 16 | 17 | namespace Parabox.OD 18 | { 19 | /** 20 | * OD file import & export. 21 | */ 22 | public static class CopyPaste 23 | { 24 | // When copying a mesh from Unity, should the mesh handedness be converted to right handed? 25 | public const string ConvertHandednessOnCopy = "od_ConvertToRightHandedOnCopy"; 26 | // When pasting a mesh into Unity, should the mesh be converted from right handed coordinates to left? 27 | public const string ConvertHandednessOnPaste = "od_ConvertToLeftHandedOnPaste"; 28 | // When pasting a mesh into Unity, should the mesh edges be split and normals recalculated? 29 | public const string SplitVerticesOnPaste = "od_SplitVerticesOnPaste"; 30 | 31 | // Swap handed-ness on export? 32 | private static bool CopyConvertsHandedness 33 | { 34 | get 35 | { 36 | #if UNITY_EDITOR 37 | return EditorPrefs.GetBool(ConvertHandednessOnCopy, false); 38 | #else 39 | return false; 40 | #endif 41 | } 42 | } 43 | 44 | // Swap handed-ness on import? 45 | private static bool PasteConvertsHandedness 46 | { 47 | get 48 | { 49 | #if UNITY_EDITOR 50 | return EditorPrefs.GetBool(ConvertHandednessOnPaste, false); 51 | #else 52 | return false; 53 | #endif 54 | } 55 | } 56 | 57 | // Split vertices on import? 58 | private static bool SplitVertices 59 | { 60 | get 61 | { 62 | #if UNITY_EDITOR 63 | return EditorPrefs.GetBool(SplitVerticesOnPaste, true); 64 | #else 65 | return true; 66 | #endif 67 | } 68 | } 69 | 70 | private enum MeshAttribute 71 | { 72 | Position, 73 | Normal, 74 | Polygon, 75 | Weight, 76 | Morph, 77 | Uv, 78 | Null 79 | } 80 | 81 | /// 82 | /// Get path to the temp mesh file. 83 | /// 84 | /// Path to the ODVertexData txt file. 85 | public static string GetTempFile() 86 | { 87 | return string.Format("{0}ODVertexData.txt", Path.GetTempPath()); 88 | } 89 | 90 | /// 91 | /// Import from ODVertexData file. 92 | /// 93 | /// 94 | /// 95 | /// 96 | /// 97 | public static bool Import(string path, out Mesh mesh, out string[] materials) 98 | { 99 | MeshAttribute attrib = MeshAttribute.Null; 100 | List positions = new List(); 101 | List normals = new List(); 102 | List polygons = new List(); 103 | List uvs = new List(); 104 | 105 | using (StreamReader reader = new StreamReader(path)) 106 | { 107 | for(string line = reader.ReadLine(); line != null; line = reader.ReadLine()) 108 | { 109 | int attributeCount = TryParseAttrib(line, ref attrib); 110 | 111 | if(attributeCount > -1) 112 | continue; 113 | 114 | if(attrib == MeshAttribute.Position) 115 | TryParseVector3(line, positions); 116 | else if(attrib == MeshAttribute.Normal) 117 | TryParseVector3(line, normals); 118 | else if(attrib == MeshAttribute.Uv) 119 | TryParseUv(line, uvs); 120 | else if(attrib == MeshAttribute.Polygon) 121 | TryParsePolygon(line, polygons); 122 | } 123 | } 124 | 125 | bool hasNormals = normals.Count == positions.Count; 126 | 127 | if(PasteConvertsHandedness) 128 | { 129 | for(int i = 0; i < positions.Count; i++) 130 | { 131 | // todo More options for swapping coordinate systems around (eg, max w/ z up) 132 | positions[i] = new Vector3(-positions[i].x, positions[i].y, positions[i].z); 133 | 134 | if(hasNormals) 135 | normals[i] = new Vector3(-normals[i].x, normals[i].y, normals[i].z); 136 | } 137 | } 138 | 139 | materials = new string[0]; 140 | mesh = null; 141 | 142 | List vertices; 143 | Dictionary> indices; 144 | if (!MeshUtility.GeneratePerTriangleVertices(positions, 145 | normals, 146 | uvs, 147 | polygons, 148 | out vertices, 149 | out indices)) 150 | return false; 151 | 152 | materials = indices.Select(x => x.Key).ToArray(); 153 | mesh = MeshUtility.CompileMesh(vertices, indices, !SplitVertices); 154 | mesh.name = "ODCopyPaste_Mesh"; 155 | mesh.RecalculateNormals(); 156 | mesh.RecalculateTangents(); 157 | mesh.RecalculateBounds(); 158 | 159 | return true; 160 | } 161 | 162 | // Copy mesh 163 | public static void Export(Mesh m, Material[] sharedMaterials) 164 | { 165 | if(m == null) 166 | return; 167 | 168 | int polyCount = 0; 169 | 170 | for (int i = 0; i < m.subMeshCount; i++) 171 | { 172 | MeshTopology topo = m.GetTopology(i); 173 | if (topo == MeshTopology.Triangles) 174 | polyCount += (int) m.GetIndexCount(i) / 3; 175 | else if(topo == MeshTopology.Quads) 176 | polyCount += (int) m.GetIndexCount(i) / 4; 177 | else 178 | return; 179 | } 180 | 181 | using (StreamWriter sw = new StreamWriter(GetTempFile(), false)) 182 | { 183 | Vector3[] positions = m.vertices; 184 | Vector3[] normals = m.normals; 185 | Vector2[] uvs = m.uv; 186 | 187 | sw.WriteLine(string.Format("VERTICES:{0}", m.vertexCount)); 188 | 189 | foreach(Vector3 p in positions) 190 | sw.WriteLine(string.Format("{0} {1} {2}", CopyConvertsHandedness ? -p.x : p.x, p.y, p.z)); 191 | 192 | if (normals != null) 193 | { 194 | sw.WriteLine(string.Format("VERTEXNORMALS:{0}", m.vertexCount)); 195 | 196 | foreach(Vector3 n in normals) 197 | sw.WriteLine(string.Format("{0} {1} {2}", CopyConvertsHandedness ? -n.x : n.x, n.y, n.z)); 198 | } 199 | 200 | if (uvs != null && uvs.Length == m.vertexCount) 201 | { 202 | sw.WriteLine(string.Format("UV:UVMap:{0}", m.vertexCount)); 203 | 204 | for(int i = 0, vc = m.vertexCount; i < vc; i++) 205 | sw.WriteLine(string.Format("{0} {1}:PNT:{2}", uvs[i].x, uvs[i].y, i)); 206 | } 207 | 208 | for (int i = 0; i < m.subMeshCount; i++) 209 | { 210 | sw.WriteLine(string.Format("POLYGONS:{0}", polyCount)); 211 | 212 | Material material = sharedMaterials != null && sharedMaterials.Length > 0 213 | ? sharedMaterials[i % sharedMaterials.Length] 214 | : null; 215 | 216 | switch (m.GetTopology(i)) 217 | { 218 | case MeshTopology.Triangles: 219 | int[] tris = m.GetIndices(i); 220 | for (int t = 0; t < tris.Length; t += 3) 221 | sw.WriteLine(string.Format( 222 | CopyConvertsHandedness 223 | ? "{2},{1},{0};;{3};;FACE" 224 | : "{0},{1},{2};;{3};;FACE", 225 | tris[t], 226 | tris[t + 1], 227 | tris[t + 2], 228 | material == null ? "Default" : material.name)); 229 | break; 230 | 231 | case MeshTopology.Quads: 232 | int[] quads = m.GetIndices(i); 233 | for (int t = 0; t < quads.Length; t += 4) 234 | sw.WriteLine(string.Format( 235 | CopyConvertsHandedness 236 | ? "{3},{2},{1},{0};;{4};;FACE" 237 | : "{0},{1},{2},{3};;{4};;FACE", 238 | quads[t], 239 | quads[t + 1], 240 | quads[t + 2], 241 | quads[t + 3], 242 | material == null ? "Default" : material.name)); 243 | break; 244 | 245 | default: 246 | // how'd you get here? 247 | break; 248 | } 249 | } 250 | } 251 | } 252 | 253 | private static int TryParseAttrib(string line, ref MeshAttribute attrib) 254 | { 255 | if(line.StartsWith("VERTICES")) 256 | attrib = MeshAttribute.Position; 257 | else if(line.StartsWith("VERTEXNORMALS")) 258 | attrib = MeshAttribute.Normal; 259 | else if(line.StartsWith("POLYGONS")) 260 | attrib = MeshAttribute.Polygon; 261 | else if(line.StartsWith("WEIGHT")) 262 | attrib = MeshAttribute.Weight; 263 | else if(line.StartsWith("MORPH")) 264 | attrib = MeshAttribute.Morph; 265 | else if(line.StartsWith("UV")) 266 | attrib = MeshAttribute.Uv; 267 | else 268 | return -1; 269 | 270 | string[] split = line.Split(':'); 271 | 272 | int size = 0; 273 | 274 | int.TryParse(split[split.Length - 1], out size); 275 | 276 | return size; 277 | } 278 | 279 | private static bool TryParseUv(string line, List uvs) 280 | { 281 | try 282 | { 283 | // 0.1725558042526245 0.5939202904701233:PLY:0:PNT:1 284 | // or 285 | // 0.1725558042526245 0.5939202904701233:PNT:1 286 | string[] all = line.Split(':'); 287 | string[] coords = all[0].Split(' '); 288 | 289 | Vector2 pos; 290 | float.TryParse(coords[0], out pos.x); 291 | float.TryParse(coords[1], out pos.y); 292 | 293 | int plyIndex = -1, pntIndex = -1; 294 | 295 | // pnt index is always there 296 | int.TryParse(all[all.Length-1], out pntIndex); 297 | 298 | if (all.Length == 5 && all[1].StartsWith("PLY")) 299 | int.TryParse(all[2], out plyIndex); 300 | 301 | uvs.Add(new UVCoord() { position = pos, polygonIndex = plyIndex, vertexIndex = pntIndex }); 302 | 303 | return true; 304 | } 305 | catch 306 | { 307 | return false; 308 | } 309 | } 310 | 311 | private static bool TryParseVector3(string line, List positions) 312 | { 313 | try 314 | { 315 | string[] split = line.Trim().Split(' '); 316 | Vector3 v; 317 | float.TryParse(split[0], out v.x); 318 | float.TryParse(split[1], out v.y); 319 | float.TryParse(split[2], out v.z); 320 | positions.Add(v); 321 | } 322 | catch 323 | { 324 | return false; 325 | } 326 | 327 | return true; 328 | } 329 | 330 | private static bool TryParsePolygon(string line, List polygons) 331 | { 332 | string[] POLYGON_SEPARATOR = new string[] { ";;" }; 333 | 334 | try 335 | { 336 | // Comma separated list of each vertid in the polygon;;materialname;;polytype. 337 | // (which can be FACE, SubD, or CCSS) 338 | // 0,1,2,3;;Default;;FACE 339 | // 340 | // For now paste only supports PolyType Face 341 | string[] split = line.Split(POLYGON_SEPARATOR, StringSplitOptions.RemoveEmptyEntries); 342 | 343 | if(split[2].Equals("FACE")) 344 | { 345 | string[] face = split[0].Split(','); 346 | int[] indices = new int[face.Length]; 347 | 348 | for(int i = 0; i < face.Length; i++) 349 | int.TryParse(face[i], out indices[i]); 350 | 351 | polygons.Add(new Polygon(split[1], indices)); 352 | } 353 | } 354 | catch(Exception e) 355 | { 356 | Debug.LogError(e.ToString()); 357 | return false; 358 | } 359 | 360 | return true; 361 | } 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/CopyPaste.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fab989486772ca248abe34b7c615c74a 3 | timeCreated: 1507995445 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3c6d299d3f359ca4aad21f9b714ffd7c 3 | folderAsset: yes 4 | timeCreated: 1507995443 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Editor/CopyPasteMenuItems.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace Parabox.OD 7 | { 8 | /** 9 | * Editor functionality for copy / paste from external. 10 | */ 11 | internal static class CopyPasteMenuItems 12 | { 13 | private static Material DefaultMaterial() 14 | { 15 | GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); 16 | Material mat = go.GetComponent().sharedMaterial; 17 | Object.DestroyImmediate(go); 18 | return mat; 19 | } 20 | 21 | [MenuItem("Edit/Paste Mesh from External %#v")] 22 | private static void Import() 23 | { 24 | Mesh mesh; 25 | string[] materials; 26 | 27 | if (CopyPaste.Import(CopyPaste.GetTempFile(), out mesh, out materials)) 28 | { 29 | GameObject go = new GameObject(); 30 | go.name = "OD Mesh"; 31 | Undo.RegisterCreatedObjectUndo(go, "Pase External Mesh"); 32 | 33 | go.AddComponent().sharedMesh = mesh; 34 | 35 | if (materials.Length > 0) 36 | { 37 | Material[] mats = new Material[materials.Length]; 38 | string[] all = System.IO.Directory.GetFiles("Assets", "*.mat", SearchOption.AllDirectories); 39 | for (int i = 0, mc = mats.Length; i < mc; i++) 40 | { 41 | string match = all.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x).Equals(materials[i])); 42 | Material mat = AssetDatabase.LoadAssetAtPath(match); 43 | mats[i] = mat ?? DefaultMaterial(); 44 | 45 | } 46 | go.AddComponent().sharedMaterials = mats; 47 | } 48 | else 49 | { 50 | go.AddComponent().sharedMaterial = DefaultMaterial(); 51 | } 52 | } 53 | else 54 | { 55 | Object.DestroyImmediate(mesh); 56 | } 57 | } 58 | 59 | [MenuItem("Edit/Copy Mesh To External %#c")] 60 | private static void Export() 61 | { 62 | GameObject first = Selection.gameObjects.FirstOrDefault(x => x.GetComponent() != null); 63 | 64 | if(first != null) 65 | CopyPaste.Export( 66 | first.GetComponent().sharedMesh, 67 | first.GetComponent().sharedMaterials); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Editor/CopyPasteMenuItems.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c6702bcc986ce643b43243eaae93f2f 3 | timeCreated: 1507995445 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Editor/CopyPastePreferences.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | namespace Parabox.OD 7 | { 8 | public static class CopyPastePreferences 9 | { 10 | private static bool m_Initialized = false; 11 | private static bool m_ConvertToRightHandedOnCopy; 12 | private static bool m_ConvertToLeftHandedOnPaste; 13 | private static bool m_SplitVerticesOnPaste; 14 | 15 | private static GUIContent m_SplitVerticesContent = new GUIContent("Split Vertices on Paste", "When enabled pasted meshes will always be constructed with hard edges instead of importing this value from the existing normals and uvs."); 16 | 17 | private static void InitializePreferences() 18 | { 19 | m_ConvertToRightHandedOnCopy = EditorPrefs.GetBool(CopyPaste.ConvertHandednessOnCopy, false); 20 | m_ConvertToLeftHandedOnPaste = EditorPrefs.GetBool(CopyPaste.ConvertHandednessOnPaste, false); 21 | m_SplitVerticesOnPaste = EditorPrefs.GetBool(CopyPaste.SplitVerticesOnPaste, false); 22 | m_Initialized = true; 23 | } 24 | 25 | [PreferenceItem("OD Copy Paste")] 26 | private static void OnGUI() 27 | { 28 | if(!m_Initialized) 29 | InitializePreferences(); 30 | 31 | EditorGUI.BeginChangeCheck(); 32 | 33 | GUILayout.Label("Copy", EditorStyles.boldLabel); 34 | m_ConvertToRightHandedOnCopy = EditorGUILayout.Toggle("Convert To Right Handed", m_ConvertToRightHandedOnCopy); 35 | GUILayout.Label("Paste", EditorStyles.boldLabel); 36 | m_ConvertToLeftHandedOnPaste = EditorGUILayout.Toggle("Convert To Left Handed", m_ConvertToLeftHandedOnPaste); 37 | m_SplitVerticesOnPaste = EditorGUILayout.Toggle(m_SplitVerticesContent, m_SplitVerticesOnPaste); 38 | 39 | if(EditorGUI.EndChangeCheck()) 40 | { 41 | EditorPrefs.SetBool(CopyPaste.ConvertHandednessOnCopy, m_ConvertToRightHandedOnCopy); 42 | EditorPrefs.SetBool(CopyPaste.ConvertHandednessOnPaste, m_ConvertToLeftHandedOnPaste); 43 | EditorPrefs.SetBool(CopyPaste.SplitVerticesOnPaste, m_SplitVerticesOnPaste); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Editor/CopyPastePreferences.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26b2307bb96d9e643ab40984a7873b57 3 | timeCreated: 1508680715 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/MeshUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using UnityEngine; 4 | 5 | namespace Parabox.OD 6 | { 7 | /// 8 | /// Methods for creating meshes from polygon soup. 9 | /// 10 | public static class MeshUtility 11 | { 12 | public static int[] TriangulatePolygon(Polygon poly) 13 | { 14 | return TriangulatePolygon(poly.indices); 15 | } 16 | 17 | public static int[] TriangulatePolygon(int[] indices) 18 | { 19 | // for now just do a simple fan triangulate 20 | // in the future it would be nice to do ear clipping 21 | int[] triangles = new int[(indices.Length - 2) * 3]; 22 | 23 | for (int i = 1; i < indices.Length - 1; i++) 24 | { 25 | triangles[(i-1)*3+0] = indices[0 ]; 26 | triangles[(i-1)*3+1] = indices[i ]; 27 | triangles[(i-1)*3+2] = indices[i+1]; 28 | } 29 | 30 | return triangles; 31 | } 32 | 33 | public static bool GeneratePerTriangleVertices(List positions, 34 | List normals, 35 | List uvCoords, 36 | List polygons, 37 | out List vertices, 38 | out Dictionary> indices) 39 | { 40 | vertices = new List(); 41 | indices = new Dictionary>(); 42 | 43 | var submeshes = new Dictionary>(); 44 | bool uvsValid = uvCoords.Count > 0; 45 | // uvs can be a mix of per-poly and continuous uvs 46 | bool uvsIndexedByPolygon = uvsValid && uvCoords.Any(x => x.polygonIndex > -1); 47 | int index = 0; 48 | 49 | if (uvsIndexedByPolygon) 50 | { 51 | var polygonUvLookup = new Dictionary>(); 52 | 53 | for (int i = 0, uc = uvCoords.Count; i < uc; i++) 54 | { 55 | Dictionary tri = null; 56 | 57 | if (polygonUvLookup.TryGetValue(uvCoords[i].polygonIndex, out tri)) 58 | tri.Add(uvCoords[i].vertexIndex, uvCoords[i].position); 59 | else 60 | polygonUvLookup.Add(uvCoords[i].polygonIndex, 61 | new Dictionary() {{uvCoords[i].vertexIndex, uvCoords[i].position}}); 62 | } 63 | 64 | Dictionary fallback = polygonUvLookup.ContainsKey(-1) ? polygonUvLookup[-1] : null; 65 | 66 | for (int ply = 0, tc = polygons.Count; ply < tc; ply++) 67 | { 68 | int[] polyIndices = TriangulatePolygon(polygons[ply]); 69 | 70 | List submeshIndices; 71 | 72 | if(!indices.TryGetValue(polygons[ply].material, out submeshIndices)) 73 | indices.Add(polygons[ply].material, submeshIndices = new List()); 74 | 75 | for (int n = 0, ic = polyIndices.Length; n < ic; n++) 76 | { 77 | Dictionary polyUvs; 78 | Vector2 v; 79 | 80 | int vi = polyIndices[n]; 81 | submeshIndices.Add(index++); 82 | 83 | if ((polygonUvLookup.TryGetValue(ply, out polyUvs) && polyUvs.TryGetValue(polyIndices[n], out v)) || 84 | (fallback != null && fallback.TryGetValue(polyIndices[n], out v))) 85 | { 86 | vertices.Add(new Vertex() 87 | { 88 | position = positions[vi], 89 | normal = vi < normals.Count ? normals[vi] : Vector3.zero, 90 | uv = v 91 | }); 92 | } 93 | else 94 | { 95 | vertices.Add(new Vertex() 96 | { 97 | position = positions[polyIndices[n]], 98 | normal = vi < normals.Count ? normals[vi] : Vector3.zero 99 | }); 100 | } 101 | } 102 | } 103 | } 104 | 105 | return true; 106 | } 107 | 108 | /// 109 | /// Compile a mesh from a set of vertices and submesh indices. 110 | /// 111 | /// 112 | /// 113 | /// If enabled common vertices will be collapsed to a single index. Disable to keep edges faceted 114 | /// 115 | public static Mesh CompileMesh(List vertices, Dictionary> indices, bool optimize = true) 116 | { 117 | var positions = optimize ? new List() : vertices.Select(x => x.position).ToList(); 118 | var normals = optimize ? new List() : vertices.Select(x => x.normal).ToList(); 119 | var uvs = optimize ? new List() : vertices.Select(x => x.uv).ToList(); 120 | 121 | if (optimize) 122 | { 123 | int index = 0; 124 | 125 | // collapse shared vertices 126 | foreach (var kvp in indices) 127 | { 128 | List submesh = kvp.Value; 129 | Dictionary commonVertices = new Dictionary(); 130 | 131 | for (int i = 0, vc = submesh.Count; i < vc; i++) 132 | { 133 | Vertex v = vertices[submesh[i]]; 134 | int ind = -1; 135 | 136 | if (commonVertices.TryGetValue(v, out ind)) 137 | { 138 | submesh[i] = ind; 139 | } 140 | else 141 | { 142 | submesh[i] = index; 143 | commonVertices.Add(v, index); 144 | index++; 145 | } 146 | } 147 | 148 | positions.AddRange(commonVertices.Select(x => x.Key.position)); 149 | normals.AddRange(commonVertices.Select(x => x.Key.normal)); 150 | uvs.AddRange(commonVertices.Select(x => x.Key.uv)); 151 | } 152 | } 153 | 154 | Mesh m = new Mesh(); 155 | m.SetVertices(positions); 156 | m.SetNormals(normals); 157 | m.SetUVs(0, uvs); 158 | m.subMeshCount = indices.Count; 159 | int smi = 0; 160 | foreach(var kvp in indices) 161 | m.SetIndices(kvp.Value.ToArray(), MeshTopology.Triangles, smi++); 162 | 163 | return m; 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/MeshUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9be0bed8b29d42bfb21f2bb4edcfec01 3 | timeCreated: 1507997002 -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Polygon.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace Parabox.OD 6 | { 7 | /** 8 | * A path of vertex indices forming a polygon. 9 | */ 10 | public class Polygon 11 | { 12 | public int[] indices; 13 | public string material; 14 | 15 | public Polygon(string material, params int[] indices) 16 | { 17 | this.material = material; 18 | this.indices = indices; 19 | } 20 | 21 | public int[] GetTriangles() 22 | { 23 | return MeshUtility.TriangulatePolygon(indices); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Polygon.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 549e969653d032644b53fd68dcb45845 3 | timeCreated: 1508690678 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/UVCoord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Parabox.OD 5 | { 6 | public struct UVCoord 7 | { 8 | public Vector2 position; 9 | public int polygonIndex; 10 | public int vertexIndex; 11 | 12 | public override string ToString() 13 | { 14 | return string.Format("{0} {1} {2}", position, polygonIndex, vertexIndex); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/UVCoord.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e92caf6238946ef8a2683ea37b4ff28 3 | timeCreated: 1509202342 -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Vertex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework.Constraints; 3 | using UnityEngine; 4 | 5 | namespace Parabox.OD 6 | { 7 | public struct Vertex : IEquatable 8 | { 9 | private const float FLT_COMPARE_RESOLUTION = 1000f; 10 | 11 | public Vector3 position; 12 | public Vector3 normal; 13 | public Vector2 uv; 14 | 15 | public override int GetHashCode() 16 | { 17 | int hash = 7; 18 | 19 | unchecked 20 | { 21 | hash ^= GetHashCode(position); 22 | hash ^= GetHashCode(normal); 23 | hash ^= GetHashCode(uv); 24 | } 25 | 26 | return hash; 27 | } 28 | 29 | private static int GetHashCode(Vector2 v) 30 | { 31 | int x = (int)(v.x * FLT_COMPARE_RESOLUTION); 32 | int y = (int)(v.y * FLT_COMPARE_RESOLUTION); 33 | 34 | int hash = 7; 35 | 36 | unchecked 37 | { 38 | hash = (hash * 7) ^ x; 39 | hash = (hash * 7) ^ y; 40 | } 41 | return hash; 42 | } 43 | 44 | private static int GetHashCode(Vector3 v) 45 | { 46 | int x = (int)(v.x * FLT_COMPARE_RESOLUTION); 47 | int y = (int)(v.y * FLT_COMPARE_RESOLUTION); 48 | int z = (int)(v.z * FLT_COMPARE_RESOLUTION); 49 | 50 | int hash = 7; 51 | 52 | unchecked 53 | { 54 | hash = (hash * 7) ^ x; 55 | hash = (hash * 7) ^ y; 56 | hash = (hash * 7) ^ z; 57 | } 58 | return hash; 59 | } 60 | 61 | public bool Equals(Vertex other) 62 | { 63 | return Approx(position, other.position) && 64 | Approx(normal, other.normal) && 65 | Approx(uv, other.uv); 66 | } 67 | 68 | private static bool Approx(Vector2 a, Vector2 b) 69 | { 70 | return Mathf.Approximately(a.x, b.x) && Mathf.Approximately(a.y, b.y); 71 | } 72 | 73 | private static bool Approx(Vector3 a, Vector3 b) 74 | { 75 | return Mathf.Approximately(a.x, b.x) && 76 | Mathf.Approximately(a.y, b.y) && 77 | Mathf.Approximately(a.z, b.z); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /Unity/Assets/OD_CopyPaste/Vertex.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d7e445f845d40d9942351a9cfac9397 3 | timeCreated: 1509217261 -------------------------------------------------------------------------------- /XSI/XSI_CopyToExternal.py: -------------------------------------------------------------------------------- 1 | import time 2 | start_time = time.time() 3 | from win32com.client import Dispatch, constants as c 4 | import tempfile, os, random, sys, re 5 | xsi=Application 6 | 7 | def TestSelection(): 8 | if (xsi.Selection.Count == 0): 9 | return "Please select an object" 10 | elif (xsi.Selection.Count > 1): 11 | return "Please select just one object" 12 | else: 13 | return "" 14 | 15 | def ProcessGeometry(): 16 | oSel=Application.Selection 17 | selOk = TestSelection() 18 | if not selOk == "": 19 | XSIUIToolkit.MsgBox(selOk) 20 | return 21 | filePath = os.path.normpath(tempfile.gettempdir()).split("\\") 22 | pfile = "" 23 | for p in filePath: 24 | if "xsi_temp" not in p: 25 | pfile += p + os.sep 26 | filePath = pfile + "ODVertexData.txt" 27 | print filePath 28 | oMesh=oSel(0).ActivePrimitive.geometry 29 | f = open(filePath, "w") 30 | 31 | oArray=oMesh.Points.PositionArray 32 | 33 | f.write("VERTICES:"+str(len(oArray[0])) + "\n") 34 | 35 | for p in range(len(oArray[0])): 36 | pString=str(oArray[0][p]) + " " + str(oArray[1][p]) + " " + str(oArray[2][p]) 37 | f.write(pString + "\n") 38 | 39 | #print("---processing points took %s seconds ---" % (time.time() - start_time)) 40 | 41 | oPolys=oMesh.Polygons 42 | f.write("POLYGONS:"+str(oPolys.count) + "\n") 43 | count = 0 44 | surfaces = [] 45 | clusters={} 46 | for oCluster in oMesh.Clusters: 47 | 48 | if oCluster.Type=="poly": 49 | for oElement in oCluster.Elements: 50 | if str(oCluster.Name) not in clusters.keys(): 51 | clusters[str(oCluster.Name)]=[] 52 | clusters[str(oCluster.Name)].append(oElement) 53 | else: 54 | clusters[str(oCluster.Name)].append(oElement) 55 | 56 | oPolys=oMesh.Polygons 57 | for oPoly in oPolys: 58 | oPoint=[] 59 | 60 | for oVertice in oPoly.Vertices: 61 | oPoint.append(str(oVertice.Index)) 62 | 63 | surf = "Default" 64 | for key in clusters: 65 | if oPoly.Index in clusters[key]: 66 | surf=key 67 | 68 | polytype = "FACE" 69 | oPoint = ",".join(oPoint) 70 | 71 | f.write(oPoint + ";;" + surf + ";;" + polytype + "\n") 72 | #print("---Total processing polys took %s seconds ---" % (time.time() - start_time)) 73 | 74 | for oCluster in oMesh.Clusters: 75 | if oCluster.Type=="pnt": 76 | for prop in oCluster.Properties: 77 | 78 | if prop.Type=="wtmap": 79 | f.write("WEIGHT:" + prop.Name + "\n") 80 | for p in prop.Elements.Array[0]: 81 | f.write(str(p)+ "\n") 82 | elif prop.IsClassOf(c.siShapeKeyID ) and prop.Name!= "ResultClusterKey": 83 | f.write("MORPH:" + prop.Name + "\n") 84 | oArray=prop.Elements.Array 85 | for p in range(len(oArray[0])): 86 | pString=str(oArray[0][p]) + " " + str(oArray[1][p]) + " " + str(oArray[2][p]) 87 | f.write(pString + "\n") 88 | 89 | ProcessGeometry() 90 | print("---Total processing took %s seconds ---" % (time.time() - start_time)) 91 | 92 | 93 | -------------------------------------------------------------------------------- /XSI/XSI_PasteFromExternal.py: -------------------------------------------------------------------------------- 1 | import time 2 | start_time = time.time() 3 | 4 | import tempfile, os, random, sys, re 5 | from win32com.client import Dispatch, constants as c 6 | 7 | xsi=Application 8 | #"ODVertexData.txt" this is the temp file where everything is stored 9 | filePath = os.path.normpath(tempfile.gettempdir()).split("\\") 10 | pfile = "" 11 | for p in filePath: 12 | if "xsi_temp" not in p: 13 | pfile += p + os.sep 14 | filePath = pfile + "ODVertexData.txt" 15 | importObjectName = "tempObject" 16 | 17 | f = open(filePath, "r") 18 | lines = f.readlines() 19 | f.close() 20 | 21 | vertline = []; polyline = []; uvMaps = []; morphMaps = []; weightMaps = [] 22 | 23 | #Parse File to see what Data we have 24 | count= 0 25 | found="" 26 | verticesx=[] ; verticesy=[]; verticesz=[] 27 | poly=0 28 | polyList=[] 29 | polys=[] 30 | surfaces={} 31 | weightsdict={} 32 | morphsdict={} 33 | 34 | for line in lines: 35 | if line.startswith("VERTICES:"): 36 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 37 | found="VERTICES" 38 | if line.startswith("POLYGONS:"): 39 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 40 | found="POLYGONS" 41 | if line.startswith("UV:"): #still to be implemented 42 | uvMaps.append([line.strip().split(":")[1:], count]) 43 | found="UV" 44 | if line.startswith("MORPH"): 45 | morphMaps.append([line.split(":")[1].strip(), count]) 46 | found="MORPH" 47 | morphline=count 48 | morphName=line.split(":")[1].strip() 49 | if line.startswith("WEIGHT"): 50 | found="WEIGHT" 51 | weightline=count 52 | weightName=line.split(":")[1].strip() 53 | 54 | count += 1 55 | 56 | if found=="VERTICES" and count <= vertline[0][0]+vertline[0][1]: 57 | x = lines[count].split(" ") 58 | pos = [ float(x[0]), float(x[1]), float(x[2].strip()) ] 59 | verticesx.append(float(x[0])) 60 | verticesy.append(float(x[1])) 61 | verticesz.append(float(x[2].strip())) 62 | 63 | if found=="POLYGONS" and count <= polyline[0][0]+polyline[0][1]: 64 | newPolyString = lines[count].split(";")[0].split(",") 65 | polys.append(str(len(newPolyString))) 66 | polys+=newPolyString 67 | polyMaterial = lines[count].split(";")[2].rstrip() 68 | surf = (lines[count].split(";;")[1]).strip() 69 | if surf not in surfaces.keys(): 70 | surfaces[surf]=[] 71 | surfaces[surf].append(poly) 72 | else: 73 | surfaces[surf].append(poly) 74 | poly+=1 75 | 76 | if found=="WEIGHT" and count <= vertline[0][0]+weightline: 77 | weights=float(lines[count].strip()) 78 | if weightName not in weightsdict.keys(): 79 | weightsdict[weightName]=[] 80 | weightsdict[weightName].append(weights) 81 | else: 82 | weightsdict[weightName].append(weights) 83 | 84 | if found=="MORPH" and count <= vertline[0][0]+morphline: 85 | x=lines[count].split(" ") 86 | morphs = [ float(x[0]), float(x[1]), float(x[2].strip()) ] 87 | if morphName not in morphsdict.keys(): 88 | morphsdict[morphName]=[] 89 | morphsdict[morphName]+=morphs 90 | else: 91 | morphsdict[morphName]+=morphs 92 | 93 | #Create Point List 94 | points=(tuple(verticesx), tuple(verticesy), tuple(verticesz)) 95 | 96 | #Generate Mesh 97 | newMesh = xsi.GetPrim("EmptyPolygonMesh", importObjectName, "", "") 98 | newMesh.ActivePrimitive.Geometry.Set(points,tuple(polys)) 99 | 100 | #create Surfaces 101 | for surf in surfaces.keys(): 102 | oCluster = newMesh.ActivePrimitive.Geometry.AddCluster( c.siPolygonCluster, surf, surfaces[surf] ) 103 | 104 | #Create Weights 105 | for weightMap in weightsdict.keys(): 106 | wmap = xsi.CreateWeightMap("WeightMap", newMesh , weightMap, "Weight Map Property", False)(0) 107 | wmap.Elements.Array = weightsdict[weightMap] 108 | 109 | #Create Morphs 110 | for morphMap in morphsdict.keys(): 111 | mmap = xsi.StoreShapeKey(newMesh, "", "siShapeObjectReferenceMode", 1, "", "", "siShapeContentPrimaryShape", "") 112 | mmap.Elements.Array = morphsdict[morphMap] 113 | mmap.Name=morphMap 114 | 115 | #create UVs (still to be implemented) 116 | 117 | print("---Total %s seconds ---" % (time.time() - start_time)) -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/OSX_binary_objToVertData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/ZBrush/ODCopyPaste/OSX_binary_objToVertData.zip -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/OSX_binary_vertDataToObj.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/ZBrush/ODCopyPaste/OSX_binary_vertDataToObj.zip -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/ZFileUtils.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/ZBrush/ODCopyPaste/ZFileUtils.lib -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/ZFileUtils64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/ZBrush/ODCopyPaste/ZFileUtils64.dll -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/objToVertData.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/ZBrush/ODCopyPaste/objToVertData.exe -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/source/ZBRUSH_ODCopyPasteExternal.txt: -------------------------------------------------------------------------------- 1 | // CopyPasteToFromExternal.txt - Oliver Hotz 2017 2 | // Groups disabled on save 3 | // buttons located in Zplugin:Misc Utilities submenu 4 | 5 | [IConfig, 3.1 ] 6 | [IShowActions, 0] 7 | 8 | [VarDef,dllPath,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\ZFileUtils64.dll"] 9 | [VarDef,Object1,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\1.OBJ"] 10 | [VarDef,importAppPath,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\vertDataToObj.exe"] 11 | [VarDef,exportAppPath,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\objToVertData.exe"] 12 | 13 | [RoutineDef, CheckSystem, [VarSet,Zvers,[ZBrushInfo,0]] 14 | [If,[Val,Zvers] >= 4.7,, 15 | [Note,"\Cff9923This zscript\Cffffff is not designed for this version of \Cff9923ZBrush\Cffffff.",,3,4737096,,300] 16 | [Exit] 17 | ] 18 | [VarSet,isMac, [ZBrushInfo,6]] //check Mac or PC 19 | // Make sure we have the dll and set its path 20 | [If,[ZBrushInfo,16]==64,//64 bit 21 | [If,isMac, 22 | //use the path below for testing only 23 | //Mac library file is combined 32 bit & 64 bit 24 | [VarSet,dllPath,"ZBRUSH_ZSTARTUP/ZPlugs64/ODCopyPaste/ZFileUtils.lib"] 25 | [VarSet,Object1,"ZBRUSH_ZSTARTUP/ZPlugs64/ODCopyPaste/1.OBJ"] 26 | [VarSet,importAppPath,"ZBRUSH_ZSTARTUP/ZPlugs64/ODCopyPaste/vertDataToObj"] 27 | [VarSet,exportAppPath,"ZBRUSH_ZSTARTUP/ZPlugs64/ODCopyPaste/objToVertData"] 28 | , 29 | //use the path below for testing only 30 | [VarSet,dllPath,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\ZFileUtils64.dll"] 31 | [VarSet,Object1,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\1.OBJ"] 32 | [VarSet,importAppPath,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\vertDataToObj.exe"] 33 | [VarSet,exportAppPath,"ZBRUSH_ZSTARTUP\ZPlugs64\ODCopyPaste\objToVertData.exe"] 34 | ] 35 | ,//else 32 bit 36 | [If,isMac, 37 | //use the path below for testing only 38 | //Mac library file is combined 32 bit & 64 bit 39 | [VarSet,dllPath,"ZBRUSH_ZSTARTUP/ZPlugs/ODCopyPaste/ZFileUtils.lib"] 40 | [VarSet,Object1,"ZBRUSH_ZSTARTUP/ZPlugs/ODCopyPaste/1.OBJ"] 41 | [VarSet,importAppPath,"ZBRUSH_ZSTARTUP/ZPlugs/ODCopyPaste/vertDataToObj"] 42 | [VarSet,exportAppPath,"ZBRUSH_ZSTARTUP/ZPlugs/ODCopyPaste/objToVertData"] 43 | , 44 | //use the path below for testing only 45 | [VarSet,dllPath,"ZBRUSH_ZSTARTUP\ZPlugs\ODCopyPaste\ZFileUtils.dll"] 46 | [VarSet,Object1,"ZBRUSH_ZSTARTUP\ZPlugs\ODCopyPaste\1.OBJ"] 47 | [VarSet,importAppPath,"ZBRUSH_ZSTARTUP\ZPlugs\ODCopyPaste\vertDataToObj.exe"] 48 | [VarSet,exportAppPath,"ZBRUSH_ZSTARTUP\ZPlugs\ODCopyPaste\objToVertData.exe"] 49 | ] 50 | ] 51 | [If, [FileExists, [Var,dllPath]], 52 | //check that correct version 53 | [VarSet, dllVersion, [FileExecute, [Var,dllPath], Version]] 54 | [If, [Val,dllVersion] >= 3.0,//dll version 55 | //OK 56 | ,//else earlier version 57 | [Note,"\Cff9923Note :\Cc0c0c0 The \Cff9923 ZFileUtils plugin \CffffffDLL\Cc0c0c0 is an earlier version which does not support this plugin. Please install //correct version."] 58 | [Exit] 59 | ] 60 | , // else no DLL. 61 | [Note,"\Cff9923Note :\Cc0c0c0 The \Cff9923 ZFileUtils plugin \CffffffDLL\Cc0c0c0 could not be found at the correct location. Please re-install the plugin, making //sure the relevant files and folders are in the \CffffffZStartup/ZPlugs\Cc0c0c0 folder."] 62 | [Exit] 63 | ] 64 | ]//end routine 65 | 66 | [VarSet,importAppPath,[FileNameResolvePath, importAppPath]] 67 | [VarSet,exportAppPath,[FileNameResolvePath, exportAppPath]] 68 | 69 | 70 | [IButton,"TOOL: CopyToExt","Exporting...", 71 | 72 | [If, [IGet, TRANSFORM:Edit] == 1, 73 | [ISet, TOOL:Export:Grp, 0 ] 74 | [FileNameSetNext, Object1 ] 75 | [IKeyPress, 13, [IPress, TOOL:Export:Export ] ] 76 | 77 | [VarSet, err, [FileExecute,[Var,dllPath],"LaunchAppWithFile", exportAppPath]] // exporting as obj, then convert to vertdata... 78 | [If,err, 79 | [Note,"An error occurred.",,2] 80 | ,//else OK 81 | [Note,"File Exported",,2] 82 | ] 83 | , // else 84 | [Note, "No model in edit mode...", , 2 ] 85 | ] 86 | ] 87 | 88 | [IButton,"TOOL: PasteFromExt","Importing...", 89 | 90 | [VarSet, err, [FileExecute,[Var,dllPath],"LaunchAppWithFile", importAppPath]] // convert vertdata to obj, then import into zbrush... 91 | [If,err, 92 | [Note,"An error occurred.",,2] 93 | ,//else OK 94 | [Note,"File imported",,2] 95 | ] 96 | [If, [FileExists, Object1 ] == 1, 97 | [FileNameSetNext, Object1 ] 98 | [IKeyPress, 13, [IPress, TOOL:Import:Import ] ] 99 | [Note, "Model Imported...", , 2 ] 100 | , // else 101 | [Note, "Sorry, Source does not exist...", , 2 ] 102 | ] 103 | ] 104 | -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/source/objToVertData.py: -------------------------------------------------------------------------------- 1 | #pyinstaller --distpath "C:\Users\Oliver\BitTorrent Sync\BTSync\_CODING\LW_Python\___WORK_IN_PROGRESS-EXPERIMENTS\ExternalCopyPaste\ZBrush" --noupx --onefile ODVertData_To_Obj.py 2 | import tempfile, os, sys 3 | 4 | def objToVertData(inputfile): 5 | output = "" 6 | file = open(inputfile, "r") 7 | lines = file.readlines() 8 | file.close() 9 | points = [] 10 | polygons = [] 11 | uvs = [] 12 | vertexnormals = [] 13 | count = 0 14 | for line in lines: 15 | if line.startswith("v "): 16 | points.append(line.strip()[2:]) 17 | if line.startswith("f "): 18 | polygons.append([line.strip()[2:], count]) 19 | if line.startswith("vt "): 20 | uvs.append(line.strip()[2:]) 21 | if line.startswith("vn "): 22 | vertexnormals.append(line.strip()[2:]) 23 | count += 1 24 | 25 | output += "VERTICES:" + str(len(points)) + "\n" 26 | for p in points: 27 | output += p + "\n" 28 | 29 | output += "POLYGONS:" + str(len(polygons)) + "\n" 30 | count = 0 31 | uvinfo = [] 32 | mat = "Default" 33 | for poly in polygons: 34 | pts = poly[0].split(" ") 35 | newpts = [] 36 | #indices in an vertdata start at 0, so we gotta subtract one from each index 37 | for p in pts: 38 | if "/" in p: 39 | newpts.append(str(int(p.split("/")[0]) - 1)) 40 | uvinfo.append([count, int(p.split("/")[1]), int(p.split("/")[0]) - 1]) 41 | else: 42 | newpts.append(str(int(p) - 1)) 43 | count += 1 44 | if "usemtl" in lines[poly[1]-1]: 45 | mat = lines[poly[1]-1].split(" ")[1].strip() 46 | output += ",".join(newpts) + ";;" + mat + ";;FACE\n" 47 | 48 | if len(uvinfo) > 0: 49 | output += "UV:Default:" + str(len(uvinfo)) + "\n" 50 | for info in uvinfo: 51 | output += uvs[info[1]-1][1:] + ":PLY:" + str(info[0]) + ":PNT:" + str(info[2]) + "\n" 52 | 53 | if len(vertexnormals) > 0: 54 | output += "VERTEXNORMALS:" + str(len(vertexnormals)) + "\n" 55 | for normal in vertexnormals: 56 | output += normal + "\n" 57 | 58 | #writing output file 59 | f = open(tempfile.gettempdir() + os.sep + "ODVertexData.txt", "w") 60 | f.write(output) 61 | f.close() 62 | 63 | ########################################################## 64 | # Main Call (just vertices and polys for now, no uv yet) # 65 | ########################################################## 66 | 67 | ##### to convert an obj to vertdata 68 | inputfile = os.path.dirname(sys.executable) + os.sep + "1.OBJ" 69 | objToVertData(inputfile) 70 | -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/source/vertDataToObj.py: -------------------------------------------------------------------------------- 1 | #pyinstaller --distpath "C:\Users\Oliver\BitTorrent Sync\BTSync\_CODING\LW_Python\___WORK_IN_PROGRESS-EXPERIMENTS\ExternalCopyPaste\zbrush" --noupx --onefile vertDataToObj.py 2 | 3 | import tempfile, os, sys 4 | 5 | def vertDataToObj(outputfile): 6 | 7 | output = "" 8 | inputfile = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 9 | file = open(inputfile, "r") 10 | lines = file.readlines() 11 | file.close() 12 | 13 | #Parse File to see what Data we have 14 | vertline = []; polyline = []; vtxnormals = []; uvMaps = []; morphMaps = []; weightMaps = [] 15 | count = 0 16 | for line in lines: 17 | if line.startswith("VERTICES:"): 18 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 19 | if line.startswith("POLYGONS:"): 20 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 21 | if line.startswith("VERTEXNORMALS:"): 22 | vtxnormals.append([int(line.strip().split(":")[1].strip()), count]) 23 | if line.startswith("UV:"): 24 | if line.strip().split(":")[1:][1] != "0": 25 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 26 | count += 1 27 | 28 | #write header 29 | output += "o ODVertexData.obj\n" 30 | output += "g default\n" 31 | 32 | #rewrite verts 33 | for verts in vertline: 34 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 35 | x = map(float, lines[i].split()) 36 | output += "v " + str(x[0]) + " " + str(x[1]) + " " + str(x[2]) + "\n" 37 | 38 | uvforobj = [] 39 | values = [] 40 | assignment = [] 41 | for uvMap in uvMaps: 42 | count = 0 43 | for i in range(int(uvMap[0][1])): 44 | split = lines[uvMap[1]+1+count].split(":") 45 | if str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1])) not in values: 46 | values.append(str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1]))) 47 | assignment.append(str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1]))) 48 | count +=1 49 | 50 | values.sort() 51 | for val in values: 52 | output += "vt " + val + "\n" 53 | 54 | 55 | for norm in vtxnormals: 56 | for i in xrange(norm[1] + 1, norm[1] + norm[0] + 1): 57 | x = map(float, lines[i].split()) 58 | output += "vn " + str(x[0]) + " " + str(x[1]) + " " + str(x[2]) + "\n" 59 | 60 | #create Polygons 61 | for polygons in polyline: 62 | polys = [] 63 | count = 0 64 | ncount = 0 65 | mat = "" 66 | testnorm = [] 67 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 68 | pts = lines[i].split(";;")[0].split(",") 69 | newpts = [] 70 | #indices in an obj start at 1, so we gotta add one to each index 71 | testpts = [] 72 | testidx = [] 73 | for p in range(len(pts)): 74 | if len(uvMaps) < 1: 75 | newpts.append(str(int(pts[p]) + 1)) 76 | if len(vtxnormals) > 0: 77 | newpts[-1] = str(newpts[-1]) + "//" + str(count+1) 78 | else: 79 | testpts.append(str(int(pts[p])+1)) 80 | testidx.append(str(values.index(assignment[count])+1)) 81 | if len(vtxnormals) > 0: 82 | testnorm.append(count) 83 | count += 1 84 | string = "" 85 | for t in range(len(testpts)): 86 | string += " " + testpts[t] + "/" + testidx[len(testpts)-1-t] 87 | if len(testnorm) > 0: 88 | string += "/" + str(testnorm[ncount]+1) 89 | ncount += 1 90 | if lines[i].split(";;")[1].strip() != mat: 91 | output += "g " + lines[i].split(";;")[1].strip() + "\n" 92 | output += "usemtl " + lines[i].split(";;")[1].strip() + "\n" 93 | #output += "s 1\n" 94 | mat = lines[i].split(";;")[1].strip() 95 | if string != "": 96 | output += "f " + string.strip() + "\n" 97 | else: 98 | output += "f " + " ".join(newpts) + "\n" 99 | 100 | #writing output file 101 | f = open(outputfile, "w") 102 | f.write(output) 103 | f.close() 104 | 105 | ########################################################## 106 | # Main Call (just vertices and polys for now, no uv yet) # 107 | ########################################################## 108 | 109 | ##### to convert vertex data to obj 110 | outputfile = os.path.dirname(sys.executable) + os.sep + "1.OBJ" 111 | vertDataToObj(outputfile) -------------------------------------------------------------------------------- /ZBrush/ODCopyPaste/vertDataToObj.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/ZBrush/ODCopyPaste/vertDataToObj.exe -------------------------------------------------------------------------------- /ZBrush/ZBRUSH_ODCopyPasteExternal.zsc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heimlich1024/OD_CopyPasteExternal/858c4c778e589235cf420040f1fa3cc2b10c9ee4/ZBrush/ZBRUSH_ODCopyPasteExternal.zsc -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /docs/datafile.txt: -------------------------------------------------------------------------------- 1 | # Fileformat Description that gets written as temporary file: 2 | 3 | VERTICES:#number of vertices(points) 4 | x y z (of each vertex) 5 | POLYGONS:#number of polygons 6 | comma separate list of each vertid in the polygon;;materialname;;polytype (which can be FACE, SubD, or CCSS) 7 | WEIGHT:name of weightmap 8 | weight of vertice (in same order as VERTICES) 9 | MORPH:name of morphmap 10 | deltax deltay deltaz 11 | UV:name of uvmap:number of uv coordinates 12 | u v:polyid:pntid (for discontinuous UVs) or 13 | u v:pntid (for continuous UVs) 14 | VERTEXNORMALS:# of vertexnormals 15 | x y z (for each normal) 16 | 17 | Example data format for a box: 18 | 19 | VERTICES:8 20 | -0.5 -0.5 -0.5 21 | -0.5 -0.5 0.5 22 | -0.5 0.5 0.5 23 | -0.5 0.5 -0.5 24 | 0.5 -0.5 -0.5 25 | 0.5 -0.5 0.5 26 | 0.5 0.5 0.5 27 | 0.5 0.5 -0.5 28 | POLYGONS:6 29 | 0,1,2,3;;Default;;FACE 30 | 0,4,5,1;;Default;;FACE 31 | 1,5,6,2;;Default;;FACE 32 | 3,2,6,7;;Default;;FACE 33 | 0,3,7,4;;Default;;FACE 34 | 4,7,6,5;;Default;;FACE 35 | WEIGHT:simpleweights 36 | 1.0 37 | 1.0 38 | 1.0 39 | 1.0 40 | 1.0 41 | 1.0 42 | 1.0 43 | 1.0 44 | UV:txuvmap:24 45 | 0.339743584394 0.339743584394:PLY:0:PNT:0 46 | 0.660256385803 0.339743584394:PLY:0:PNT:1 47 | 0.660256385803 0.660256385803:PLY:0:PNT:2 48 | 0.339743584394 0.660256385803:PLY:0:PNT:3 49 | 0.660256385803 0.326923072338:PLY:1:PNT:5 50 | 0.339743584394 0.326923072338:PLY:1:PNT:1 51 | 0.00641027092934 0.339743584394:PLY:3:PNT:3 52 | 0.00641027092934 0.660256385803:PLY:3:PNT:2 53 | 0.326923072338 0.660256385803:PLY:3:PNT:6 54 | 0.326923072338 0.339743584394:PLY:3:PNT:7 55 | 0.673076927662 0.00641025649384:PLY:4:PNT:0 56 | 0.993589758873 0.00641025649384:PLY:4:PNT:4 57 | 0.673076927662 0.339743584394:PLY:5:PNT:4 58 | 0.673076927662 0.660256385803:PLY:5:PNT:7 59 | 0.993589758873 0.660256385803:PLY:5:PNT:6 60 | 0.993589758873 0.339743584394:PLY:5:PNT:5 61 | 0.339743584394 0.00641025649384:PNT:0 62 | 0.660256385803 0.00641025649384:PNT:4 63 | 0.00641027092934 0.00641025649384:PNT:1 64 | 0.326923072338 0.00641025649384:PNT:5 65 | 0.326923072338 0.326923072338:PNT:6 66 | 0.00641027092934 0.326923072338:PNT:2 67 | 0.673076927662 0.326923072338:PNT:3 68 | 0.993589758873 0.326923072338:PNT:7 69 | MORPH:simplemorph 70 | None 71 | None 72 | 0.0 0.290000021458 0.0 73 | 0.0 0.290000021458 0.0 74 | None 75 | None 76 | 0.0 0.290000021458 0.0 77 | 0.0 0.290000021458 0.0 78 | 79 | -------------------------------------------------------------------------------- /docs/datafile_example.txt: -------------------------------------------------------------------------------- 1 | VERTICES:8 2 | -0.5 -0.5 -0.5 3 | -0.5 -0.5 0.5 4 | -0.5 0.5 0.5 5 | -0.5 0.5 -0.5 6 | 0.5 -0.5 -0.5 7 | 0.5 -0.5 0.5 8 | 0.5 0.5 0.5 9 | 0.5 0.5 -0.5 10 | POLYGONS:6 11 | 0,1,2,3;;Default;;FACE 12 | 0,4,5,1;;Default;;FACE 13 | 1,5,6,2;;Default;;FACE 14 | 3,2,6,7;;Default;;FACE 15 | 0,3,7,4;;Default;;FACE 16 | 4,7,6,5;;Default;;FACE 17 | WEIGHT:simpleweights 18 | 1.0 19 | 1.0 20 | 1.0 21 | 1.0 22 | 1.0 23 | 1.0 24 | 1.0 25 | 1.0 26 | UV:txuvmap:24 27 | 0.339743584394 0.339743584394:PLY:0:PNT:0 28 | 0.660256385803 0.339743584394:PLY:0:PNT:1 29 | 0.660256385803 0.660256385803:PLY:0:PNT:2 30 | 0.339743584394 0.660256385803:PLY:0:PNT:3 31 | 0.660256385803 0.326923072338:PLY:1:PNT:5 32 | 0.339743584394 0.326923072338:PLY:1:PNT:1 33 | 0.00641027092934 0.339743584394:PLY:3:PNT:3 34 | 0.00641027092934 0.660256385803:PLY:3:PNT:2 35 | 0.326923072338 0.660256385803:PLY:3:PNT:6 36 | 0.326923072338 0.339743584394:PLY:3:PNT:7 37 | 0.673076927662 0.00641025649384:PLY:4:PNT:0 38 | 0.993589758873 0.00641025649384:PLY:4:PNT:4 39 | 0.673076927662 0.339743584394:PLY:5:PNT:4 40 | 0.673076927662 0.660256385803:PLY:5:PNT:7 41 | 0.993589758873 0.660256385803:PLY:5:PNT:6 42 | 0.993589758873 0.339743584394:PLY:5:PNT:5 43 | 0.339743584394 0.00641025649384:PNT:0 44 | 0.660256385803 0.00641025649384:PNT:4 45 | 0.00641027092934 0.00641025649384:PNT:1 46 | 0.326923072338 0.00641025649384:PNT:5 47 | 0.326923072338 0.326923072338:PNT:6 48 | 0.00641027092934 0.326923072338:PNT:2 49 | 0.673076927662 0.326923072338:PNT:3 50 | 0.993589758873 0.326923072338:PNT:7 51 | MORPH:simplemorph 52 | None 53 | None 54 | 0.0 0.290000021458 0.0 55 | 0.0 0.290000021458 0.0 56 | None 57 | None 58 | 0.0 0.290000021458 0.0 59 | 0.0 0.290000021458 0.0 60 | -------------------------------------------------------------------------------- /docs/objToVertData.py: -------------------------------------------------------------------------------- 1 | #pyinstaller --distpath "C:\Users\Oliver\BitTorrent Sync\BTSync\_CODING\LW_Python\___WORK_IN_PROGRESS-EXPERIMENTS\ExternalCopyPaste\ZBrush" --noupx --onefile ODVertData_To_Obj.py 2 | import tempfile, os, sys 3 | 4 | def objToVertData(inputfile): 5 | output = "" 6 | file = open(inputfile, "r") 7 | lines = file.readlines() 8 | file.close() 9 | points = [] 10 | polygons = [] 11 | uvs = [] 12 | vertexnormals = [] 13 | count = 0 14 | for line in lines: 15 | if line.startswith("v "): 16 | points.append(line.strip()[2:]) 17 | if line.startswith("f "): 18 | polygons.append([line.strip()[2:], count]) 19 | if line.startswith("vt "): 20 | uvs.append(line.strip()[2:]) 21 | if line.startswith("vn "): 22 | vertexnormals.append(line.strip()[2:]) 23 | count += 1 24 | 25 | output += "VERTICES:" + str(len(points)) + "\n" 26 | for p in points: 27 | output += p + "\n" 28 | 29 | output += "POLYGONS:" + str(len(polygons)) + "\n" 30 | count = 0 31 | uvinfo = [] 32 | mat = "Default" 33 | for poly in polygons: 34 | pts = poly[0].split(" ") 35 | newpts = [] 36 | #indices in an vertdata start at 0, so we gotta subtract one from each index 37 | for p in pts: 38 | if "/" in p: 39 | newpts.append(str(int(p.split("/")[0]) - 1)) 40 | uvinfo.append([count, int(p.split("/")[1]), int(p.split("/")[0]) - 1]) 41 | else: 42 | newpts.append(str(int(p) - 1)) 43 | count += 1 44 | if "usemtl" in lines[poly[1]-1]: 45 | mat = lines[poly[1]-1].split(" ")[1].strip() 46 | output += ",".join(newpts) + ";;" + mat + ";;FACE\n" 47 | 48 | if len(uvinfo) > 0: 49 | output += "UV:Default:" + str(len(uvinfo)) + "\n" 50 | for info in uvinfo: 51 | output += uvs[info[1]-1][1:] + ":PLY:" + str(info[0]) + ":PNT:" + str(info[2]) + "\n" 52 | 53 | if len(vertexnormals) > 0: 54 | output += "VERTEXNORMALS:" + str(len(vertexnormals)) + "\n" 55 | for normal in vertexnormals: 56 | output += normal + "\n" 57 | 58 | #writing output file 59 | f = open(tempfile.gettempdir() + os.sep + "ODVertexData.txt", "w") 60 | f.write(output) 61 | f.close() 62 | 63 | ########################################################## 64 | # Main Call (just vertices and polys for now, no uv yet) # 65 | ########################################################## 66 | 67 | ##### to convert an obj to vertdata 68 | inputfile = os.path.dirname(sys.executable) + os.sep + "1.OBJ" 69 | objToVertData(inputfile) 70 | -------------------------------------------------------------------------------- /docs/vertDataToObj.py: -------------------------------------------------------------------------------- 1 | #pyinstaller --distpath "C:\Users\Oliver\BitTorrent Sync\BTSync\_CODING\LW_Python\___WORK_IN_PROGRESS-EXPERIMENTS\ExternalCopyPaste\zbrush" --noupx --onefile vertDataToObj.py 2 | 3 | import tempfile, os, sys 4 | 5 | def vertDataToObj(outputfile): 6 | 7 | output = "" 8 | inputfile = tempfile.gettempdir() + os.sep + "ODVertexData.txt" 9 | file = open(inputfile, "r") 10 | lines = file.readlines() 11 | file.close() 12 | 13 | #Parse File to see what Data we have 14 | vertline = []; polyline = []; vtxnormals = []; uvMaps = []; morphMaps = []; weightMaps = [] 15 | count = 0 16 | for line in lines: 17 | if line.startswith("VERTICES:"): 18 | vertline.append([int(line.strip().split(":")[1].strip()), count]) 19 | if line.startswith("POLYGONS:"): 20 | polyline.append([int(line.strip().split(":")[1].strip()), count]) 21 | if line.startswith("VERTEXNORMALS:"): 22 | vtxnormals.append([int(line.strip().split(":")[1].strip()), count]) 23 | if line.startswith("UV:"): 24 | uvMaps.append([line.strip().split(":")[1:], count]) # changed this to add the # of uv coordinates into the mix 25 | count += 1 26 | 27 | #write header 28 | output += "o ODVertexData.obj\n" 29 | output += "g default\n" 30 | 31 | #rewrite verts 32 | for verts in vertline: 33 | for i in xrange(verts[1] + 1, verts[1] + verts[0] + 1): 34 | x = map(float, lines[i].split()) 35 | output += "v " + str(x[0]) + " " + str(x[1]) + " " + str(x[2]) + "\n" 36 | 37 | uvforobj = [] 38 | values = [] 39 | assignment = [] 40 | for uvMap in uvMaps: 41 | count = 0 42 | for i in range(int(uvMap[0][1])): 43 | split = lines[uvMap[1]+1+count].split(":") 44 | if str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1])) not in values: 45 | values.append(str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1]))) 46 | assignment.append(str(float(split[0].split(" ")[0])) + " " + str(float(split[0].split(" ")[1]))) 47 | count +=1 48 | 49 | values.sort() 50 | for val in values: 51 | output += "vt " + val + "\n" 52 | 53 | 54 | for norm in vtxnormals: 55 | for i in xrange(norm[1] + 1, norm[1] + norm[0] + 1): 56 | x = map(float, lines[i].split()) 57 | output += "vn " + str(x[0]) + " " + str(x[1]) + " " + str(x[2]) + "\n" 58 | 59 | #create Polygons 60 | for polygons in polyline: 61 | polys = [] 62 | count = 0 63 | ncount = 0 64 | mat = "" 65 | testnorm = [] 66 | for i in xrange(polygons[1] + 1, polygons[1] + polygons[0] + 1): 67 | pts = lines[i].split(";;")[0].split(",") 68 | newpts = [] 69 | #indices in an obj start at 1, so we gotta add one to each index 70 | testpts = [] 71 | testidx = [] 72 | for p in range(len(pts)): 73 | if len(uvMaps) < 1: 74 | newpts.append(str(int(pts[p]) + 1)) 75 | if len(vtxnormals) > 0: 76 | newpts[-1] = str(newpts[-1]) + "//" + str(count+1) 77 | else: 78 | testpts.append(str(int(pts[p])+1)) 79 | testidx.append(str(values.index(assignment[count])+1)) 80 | if len(vtxnormals) > 0: 81 | testnorm.append(count) 82 | count += 1 83 | string = "" 84 | for t in range(len(testpts)): 85 | string += " " + testpts[t] + "/" + testidx[len(testpts)-1-t] 86 | if len(testnorm) > 0: 87 | string += "/" + str(testnorm[ncount]+1) 88 | ncount += 1 89 | if lines[i].split(";;")[1].strip() != mat: 90 | output += "g " + lines[i].split(";;")[1].strip() + "\n" 91 | output += "usemtl " + lines[i].split(";;")[1].strip() + "\n" 92 | #output += "s 1\n" 93 | mat = lines[i].split(";;")[1].strip() 94 | if string != "": 95 | output += "f " + string.strip() + "\n" 96 | else: 97 | output += "f " + " ".join(newpts) + "\n" 98 | 99 | #writing output file 100 | f = open(outputfile, "w") 101 | f.write(output) 102 | f.close() 103 | 104 | ########################################################## 105 | # Main Call (just vertices and polys for now, no uv yet) # 106 | ########################################################## 107 | 108 | ##### to convert vertex data to obj 109 | outputfile = os.path.dirname(sys.executable) + os.sep + "1.OBJ" 110 | vertDataToObj(outputfile) --------------------------------------------------------------------------------