|
| 1 | +# ##### BEGIN GPL LICENSE BLOCK ##### |
| 2 | +# |
| 3 | +# This program is free software; you can redistribute it and/or |
| 4 | +# modify it under the terms of the GNU General Public License |
| 5 | +# as published by the Free Software Foundation; either version 2 |
| 6 | +# of the License, or (at your option) any later version. |
| 7 | +# |
| 8 | +# This program is distributed in the hope that it will be useful, |
| 9 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | +# GNU General Public License for more details. |
| 12 | +# |
| 13 | +# You should have received a copy of the GNU General Public License |
| 14 | +# along with this program; if not, write to the Free Software Foundation, |
| 15 | +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 16 | +# |
| 17 | +# ##### END GPL LICENSE BLOCK ##### |
| 18 | + |
| 19 | +# Based on export_ply.py |
| 20 | +# Contributors: Mr.doob, Kikko |
| 21 | + |
| 22 | +""" |
| 23 | +This script exports the selected object for the three.js engine. |
| 24 | +""" |
| 25 | + |
| 26 | +import bpy |
| 27 | +import os |
| 28 | + |
| 29 | +def save(operator, context, filepath="", use_modifiers=True, use_normals=True, use_uv_coords=True, use_colors=True): |
| 30 | + |
| 31 | + def rvec3d(v): |
| 32 | + return round(v[0], 6), round(v[1], 6), round(v[2], 6) |
| 33 | + |
| 34 | + def rvec2d(v): |
| 35 | + return round(v[0], 6), round(v[1], 6) |
| 36 | + |
| 37 | + scene = context.scene |
| 38 | + obj = context.object |
| 39 | + |
| 40 | + if not filepath.lower().endswith('.js'): |
| 41 | + filepath += '.js' |
| 42 | + |
| 43 | + classname = filepath.split('/')[-1].replace('.js','') |
| 44 | + |
| 45 | + if not obj: |
| 46 | + raise Exception("Error, Select 1 active object") |
| 47 | + |
| 48 | + file = open(filepath, 'w') |
| 49 | + |
| 50 | + if scene.objects.active: |
| 51 | + bpy.ops.object.mode_set(mode='OBJECT') |
| 52 | + |
| 53 | + if use_modifiers: |
| 54 | + mesh = obj.create_mesh(scene, True, 'PREVIEW') |
| 55 | + else: |
| 56 | + mesh = obj.data |
| 57 | + |
| 58 | + if not mesh: |
| 59 | + raise Exception("Error, could not get mesh data from active object") |
| 60 | + |
| 61 | + # mesh.transform(obj.matrix_world) # XXX |
| 62 | + |
| 63 | + faceUV = (len(mesh.uv_textures) > 0) |
| 64 | + vertexUV = (len(mesh.sticky) > 0) |
| 65 | + vertexColors = len(mesh.vertex_colors) > 0 |
| 66 | + |
| 67 | + if (not faceUV) and (not vertexUV): |
| 68 | + use_uv_coords = False |
| 69 | + if not vertexColors: |
| 70 | + use_colors = False |
| 71 | + |
| 72 | + if not use_uv_coords: |
| 73 | + faceUV = vertexUV = False |
| 74 | + if not use_colors: |
| 75 | + vertexColors = False |
| 76 | + |
| 77 | + if faceUV: |
| 78 | + active_uv_layer = mesh.uv_textures.active |
| 79 | + if not active_uv_layer: |
| 80 | + use_uv_coords = False |
| 81 | + faceUV = None |
| 82 | + else: |
| 83 | + active_uv_layer = active_uv_layer.data |
| 84 | + |
| 85 | + if vertexColors: |
| 86 | + active_col_layer = mesh.vertex_colors.active |
| 87 | + if not active_col_layer: |
| 88 | + use_colors = False |
| 89 | + vertexColors = None |
| 90 | + else: |
| 91 | + active_col_layer = active_col_layer.data |
| 92 | + |
| 93 | + # incase |
| 94 | + color = uvcoord = uvcoord_key = normal = normal_key = None |
| 95 | + |
| 96 | + file.write('// Generated with Blender 2.54 exporter\n\n') |
| 97 | + |
| 98 | + file.write('var %s = function () {\n\n' % classname) |
| 99 | + |
| 100 | + file.write('\tvar scope = this;\n\n') |
| 101 | + |
| 102 | + file.write('\tTHREE.Geometry.call( this );\n\n') |
| 103 | + |
| 104 | + for v in mesh.vertices: |
| 105 | + file.write('\tv( %.6f, %.6f, %.6f );\n' % (v.co.x, v.co.z, -v.co.y)) # co |
| 106 | + |
| 107 | + file.write('\n') |
| 108 | + |
| 109 | + if use_normals: |
| 110 | + for f in mesh.faces: |
| 111 | + if len(f.vertices) == 3: |
| 112 | + file.write('\tf3( %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.vertices[0], f.vertices[1], f.vertices[2], f.normal[0], f.normal[1], f.normal[2])) |
| 113 | + else: |
| 114 | + file.write('\tf4( %d, %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.vertices[0], f.vertices[1], f.vertices[2], f.vertices[3], f.normal[0], f.normal[1], f.normal[2])) |
| 115 | + |
| 116 | + else: |
| 117 | + for f in mesh.faces: |
| 118 | + if len(f.vertices) == 3: |
| 119 | + file.write('\tf3( %d, %d, %d );\n' % (f.vertices[0], f.vertices[1], f.vertices[2])) |
| 120 | + else: |
| 121 | + file.write('\tf4( %d, %d, %d, %d );\n' % (f.vertices[0], f.vertices[1], f.vertices[2], f.vertices[3])) |
| 122 | + |
| 123 | + face_index_pairs = [ (face, index) for index, face in enumerate(mesh.faces)] |
| 124 | + |
| 125 | + if use_uv_coords: |
| 126 | + file.write('\n') |
| 127 | + for f, f_index in face_index_pairs: |
| 128 | + tface = mesh.uv_textures[0].data[f_index] |
| 129 | + if len(f.vertices) == 3: |
| 130 | + file.write('\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f );\n' % (tface.uv1[0], 1.0-tface.uv1[1], tface.uv2[0], 1.0-tface.uv2[1], tface.uv3[0], 1.0-tface.uv3[1])) |
| 131 | + else: |
| 132 | + file.write('\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f );\n' % (tface.uv1[0], 1.0-tface.uv1[1], tface.uv2[0], 1.0-tface.uv2[1], tface.uv3[0], 1.0-tface.uv3[1], tface.uv4[0], 1.0-tface.uv4[1])) |
| 133 | + |
| 134 | + file.write('\n') |
| 135 | + |
| 136 | + file.write('\tfunction v( x, y, z ) {\n\n') |
| 137 | + file.write('\t\tscope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );\n\n') |
| 138 | + file.write('\t}\n\n') |
| 139 | + |
| 140 | + file.write('\tfunction f3( a, b, c, nx, ny, nz ) {\n\n') |
| 141 | + file.write('\t\tscope.faces.push( new THREE.Face3( a, b, c, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n') |
| 142 | + file.write('\t}\n\n') |
| 143 | + |
| 144 | + file.write('\tfunction f4( a, b, c, d, nx, ny, nz ) {\n\n') |
| 145 | + file.write('\t\tscope.faces.push( new THREE.Face4( a, b, c, d, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n') |
| 146 | + file.write('\t}\n\n') |
| 147 | + |
| 148 | + file.write('\tfunction uv( u1, v1, u2, v2, u3, v3, u4, v4 ) {\n\n') |
| 149 | + file.write('\t\tvar uv = [];\n') |
| 150 | + file.write('\t\tuv.push( new THREE.UV( u1, v1 ) );\n') |
| 151 | + file.write('\t\tuv.push( new THREE.UV( u2, v2 ) );\n') |
| 152 | + file.write('\t\tuv.push( new THREE.UV( u3, v3 ) );\n') |
| 153 | + file.write('\t\tif ( u4 && v4 ) uv.push( new THREE.UV( u4, v4 ) );\n') |
| 154 | + file.write('\t\tscope.uvs.push( uv );\n') |
| 155 | + file.write('\t}\n\n') |
| 156 | + |
| 157 | + file.write('}\n\n') |
| 158 | + |
| 159 | + file.write('%s.prototype = new THREE.Geometry();\n' % classname) |
| 160 | + file.write('%s.prototype.constructor = %s;' % (classname, classname)) |
| 161 | + |
| 162 | + file.close() |
| 163 | + |
| 164 | + print("writing", filepath, "done") |
| 165 | + |
| 166 | + if use_modifiers: |
| 167 | + bpy.data.meshes.remove(mesh) |
| 168 | + |
| 169 | + """ |
| 170 | + mesh_vertices = mesh.vertices # save a lookup |
| 171 | + ply_vertices = [] # list of dictionaries |
| 172 | + # vdict = {} # (index, normal, uv) -> new index |
| 173 | + vdict = [{} for i in range(len(mesh_vertices))] |
| 174 | + ply_faces = [[] for f in range(len(mesh.faces))] |
| 175 | + vert_count = 0 |
| 176 | + for i, f in enumerate(mesh.faces): |
| 177 | +
|
| 178 | + smooth = f.use_smooth |
| 179 | + if not smooth: |
| 180 | + normal = tuple(f.normal) |
| 181 | + normal_key = rvec3d(normal) |
| 182 | +
|
| 183 | + if faceUV: |
| 184 | + uv = active_uv_layer[i] |
| 185 | + uv = uv.uv1, uv.uv2, uv.uv3, uv.uv4 # XXX - crufty :/ |
| 186 | + if vertexColors: |
| 187 | + col = active_col_layer[i] |
| 188 | + col = col.color1, col.color2, col.color3, col.color4 |
| 189 | +
|
| 190 | + f_vertices = f.vertices |
| 191 | +
|
| 192 | + pf = ply_faces[i] |
| 193 | + for j, vidx in enumerate(f_vertices): |
| 194 | + v = mesh_vertices[vidx] |
| 195 | +
|
| 196 | + if smooth: |
| 197 | + normal = tuple(v.normal) |
| 198 | + normal_key = rvec3d(normal) |
| 199 | +
|
| 200 | + if faceUV: |
| 201 | + uvcoord = uv[j][0], 1.0 - uv[j][1] |
| 202 | + uvcoord_key = rvec2d(uvcoord) |
| 203 | + elif vertexUV: |
| 204 | + uvcoord = v.uvco[0], 1.0 - v.uvco[1] |
| 205 | + uvcoord_key = rvec2d(uvcoord) |
| 206 | +
|
| 207 | + if vertexColors: |
| 208 | + color = col[j] |
| 209 | + color = int(color[0] * 255.0), int(color[1] * 255.0), int(color[2] * 255.0) |
| 210 | +
|
| 211 | +
|
| 212 | + key = normal_key, uvcoord_key, color |
| 213 | +
|
| 214 | + vdict_local = vdict[vidx] |
| 215 | + pf_vidx = vdict_local.get(key) # Will be None initially |
| 216 | +
|
| 217 | + if pf_vidx == None: # same as vdict_local.has_key(key) |
| 218 | + pf_vidx = vdict_local[key] = vert_count |
| 219 | + ply_vertices.append((vidx, normal, uvcoord, color)) |
| 220 | + vert_count += 1 |
| 221 | +
|
| 222 | + pf.append(pf_vidx) |
| 223 | +
|
| 224 | + file.write('ply\n') |
| 225 | + file.write('format ascii 1.0\n') |
| 226 | + file.write('comment Created by Blender %s - www.blender.org, source file: %r\n' % (bpy.app.version_string, os.path.basename(bpy.data.filepath))) |
| 227 | +
|
| 228 | + file.write('element vertex %d\n' % len(ply_vertices)) |
| 229 | +
|
| 230 | + file.write('property float x\n') |
| 231 | + file.write('property float y\n') |
| 232 | + file.write('property float z\n') |
| 233 | +
|
| 234 | + if use_normals: |
| 235 | + file.write('property float nx\n') |
| 236 | + file.write('property float ny\n') |
| 237 | + file.write('property float nz\n') |
| 238 | + if use_uv_coords: |
| 239 | + file.write('property float s\n') |
| 240 | + file.write('property float t\n') |
| 241 | + if use_colors: |
| 242 | + file.write('property uchar red\n') |
| 243 | + file.write('property uchar green\n') |
| 244 | + file.write('property uchar blue\n') |
| 245 | +
|
| 246 | + file.write('element face %d\n' % len(mesh.faces)) |
| 247 | + file.write('property list uchar uint vertex_indices\n') |
| 248 | + file.write('end_header\n') |
| 249 | +
|
| 250 | + for i, v in enumerate(ply_vertices): |
| 251 | + file.write('%.6f %.6f %.6f ' % tuple(mesh_vertices[v[0]].co)) # co |
| 252 | + if use_normals: |
| 253 | + file.write('%.6f %.6f %.6f ' % v[1]) # no |
| 254 | + if use_uv_coords: |
| 255 | + file.write('%.6f %.6f ' % v[2]) # uv |
| 256 | + if use_colors: |
| 257 | + file.write('%u %u %u' % v[3]) # col |
| 258 | + file.write('\n') |
| 259 | +
|
| 260 | + for pf in ply_faces: |
| 261 | + if len(pf) == 3: |
| 262 | + file.write('3 %d %d %d\n' % tuple(pf)) |
| 263 | + else: |
| 264 | + file.write('4 %d %d %d %d\n' % tuple(pf)) |
| 265 | +
|
| 266 | + file.close() |
| 267 | + print("writing %r done" % filepath) |
| 268 | +
|
| 269 | + if use_modifiers: |
| 270 | + bpy.data.meshes.remove(mesh) |
| 271 | + """ |
| 272 | + |
| 273 | + # XXX |
| 274 | + """ |
| 275 | + if is_editmode: |
| 276 | + Blender.Window.EditMode(1, '', 0) |
| 277 | + """ |
| 278 | + |
| 279 | + return {'FINISHED'} |
0 commit comments