├── addons └── CSGExport │ ├── icon.png │ ├── plugin.cfg │ └── csgexport.gd ├── README.md └── LICENSE /addons/CSGExport/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xtremezero/CSGExport-Godot/HEAD/addons/CSGExport/icon.png -------------------------------------------------------------------------------- /addons/CSGExport/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | name="CSG Export" 3 | description="A tool to export CSG container meshes as Wavefront OBJ." 4 | author="mohammedzero43" 5 | version="0.3.2" 6 | script="csgexport.gd" 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSGExport-Godot 2 | CSG Export Plugin for GodotEngine 3 | ================================= 4 | Export CSG Meshes with 1 click 5 | 6 | How to use : 7 | - Combine all your CSGMeshes under a CSGCombiner node then press (Export to OBJ) in the Spatial Container Menu. 8 | 9 | Limitations : 10 | - Only works when you select 1 CSGCombiner node (Cant multiselect) 11 | 12 | - Only material diffuse and emission colors will be exported (Textures and maps wont be exported, but you can add them manually in your 3D editing software) 13 | 14 | - The plugin is still experimental ,so please report for bugs at: mohammedzero43@gmail.com 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 mohammedzero43 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /addons/CSGExport/csgexport.gd: -------------------------------------------------------------------------------- 1 | #This script is created by: mohammedzero43 (Xtremezero), please give credits if remixed or shared 2 | #feel free to report bugs and suggest improvements at mohammedzero43@gmail.com 3 | tool 4 | extends EditorPlugin 5 | 6 | var button_csg = Button.new() 7 | var object_name = "" 8 | var obj = null 9 | 10 | var objcont = "" #.obj content 11 | var matcont = "" #.mat content 12 | var fdialog: FileDialog 13 | 14 | 15 | func _enter_tree(): 16 | 17 | get_editor_interface().get_selection().connect("selection_changed",self,"_selectionchanged") 18 | add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU,button_csg) 19 | button_csg.text = "Export CSGMesh to .obj" 20 | func _ready(): 21 | button_csg.connect("pressed",self,"_on_csg_pressed") 22 | func _exit_tree(): 23 | button_csg.queue_free() 24 | remove_control_from_container(CONTAINER_SPATIAL_EDITOR_MENU,button_csg) 25 | 26 | func _selectionchanged(): 27 | var selected = get_editor_interface().get_selection().get_selected_nodes() 28 | if selected.size() == 1: 29 | 30 | if selected[0] is CSGCombiner: 31 | object_name= selected[0].name 32 | obj = selected[0] 33 | button_csg.visible = true 34 | else: 35 | button_csg.visible = false 36 | else: 37 | button_csg.visible = false 38 | 39 | 40 | func handles(obj): 41 | if obj is CSGCombiner: 42 | return true 43 | 44 | 45 | func _on_csg_pressed(): 46 | exportcsg() 47 | 48 | func exportcsg(): 49 | #Variables 50 | objcont = "" #.obj content 51 | matcont = "" #.mat content 52 | var csgMesh= obj.get_meshes(); 53 | var vertcount=0 54 | 55 | #OBJ Headers 56 | objcont+="mtllib "+object_name+".mtl\n" 57 | objcont+="o " + object_name + "\n";#CHANGE WITH SELECTION NAME"; 58 | 59 | #Blank material 60 | var blank_material = SpatialMaterial.new() 61 | blank_material.resource_name = "BlankMaterial" 62 | 63 | #Get surfaces and mesh info 64 | for t in range(csgMesh[-1].get_surface_count()): 65 | var surface = csgMesh[-1].surface_get_arrays(t) 66 | var verts = surface[0] 67 | var UVs = surface[4] 68 | var normals = surface[1] 69 | var mat:SpatialMaterial = csgMesh[-1].surface_get_material(t) 70 | var faces = [] 71 | 72 | #create_faces_from_verts (Triangles) 73 | var tempv=0 74 | for v in range(verts.size()): 75 | if tempv%3==0: 76 | faces.append([]) 77 | faces[-1].append(v+1) 78 | tempv+=1 79 | tempv= tempv%3 80 | 81 | #add verticies 82 | var tempvcount =0 83 | for ver in verts: 84 | objcont+=str("v ",ver[0],' ',ver[1],' ',ver[2])+"\n" 85 | tempvcount +=1 86 | 87 | #add UVs 88 | for uv in UVs: 89 | objcont+=str("vt ",uv[0],' ',uv[1])+"\n" 90 | for norm in normals: 91 | objcont+=str("vn ",norm[0],' ',norm[1],' ',norm[2])+"\n" 92 | 93 | #add groups and materials 94 | objcont+="g surface"+str(t)+"\n" 95 | 96 | if mat == null: 97 | mat = blank_material 98 | 99 | objcont+="usemtl "+str(mat)+"\n" 100 | 101 | #add faces 102 | for face in faces: 103 | objcont+=str("f ", face[2]+vertcount,"/",face[2]+vertcount,"/",face[2]+vertcount, 104 | ' ',face[1]+vertcount,"/",face[1]+vertcount,"/",face[1]+vertcount, 105 | ' ',face[0]+vertcount,"/",face[0]+vertcount,"/",face[0]+vertcount)+"\n" 106 | #update verts 107 | vertcount+=tempvcount 108 | 109 | #create Materials for current surface 110 | matcont+=str("newmtl "+str(mat))+'\n' 111 | matcont+=str("Kd ",mat.albedo_color.r," ",mat.albedo_color.g," ",mat.albedo_color.b)+'\n' 112 | matcont+=str("Ke ",mat.emission.r," ",mat.emission.g," ",mat.emission.b)+'\n' 113 | matcont+=str("d ",mat.albedo_color.a)+"\n" 114 | 115 | #Select file destination 116 | fdialog = FileDialog.new() 117 | fdialog.mode = FileDialog.MODE_OPEN_DIR 118 | fdialog.access = FileDialog.ACCESS_RESOURCES 119 | ##fdialog.add_filter("*.obj; Wavefront File") 120 | fdialog.show_hidden_files = false 121 | fdialog.window_title = "Export CSGMesh" 122 | fdialog.resizable = true 123 | 124 | get_editor_interface().get_editor_viewport().add_child(fdialog) 125 | fdialog.connect("dir_selected", self, "onFileDialogOK", []) 126 | fdialog.popup_centered(Vector2(700, 450)) 127 | 128 | func onFileDialogOK(path: String): 129 | #Write to files 130 | var objfile = File.new() 131 | objfile.open(path+"/"+object_name+".obj", File.WRITE) 132 | objfile.store_string(objcont) 133 | objfile.close() 134 | 135 | var mtlfile = File.new() 136 | mtlfile.open(path+"/"+object_name+".mtl", File.WRITE) 137 | mtlfile.store_string(matcont) 138 | mtlfile.close() 139 | 140 | #output message 141 | print("CSG Mesh Exported") 142 | get_editor_interface().get_resource_filesystem().scan() 143 | 144 | --------------------------------------------------------------------------------