def process(self): verts = self.inputs['Vertices'].sv_get() if self.inputs['PolyEdge'].is_linked: poly_edge = self.inputs['PolyEdge'].sv_get() polyIn = True else: polyIn = False poly_edge = repeat_last([[]]) verts_out = [] poly_edge_out = [] item_order = [] polyOutput = polyIn and self.outputs['PolyEdge'].is_linked orderOutput = self.outputs['Item order'].is_linked vertOutput = self.outputs['Vertices'].is_linked if not any((vertOutput, orderOutput, polyOutput)): return if self.mode == 'XYZ': # should be user settable op_order = [(0, False), (1, False), (2, False)] for v, p in zip(verts, poly_edge): s_v = ((e[0], e[1], e[2], i) for i, e in enumerate(v)) for item_index, rev in op_order: s_v = sorted(s_v, key=itemgetter(item_index), reverse=rev) verts_out.append([v[:3] for v in s_v]) if polyOutput: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append( [list(map(lambda n: v_index[n], pe)) for pe in p]) if orderOutput: item_order.append([i[-1] for i in s_v]) if self.mode == 'DIST': if self.inputs['Base Point'].is_linked: base_points = self.inputs['Base Point'].sv_get() bp_iter = repeat_last(base_points[0]) else: bp = [(0, 0, 0)] bp_iter = repeat_last(bp) for v, p, v_base in zip(verts, poly_edge, bp_iter): s_v = sorted(((v_c, i) for i, v_c in enumerate(v)), key=lambda v: distK(v[0], v_base)) verts_out.append([vert[0] for vert in s_v]) if polyOutput: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append( [list(map(lambda n: v_index[n], pe)) for pe in p]) if orderOutput: item_order.append([i[-1] for i in s_v]) if self.mode == 'AXIS': if self.inputs['Mat'].is_linked: mat = Matrix_generate(self.inputs['Mat'].sv_get()) else: mat = [Matrix.Identity(4)] mat_iter = repeat_last(mat) def f(axis, q): if axis.dot(q.axis) > 0: return q.angle else: return -q.angle for v, p, m in zip(Vector_generate(verts), poly_edge, mat_iter): axis = m * Vector((0, 0, 1)) axis_norm = m * Vector((1, 0, 0)) base_point = m * Vector((0, 0, 0)) intersect_d = [ intersect_point_line(v_c, base_point, axis) for v_c in v ] rotate_d = [ f(axis, (axis_norm + v_l[0]).rotation_difference(v_c)) for v_c, v_l in zip(v, intersect_d) ] s_v = ((data[0][1], data[1], i) for i, data in enumerate(zip(intersect_d, rotate_d))) s_v = sorted(s_v, key=itemgetter(0, 1)) verts_out.append([v[i[-1]].to_tuple() for i in s_v]) if polyOutput: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append( [list(map(lambda n: v_index[n], pe)) for pe in p]) if orderOutput: item_order.append([i[-1] for i in s_v]) if self.mode == 'USER': if self.inputs['Index Data'].is_linked: index = self.inputs['Index Data'].sv_get() else: return for v, p, i in zip(verts, poly_edge, index): s_v = sorted([(data[0], data[1], i) for i, data in enumerate(zip(i, v))], key=itemgetter(0)) verts_out.append([obj[1] for obj in s_v]) if polyOutput: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append([[v_index[k] for k in pe] for pe in p]) if orderOutput: item_order.append([i[-1] for i in s_v]) if vertOutput: self.outputs['Vertices'].sv_set(verts_out) if polyOutput: self.outputs['PolyEdge'].sv_set(poly_edge_out) if orderOutput: self.outputs['Item order'].sv_set(item_order)
def execute(self, context): crv_data = context.object.data if len(crv_data.splines) != 2: #TODO, make real error print('ERROR, curve must have 2 splines in one object') return {'CANCELLED'} ob = context.object mx = ob.matrix_world meta_data = bpy.data.metaballs.new('Meta Wax Rim') meta_obj = bpy.data.objects.new('Meta Surface', meta_data) meta_data.resolution = .8 meta_data.render_resolution = .8 context.scene.objects.link(meta_obj) me = context.object.to_mesh(context.scene, apply_modifiers=True, settings='PREVIEW') bme = bmesh.new() bme.from_mesh(me) bme.verts.ensure_lookup_table() bme.edges.ensure_lookup_table() loops = edge_loops_from_bmedges(bme, [ed.index for ed in bme.edges]) vs0 = [bme.verts[i].co for i in loops[0]] vs1 = [bme.verts[i].co for i in loops[1]] vs_even_0, eds0 = space_evenly_on_path(vs0, [(0, 1), (1, 2)], 60) vs_even_1, eds1 = space_evenly_on_path(vs1, [(0, 1), (1, 2)], 60) if (vs_even_0[0] - vs_even_1[0]).length > (vs_even_0[0] - vs_even_1[-1]).length: vs_even_1.reverse() for i in range(1, len(vs_even_0) - 1): blend = -abs((i - 30) / 30) + 1 v0_0 = vs_even_0[i] v1_1 = vs_even_1[i] v0_p1 = vs_even_0[i + 1] v1_p1 = vs_even_1[i + 1] v0_m1 = vs_even_0[i - 1] v1_m1 = vs_even_1[i - 1] mid = .5 * v0_0 + .5 * v1_1 Z = v1_1 - v0_0 Z.normalize() x0, x1 = v0_p1 - v0_m1, v1_p1 - v1_m1 x0.normalize() x1.normalize() X = .5 * x0 + .5 * x1 X.normalize() Y = Z.cross(X) X_c = Y.cross(Z) #X corrected T = Matrix.Identity(3) T.col[0] = X_c T.col[1] = Y T.col[2] = Z quat = T.to_quaternion() mb = meta_data.elements.new(type=self.meta_type) mb.size_y = .5 * (blend * self.anterior_width + (1 - blend) * self.posterior_width) mb.size_z = .5 * (v1_1 - v0_0).length mb.size_x = 2 mb.rotation = quat mb.stiffness = 2 mb.co = mid meta_obj.matrix_world = mx #if self.finalize: # context.scene.update() # me = meta_obj.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') # new_ob = bpy.data.objects.new('MetaSurfaceMesh', me) # context.scene.objects.link(new_ob) # new_ob.matrix_world = mx # if meta_obj.data.materials: # new_ob.data.materials.append(meta_obj.data.materials[0]) # # context.scene.objects.unlink(meta_obj) # bpy.data.objects.remove(meta_obj) # bpy.data.metaballs.remove(meta_data) bme.free() return {'FINISHED'}
def main(context, rand_sample, spin_res, make_sphere): start = time.time() # rand_sample = 400 #randomly select this many directions on a solid hemisphere to measure from # spin_res = 180 #180 steps is 0.5 degrees world_mx = context.object.matrix_world scale = world_mx.to_scale() trans = world_mx.to_translation() tr_mx = Matrix.Identity(4) sc_mx = Matrix.Identity(4) tr_mx[0][3], tr_mx[1][3], tr_mx[2][3] = trans[0], trans[1], trans[2] sc_mx[0][0], sc_mx[1][1], sc_mx[2][2] = scale[0], scale[1], scale[2] r_mx = world_mx.to_quaternion().to_matrix().to_4x4() me = context.object.data bme = bmesh.new() bme.from_mesh(me) convex_hull = bmesh.ops.convex_hull(bme, input=bme.verts, use_existing_faces=True) total_hull = convex_hull['geom'] hull_verts = [item for item in total_hull if hasattr(item, 'co')] hull_faces = [item for item in total_hull if hasattr(item, 'no')] hull_bme = bmesh.new() #hull_bme.verts = hull_verts #hull_bme.faces = hull_faces min_mx = Matrix.Identity(4) min_box = bbox_orient(hull_verts, min_mx) min_V = bbox_vol(min_box) print('initial volume %f' % min_V) min_axis = Vector((0, 0, 1)) min_angle = 0 axes = [] for i in range(0, rand_sample): u = random.random() v = random.random() theta = math.pi * u phi = math.acos(2 * v - 1) x = math.cos(theta) * math.sin(phi) y = math.sin(theta) * math.sin(phi) z = math.cos(phi) axis = Vector((x, y, z)) axes.append(axis) for n in range(0, spin_res): angle = math.pi / 2 * n / spin_res rot_mx = Matrix.Rotation(angle, 4, axis) box = bbox_orient(hull_verts, rot_mx) test_V = bbox_vol(box) if test_V < min_V: min_V = test_V min_axis = axis min_angle = angle min_box = box min_mx = rot_mx elapsed_time = time.time() - start print('did %i iterations in %f seconds' % (rand_sample * spin_res, elapsed_time)) print("final volume %f" % bbox_vol(min_box)) box_verts = box_cords(min_box) bpy.ops.mesh.primitive_cube_add() fmx = tr_mx * r_mx * min_mx.inverted() * sc_mx context.object.matrix_world = fmx context.object.draw_type = 'BOUNDS' for i, v in enumerate(box_verts): context.object.data.vertices[i].co = v # visualize the sample vectors if make_sphere: sample_sphere = bmesh.new() for ax in axes: sample_sphere.verts.new(ax) sphere_me = bpy.data.meshes.new('Bound Samples') dest_ob = bpy.data.objects.new('Bound Samples', sphere_me) sample_sphere.to_mesh(sphere_me) context.scene.objects.link(dest_ob) sample_sphere.free() bme.free()
def modal(self,context,event): context.area.tag_redraw() if event.type == 'RET' and event.value == 'PRESS': for drop in self.drops: for i in drop.ind_path: self.bme.verts[i].select = True bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') self.bme.to_mesh(self.ob.data) self.bme.free() return {'FINISHED'} elif event.type == 'Q' and event.value == 'PRESS': n_rolling = self.roll_droplets(context) iters = 0 while n_rolling > 5 and iters < 400: n_rolling = self.roll_droplets(context) iters += 1 if iters >= 399: print('too much rolling') self.consensus_count = 20 self.build_concensus(context) l_co = [self.bme.verts[i].co for i in self.consensus_list] test_no = vector_average([self.bme.verts[i].normal for i in self.consensus_list]) test_no.normalize() pt, pno = calculate_plane(l_co) if pno.dot(test_no) < 0: pno *= -1 self.pln_pt = pt - 5*pno self.pln_no = pno mx = self.ob.matrix_world imx = mx.inverted() no_mx = mx.transposed().inverted().to_3x3() Z = no_mx * pno loc = mx * pt - 5 * Z ob_y = no_mx * Vector((0,1,0)) X = ob_y.cross(Z) Y = Z.cross(X) Z.normalize() Y.normalize() X.normalize() wmx = Matrix.Identity(4) wmx[0][0], wmx[1][0], wmx[2][0] = X[0], X[1], X[2] wmx[0][1], wmx[1][1], wmx[2][1] = Y[0], Y[1], Y[2] wmx[0][2], wmx[1][2], wmx[2][2] = Z[0], Z[1], Z[2] wmx[0][3], wmx[1][3], wmx[2][3] = loc[0], loc[1], loc[2] #circ_bm = bmesh.new() #bmesh.ops.create_circle(circ_bm, cap_ends = True, cap_tris = False, segments = 10, diameter = .5 *min(context.object.dimensions) + .5 *max(context.object.dimensions)) # Finish up, write the bmesh into a new mesh #me = bpy.data.meshes.new("Occlusal Plane") #circ_bm.to_mesh(me) #circ_bm.free() # Add the mesh to the scene #scene = bpy.context.scene #obj = bpy.data.objects.new("Object", me) #scene.objects.link(obj) #obj.matrix_world = wmx return {'RUNNING_MODAL'} elif event.type == 'W' and event.value == 'PRESS': curv_id = self.bme.verts.layers.float['max_curve'] start = time.time() cut_geom = self.bme.faces[:] + self.bme.verts[:] + self.bme.edges[:] bmesh.ops.bisect_plane(self.bme, geom = cut_geom, dist = .000001, plane_co = self.pln_pt, plane_no = self.pln_no, use_snap_center = False, clear_outer=False, clear_inner=True) self.bme.verts.ensure_lookup_table() self.bme.faces.ensure_lookup_table() rand_sample = list(set([random.randint(0,len(self.bme.verts)-1) for i in range(math.floor(.2 * len(self.bme.verts)))])) self.drops = [CuspWaterDroplet(self.bme.verts[i], self.pln_pt, self.pln_no, curv_id) for i in rand_sample] dur = time.time() - start print('took %f seconds to cut the mesh and generate drops' % dur) start = time.time() n_rolling = self.roll_droplets(context) iters = 0 while n_rolling > 10 and iters < 100: n_rolling = self.roll_droplets(context) iters += 1 self.consensus_count = 80 self.build_concensus(context) dur = time.time() - start print('took %f seconds to roll the drops' % dur) return {'RUNNING_MODAL'} elif event.type == 'UP_ARROW' and event.value == 'PRESS': n_rolling = self.roll_droplets(context) iters = 0 while n_rolling > 10 and iters < 100: n_rolling = self.roll_droplets(context) iters += 1 return {'RUNNING_MODAL'} elif event.type == 'LEFT_ARROW' and event.value == 'PRESS': self.consensus_count -= 5 self.build_concensus(context) return {'RUNNING_MODAL'} elif event.type == 'RIGHT_ARROW' and event.value == 'PRESS': self.consensus_count += 5 self.build_concensus(context) return {'RUNNING_MODAL'} elif event.type == 'C' and event.value == 'PRESS': self.build_concensus(context) return {'RUNNING_MODAL'} elif event.type == 'M' and event.value == 'PRESS': self.merge_close_consensus_points() return {'RUNNING_MODAL'} elif event.type == 'B' and event.value == 'PRESS' and self.consensus_generated: self.fit_cubic_consensus_points() return {'RUNNING_MODAL'} elif event.type == 'S' and event.value == 'PRESS': self.sort_by_value(context) return {'RUNNING_MODAL'} elif event.type in {'RIGHTMOUSE', 'ESC'}: bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') self.bme.to_mesh(self.ob.data) self.bme.free() return {'CANCELLED'} else: return {'PASS_THROUGH'}
def load(self, context, **options): """load a sketchup file""" self.context = context self.reuse_material = options['reuse_material'] self.reuse_group = options['reuse_existing_groups'] self.max_instance = options['max_instance'] self.render_engine = options['render_engine'] self.component_stats = defaultdict(list) self.component_skip = proxy_dict() self.component_depth = proxy_dict() self.group_written = {} ren_res_x = context.scene.render.resolution_x ren_res_y = context.scene.render.resolution_y self.aspect_ratio = ren_res_x / ren_res_y skp_log(f'Importing: {self.filepath}') addon_name = __name__.split('.')[0] self.prefs = context.preferences.addons[addon_name].preferences _time_main = time.time() try: self.skp_model = sketchup.Model.from_file(self.filepath) except Exception as e: skp_log(f'Error reading input file: {self.filepath}') skp_log(e) return {'FINISHED'} if options['import_scene']: for s in self.skp_model.scenes: if s.name == options['import_scene']: skp_log(f"Importing Scene '{s.name}'") self.scene = s self.layers_skip = [l for l in s.layers] for l in s.layers: skp_log(f"SKIP: {l.name}") if not self.layers_skip: skp_log('Could not find scene: {}, importing default.'.format( options['import_scene'])) if not self.layers_skip: self.layers_skip = [ l for l in self.skp_model.layers if not l.visible ] skp_log('Skipping Layers ... ') for l in sorted([l.name for l in self.layers_skip]): skp_log(l) self.skp_components = proxy_dict( self.skp_model.component_definition_as_dict) skp_log(f'Parsed in {(time.time() - _time_main):.4f} sec.') if options['scenes_as_camera']: for s in self.skp_model.scenes: self.write_camera(s.camera, s.name) if options['import_camera']: if self.scene: active_cam = self.write_camera(self.scene.camera, name=self.scene.name) context.scene.camera = active_cam else: active_cam = self.write_camera(self.skp_model.camera) context.scene.camera = active_cam _t1 = time.time() self.write_materials(self.skp_model.materials) skp_log(f'Materials imported in {(time.time() - _t1):.4f} sec.') _t1 = time.time() D = SKP_util() SKP_util.layers_skip = self.layers_skip for c in self.skp_model.component_definitions: self.component_depth[c.name] = D.component_deps(c.entities) skp_log(f'Component depths analyzed in {(time.time() - _t1):.4f} sec.') self.write_duplicateable_groups() if options["dedub_only"]: return {'FINISHED'} self.component_stats = defaultdict(list) self.write_entities(self.skp_model.entities, "Sketchup", Matrix.Identity(4)) for k, _v in self.component_stats.items(): name, mat = k if options['dedub_type'] == "VERTEX": self.instance_group_dupli_vert(name, mat, self.component_stats) else: self.instance_group_dupli_face(name, mat, self.component_stats) skp_log(f'Entities imported in {(time.time() - _t1):.4f} sec.') skp_log('Finished importing in %.4f sec.\n' % (time.time() - _time_main)) return {'FINISHED'}
def _convert_cycles_world(exporter, scene, world, is_viewport_render): definitions = { "importance": world.luxcore.importance, } node_tree = world.node_tree if not world.use_nodes or not node_tree: if not _define_constantinfinite(definitions, list(world.color)): return None output_node = node_tree.get_output_node("CYCLES") if not output_node: return None surface_node = utils_node.get_linked_node(output_node.inputs["Surface"]) if not surface_node: return None if surface_node.bl_idname == "ShaderNodeBackground": gain = surface_node.inputs["Strength"].default_value color_socket = surface_node.inputs["Color"] color_node = utils_node.get_linked_node(color_socket) if color_node: if color_node.bl_idname == "ShaderNodeRGB": color = list(color_node.outputs[0].default_value)[:3] if not _define_constantinfinite(definitions, color): return None elif color_node.bl_idname == "ShaderNodeTexEnvironment": image = color_node.image if not image: image_missing = True else: try: filepath = ImageExporter.export_cycles_node_reader( image) image_missing = False definitions["type"] = "infinite" definitions["file"] = filepath definitions[ "gamma"] = 2.2 if image.colorspace_settings.name == "sRGB" else 1 # Transformation mapping_node = utils_node.get_linked_node( color_node.inputs["Vector"]) if mapping_node: # TODO fix transformation raise NotImplementedError( "Mapping node not supported yet") # tex_loc = Matrix.Translation(mapping_node.inputs["Location"].default_value) # # tex_sca = Matrix() # scale = mapping_node.inputs["Scale"].default_value # tex_sca[0][0] = scale.x # tex_sca[1][1] = scale.y # tex_sca[2][2] = scale.z # # # Prevent "singular matrix in matrixinvert" error (happens if a scale axis equals 0) # for i in range(3): # if tex_sca[i][i] == 0: # tex_sca[i][i] = 0.0000000001 # # rotation = mapping_node.inputs["Rotation"].default_value # tex_rot0 = Matrix.Rotation(rotation.x, 4, "X") # tex_rot1 = Matrix.Rotation(rotation.y, 4, "Y") # tex_rot2 = Matrix.Rotation(rotation.z, 4, "Z") # tex_rot = tex_rot0 @ tex_rot1 @ tex_rot2 # # transformation = tex_loc @ tex_rot @ tex_sca else: infinite_fix = Matrix.Scale(1.0, 4) infinite_fix[0][ 0] = -1.0 # mirror the hdri map to match Cycles and old LuxBlend transformation = infinite_fix @ Matrix.Identity( 4).inverted() definitions["transformation"] = utils.matrix_to_list( transformation) except OSError as image_missing: LuxCoreErrorLog.add_warning("World: " + str(image_missing)) image_missing = True if image_missing: _define_constantinfinite(definitions, MISSING_IMAGE_COLOR) elif color_node.bl_idname == "ShaderNodeTexSky": if color_node.sky_type != "HOSEK_WILKIE": LuxCoreErrorLog.add_warning( "World: Unsupported sky type: " + color_node.sky_type) definitions["type"] = "sky2" definitions["ground.enable"] = False definitions["groundalbedo"] = [color_node.ground_albedo] * 3 definitions["turbidity"] = color_node.turbidity definitions["dir"] = list(color_node.sun_direction) # Found by eyeballing, not super precise gain *= 0.000014 else: # No color node linked definitions["type"] = "constantinfinite" # Alpha not supported color = list(color_socket.default_value)[:3] if not _define_constantinfinite(definitions, color): return None else: raise Exception("Unsupported node type:", surface_node.bl_idname) if gain == 0: return None definitions["gain"] = [gain] * 3 return definitions
def make_bmesh_geometry(node, obj_index, context, verts, *topology): collection = context.scene.collection meshes = bpy.data.meshes objects = bpy.data.objects islands = None edges, faces, matrix = topology name = node.basedata_name + '.' + str("%04d" % obj_index) if name in objects: sv_object = objects[name] else: temp_mesh = default_mesh(name) sv_object = objects.new(name, temp_mesh) collection.objects.link(sv_object) # book-keeping via ID-props!? even this is can be broken by renames sv_object['idx'] = obj_index sv_object['madeby'] = node.name sv_object['basedata_name'] = node.basedata_name mesh = sv_object.data current_count = len(mesh.vertices) propose_count = len(verts) difference = (propose_count - current_count) ''' With this mode you make a massive assumption about the constant state of geometry. Assumes the count of verts edges/faces stays the same, and only updates the locations node.fixed_verts is not suitable for initial object creation but if over time you find that the only change is going to be vertices, this mode can be switched to to increase efficiency ''' if node.fixed_verts and difference == 0: f_v = list(itertools.chain.from_iterable(verts)) mesh.vertices.foreach_set('co', f_v) mesh.update() else: ''' get bmesh, write bmesh to obj, free bmesh''' bm = bmesh_from_pydata(verts, edges, faces, normal_update=node.calc_normals) bm.to_mesh(sv_object.data) if node.randomize_vcol_islands: islands = find_islands_treemap(bm) bm.free() sv_object.hide_select = False if node.randomize_vcol_islands: set_vertices(sv_object, islands) if matrix: # matrix = matrix_sanitizer(matrix) if node.extended_matrix: sv_object.data.transform(matrix) sv_object.matrix_local = Matrix.Identity(4) else: sv_object.matrix_local = matrix else: sv_object.matrix_local = Matrix.Identity(4)
def CreateFaceEdgeRotation(context, obj, force_stay_editmode, flip_normal, flip_line, flip_tangent, empty_origin_index, map_normal, map_line, map_tangent): error_message = ErrorMessage.none vertex_select_amount = 0 vertices = [] #TODO: not sure about this mode changing weirdness bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') for i in context.active_object.data.vertices: if i.select: vertices.append(i) vertex_select_amount += 1 mat = Matrix.Identity(4) if vertex_select_amount == 3: if empty_origin_index == 0: #Get the vertex coordinate from the index localCoord0 = vertices[0].co localCoord1 = vertices[1].co localCoord2 = vertices[2].co if empty_origin_index == 1: localCoord0 = vertices[1].co localCoord1 = vertices[2].co localCoord2 = vertices[0].co if empty_origin_index == 2: localCoord0 = vertices[2].co localCoord1 = vertices[0].co localCoord2 = vertices[1].co #Transform from local to global globalCoord0 = obj.matrix_world * localCoord0 globalCoord1 = obj.matrix_world * localCoord1 globalCoord2 = obj.matrix_world * localCoord2 vertex_position_origin = globalCoord0 #Calculate the normal from 3 points line_vector = globalCoord1 - globalCoord0 line_vector.normalize() line_vector1 = globalCoord2 - globalCoord0 line_vector1.normalize() normal_vector = line_vector.cross(line_vector1) normal_vector.normalize() tangent_vector = normal_vector.cross(line_vector) tangent_vector.normalize() if flip_normal is True: normal_vector = normal_vector * -1 if flip_line is True: line_vector = line_vector * -1 if flip_tangent == True: tangent_vector = tangent_vector * -1 if force_stay_editmode is False: bpy.ops.object.mode_set(mode='OBJECT') #All the axis have to be different (we can't have x, x, z for example) if (map_normal != map_line) and (map_normal != map_tangent) and ( map_line != map_tangent): #matrix order: x=0 y=1 z=2 position=3 if map_line == 'x': mat.col[0] = line_vector.to_4d() if map_line == 'y': mat.col[1] = line_vector.to_4d() if map_line == 'z': mat.col[2] = line_vector.to_4d() if map_normal == 'x': mat.col[0] = normal_vector.to_4d() if map_normal == 'y': mat.col[1] = normal_vector.to_4d() if map_normal == 'z': mat.col[2] = normal_vector.to_4d() if map_tangent == 'x': mat.col[0] = tangent_vector.to_4d() if map_tangent == 'y': mat.col[1] = tangent_vector.to_4d() if map_tangent == 'z': mat.col[2] = tangent_vector.to_4d() mat.col[3] = vertex_position_origin.to_4d() #The coordinate system must be right handed if IsMatrixRightHanded(mat): return True, "", mat else: error_message = ErrorMessage.not_right_handed return False, error_message, mat else: #Invalid axis mapping, so stay in edit mode bpy.ops.object.mode_set(mode='EDIT') error_message = ErrorMessage.two_axis_same return False, error_message, mat #No edge was selected, so stay in edit mode else: bpy.ops.object.mode_set(mode='EDIT') #Deselect all to work around the bug which causes an edge to appear #selected in the 3d view while it is not. bpy.ops.mesh.select_all(action='DESELECT') error_message = ErrorMessage.edge_invalid return False, error_message, mat
def export_bone(bone, bones, materials, mesh, meshes, group_names): """ Returns (bone_data, other_data, ptrs) where: bone_data: AlignedBytes is the bytestring of the bone name_data: [AlignedBytes] is a list of relevant detached bytestrings ptrs: [BytesPtr] is a list of relevant pointers If bone is None, the model is exported as rooms, so mesh and meshes must be provided. """ bytestr = bytearray() aligned = AlignedBytes(bytestr, 4) num_bones = len(bones) if bone else len(meshes) # Bone ID bone_id = bones.find(bone.name) if bone else meshes.index(mesh) bytestr += from_uint(bone_id, 4) # Name name_bytes = AlignedBytes(str_to_cstr(bone.name if bone else "r" + str(bone_id)), 1) bytestr += from_uint(0, 4) name_ptr = BytesPtr(aligned, 4, name_bytes, 0, 4) # Offset to parent bytestr += from_int(bones.find(bone.parent.name) - bone_id \ if bone and bone.parent else 0, 2) # Has children bytestr += from_uint(len(bone.children) > 0 if bone else 0, 2) # Next sibling sibling_id = 1 if bone_id < num_bones - 1 else 0 if bone: later_siblings = [b for b in bones[bone_id + 1:] if b.parent == bone.parent] sibling_id = bones.find(later_siblings[0].name) - bone_id if later_siblings else 0 bytestr += from_int(sibling_id, 2) bytestr += from_uint(0, 2) # padding # Transform transform = bone.matrix_local if bone else Matrix.Identity(4) if bone and bone.parent: transform = bone.parent.matrix_local.inverted() * transform bytestr += from_vec(transform.to_scale(), 4, 12) euler = transform.to_euler('XYZ') for e in euler: bytestr += from_deg(math.degrees(e) / 16) # division by 16 because of format bytestr += from_uint(0, 2) # padding bytestr += from_vec(transform.to_translation(), 4, 12) # Materials and display lists indexes = None if bone: # verts = {i for i,v in enumerate(mesh.vertices) if # group_names[v.groups[0].group if v.groups else 0] == bone.name} # indexes = {p.material_index for p in mesh.polygons if set(p.vertices) & verts} indexes = list(range(len(materials))) if bone_id == 0 else [] else: start = sum(len(m.materials) for m in meshes[:bone_id]) indexes = list(range(start, start + len(materials))) bytestr += from_uint(len(indexes), 4) bytestr += from_uint(0, 4) * 2 # placeholder pointers ids = lambda: AlignedBytes(from_uint_list(indexes, 1), 1) mat_ids = ids() dl_ids = ids() mat_ptr = BytesPtr(aligned, 0x34, mat_ids, 0, 4) dl_ptr = BytesPtr(aligned, 0x38, dl_ids, 0, 4) # Billboard bytestr += from_uint(0, 4) # No billboard return (aligned, [name_bytes, mat_ids, dl_ids], [name_ptr, mat_ptr, dl_ptr])
def get_scale_mat(vec_scale): mat_scale = Matrix.Identity(4) mat_scale[0][0] = vec_scale.x mat_scale[1][1] = vec_scale.y mat_scale[2][2] = vec_scale.z return mat_scale
def getValue(self): return Matrix.Identity(4)
def execute(self, context): settings = get_settings() dbg = settings.debug #if bpy.context.mode != 'OBJECT': # bpy.ops.object.mode_set(mode = 'OBJECT') sce = context.scene #n = sce.odc_implant_index #implant_space = sce.odc_implants[n] implants = odcutils.implant_selection(context) layers_copy = [layer for layer in context.scene.collection.all_objects] context.scene.collection.all_objects[0] if implants != []: for implant_space in implants: #check if space already has an implant object. #if so, delete, replace, print warning if implant_space.implant and implant_space.implant in bpy.data.objects: self.report({ 'WARNING' }, "replacing the existing implant with the one you chose") Implant = bpy.data.objects[implant_space.implant] #the origin/location of the implant is it's apex L = Implant.location.copy() world_mx = Implant.matrix_world.copy() #the platorm is the length of the implant above the apex, in the local Z direction #local Z positive is out the apex, soit's negative. #Put the cursor there sce.cursor.location = L - Implant.dimensions[ 2] * world_mx.to_3x3() @ Vector((0, 0, 1)) #first get rid of children...so we can use the #parent to find out who the children are if Implant.children: for child in Implant.children: sce.objects.unlink(child) child.user_clear() bpy.data.objects.remove(child) #unlink it from the scene, clear it's users, remove it. sce.objects.unlink(Implant) Implant.user_clear() #remove the object bpy.data.objects.remove(Implant) #TDOD what about the children/hardwares? else: world_mx = Matrix.Identity(4) world_mx[0][3] = sce.cursor.location[0] world_mx[1][3] = sce.cursor.location[1] world_mx[2][3] = sce.cursor.location[2] #is this more memory friendly than listing all objects? current_obs = [ob.name for ob in bpy.data.objects] #link the new implant from the library odcutils.obj_from_lib(settings.imp_lib, self.imp) #this is slightly more robust than trusting we don't have duplicate names. for ob in bpy.data.objects: if ob.name not in current_obs: Implant = ob context.collection.objects.link(Implant) #this relies on the associated hardware objects having the parent implant #name inside them if self.hardware: current_obs = [ob.name for ob in bpy.data.objects] inc = self.imp + '_' hardware_list = odcutils.obj_list_from_lib( settings.imp_lib, include=inc) print(hardware_list) for ob in hardware_list: odcutils.obj_from_lib(settings.imp_lib, ob) for ob in bpy.data.objects: if ob.name not in current_obs: context.collection.objects.link(ob) ob.parent = Implant ob.layers[11] = True delta = Implant.dimensions[2] * world_mx.to_3x3() @ Vector( (0, 0, 1)) print(delta.length) world_mx[0][3] += delta[0] world_mx[1][3] += delta[1] world_mx[2][3] += delta[2] Implant.matrix_world = world_mx if sce.odc_props.master: Master = bpy.data.objects[sce.odc_props.master] odcutils.parent_in_place(Implant, Master) else: self.report({ 'WARNING' }, 'No Master Model, placing implant anyway, moving objects may not preserve spatial relationships' ) #looks a little redundant, but it ensure if any #duplicates exist our referencing stays accurate Implant.name = implant_space.name + '_' + Implant.name implant_space.implant = Implant.name odcutils.layer_management(sce.odc_implants, debug=dbg) else: world_mx = Matrix.Identity(4) world_mx[0][3] = sce.cursor.location[0] world_mx[1][3] = sce.cursor.location[1] world_mx[2][3] = sce.cursor.location[2] #is this more memory friendly than listing all objects? current_obs = [ob.name for ob in bpy.data.objects] #link the new implant from the library odcutils.obj_from_lib(settings.imp_lib, self.imp) #this is slightly more robust than trusting we don't have duplicate names. for ob in bpy.data.objects: if ob.name not in current_obs: Implant = ob context.collection.objects.link(Implant) Implant.matrix_world = world_mx for i, layer in enumerate(layers_copy): context.scene.collection.all_objects[i] = layer context.scene.collection.all_objects[11] = True return {'FINISHED'}
def load(self, context, **options): """load a sketchup file""" self.context = context self.reuse_material = options['reuse_material'] self.reuse_group = options['reuse_existing_groups'] self.max_instance = options['max_instance'] # self.render_engine = options['render_engine'] self.component_stats = defaultdict(list) self.component_skip = proxy_dict() self.component_depth = proxy_dict() self.group_written = {} ren_res_x = context.scene.render.resolution_x ren_res_y = context.scene.render.resolution_y self.aspect_ratio = ren_res_x / ren_res_y if LOGS: skp_log(f'Importing: {self.filepath}') addon_name = __name__.split('.')[0] self.prefs = context.preferences.addons[addon_name].preferences _time_main = time.time() try: self.skp_model = sketchup.Model.from_file(self.filepath) except Exception as e: if LOGS: skp_log(f'Error reading input file: {self.filepath}') skp_log(e) return {'FINISHED'} if options['import_scene']: options['scenes_as_camera'] = False options['import_camera'] = True for s in self.skp_model.scenes: if s.name == options['import_scene']: if not MIN_LOGS: skp_log(f"Importing Scene '{s.name}'") self.scene = s # s.layers are the invisible layers self.layers_skip = [l for l in s.layers] # for l in s.layers: # skp_log(f"SKIP: {l.name}") if not self.layers_skip and not MIN_LOGS: skp_log("Scene: '{}' didn't have any invisible layers.".format( options['import_scene'])) # if not self.layers_skip: # self.layers_skip = [ # l for l in self.skp_model.layers if not l.visible # ] if self.layers_skip != [] and not MIN_LOGS: hidden_layers = [l.name for l in self.layers_skip] print('SU | Invisible Layer(s)/Tag(s): \r', end='') print(*hidden_layers, sep=', ') # for l in sorted([l.name for l in self.layers_skip]): # skp_log(l) self.skp_components = proxy_dict( self.skp_model.component_definition_as_dict) if DEBUG: u_comps = [k for k, v in self.skp_components.items()] print(f'Components: {len(u_comps)} ||| \r', end='') print(*u_comps, sep=', ') if not MIN_LOGS: skp_log(f'Parsed in {(time.time() - _time_main):.4f} sec.') create_nested_collection('SKP Scenes (as Cameras)') if options['scenes_as_camera']: for s in self.skp_model.scenes: self.write_camera(s.camera, s.name) if options['import_camera']: if self.scene: active_cam = self.write_camera(self.scene.camera, name=self.scene.name) context.scene.camera = active_cam else: active_cam = self.write_camera(self.skp_model.camera) context.scene.camera = active_cam _time_material = time.time() self.write_materials(self.skp_model.materials) if not MIN_LOGS: skp_log('Materials imported ' + f'in {(time.time() - _time_material):.4f} sec.') _time_analyze_depth = time.time() D = SKP_util() SKP_util.layers_skip = self.layers_skip for c in self.skp_model.component_definitions: self.component_depth[c.name] = D.component_deps(c.entities) if DEBUG: print(f'\n-- Comp Depth: {self.component_depth[c.name]}\r', end='') print(f' ({c.name}) --') print(f'Instances: {c.numInstances}') print(f'Instances Used: {c.numUsedInstances}\n') if not MIN_LOGS: skp_log('Component depths analyzed ' + f'in {(time.time() - _time_analyze_depth):.4f} sec.') self.write_duplicateable_groups() if options["dedub_only"]: return {'FINISHED'} # self.component_stats = defaultdict(list) _time_mesh_data = time.time() create_nested_collection('SKP Mesh Objects') self.write_entities(self.skp_model.entities, "_(Loose Entity)", Matrix.Identity(4)) for k, _v in self.component_stats.items(): name, mat = k if options['dedub_type'] == "VERTEX": self.instance_group_dupli_vert(name, mat, self.component_stats) else: self.instance_group_dupli_face(name, mat, self.component_stats) if not MIN_LOGS: skp_log('Entities imported ' + f'in {(time.time() - _time_mesh_data):.4f} sec.') if LOGS: skp_log('Finished entire importing process in %.4f sec.\n' % (time.time() - _time_main)) # hide_one_level() return {'FINISHED'}
def invoke(self, context, event): if context.object: #self.value_fix_x = 0 #self.value_fix_y = 0 #self.value_fix_z = 0 ################# # for 360 array # ################# self.bend360 = False self.vert = self.tag_vert() print("TV:", self.vert) self.Q = [Quaternion((1, 0, 0, 0))] * 3 self.Q[1] = Quaternion((0.707, 0.707, 0, 0)) #Y self.Q[2] = Quaternion((0.707, 0, 0.707, 0)) #Z #mesh dupe self.mesh = context.object.data self.mesh_bu = context.object.data.copy() self.start_rot = bpy.context.object.rotation_quaternion.copy() self.start_mat = Matrix.Identity(4) self.start_mat.translation = bpy.context.object.matrix_world.translation ############## self.first_mouse_x = event.mouse_x self.first_value = context.object.location.x cArrID = -1 n = -1 is_array = False for mode in bpy.context.object.modifiers: if mode.type == 'ARRAY': is_array = True #legacy mess for x in bpy.context.object.modifiers: n += 1 if x.name == "Array": cArrID = n oo = bpy.context.object.modifiers[ "Array"].constant_offset_displace ixx = 0 if oo[1] > 0 or oo[1] < 0: ixx = 1 if oo[2] > 0 or oo[2] < 0: ixx = 2 self.nd = ixx if self.nd == 0: self.start = oo[0] elif self.nd == 1: self.start = oo[1] elif self.nd == 2: self.start = oo[2] if is_array == False: bpy.context.object.modifiers.new("Array", "ARRAY") bpy.context.object.modifiers[ "Array"].use_relative_offset = False bpy.context.object.modifiers[ "Array"].use_constant_offset = True self.first_valuex = -1 * bpy.context.object.modifiers[ "Array"].constant_offset_displace[0] self.first_valuey = -1 * bpy.context.object.modifiers[ "Array"].constant_offset_displace[1] self.first_valuez = -1 * bpy.context.object.modifiers[ "Array"].constant_offset_displace[2] self.click_pos = [event.mouse_region_x, event.mouse_region_y] self.mouse_pos = event.mouse_x self.first_mouse_x = event.mouse_x self.first_mouse_y = event.mouse_x self.first_mouse_z = event.mouse_x self.exists = False # detect serialized state. restore original if bpy.data.objects[context.object.name].get('arrAxis') != None: self.exists = True s360 = None for m in context.object.modifiers: if m.type == 'SIMPLE_DEFORM': s360 = m break if s360: self.bend360 = True self.bend360_mod = s360 self.bend360_mod.angle = 6.28319 self.bend360_mod.deform_method = 'BEND' self.dir = bpy.data.objects[context.object.name].get('arrAxis') br = bpy.data.objects[context.object.name].get('arrBaseRot') self.start_rot = Quaternion((br[0], br[1], br[2], br[3])) A = Matrix.Identity(4) self.start_mat[0] = bpy.data.objects[context.object.name].get( 'a0') self.start_mat[1] = bpy.data.objects[context.object.name].get( 'a1') self.start_mat[2] = bpy.data.objects[context.object.name].get( 'a2') self.start_mat[3] = bpy.data.objects[context.object.name].get( 'a3') A.translation = self.start_mat.translation self.start_mat = A bm = bmesh.new() bm.from_mesh(self.mesh_bu.copy()) rot = (self.Q[self.dir]).to_matrix() bmesh.ops.rotate(bm, cent=bpy.context.object.location, matrix=rot, verts=bm.verts, space=self.start_mat) #, bm.to_mesh(self.mesh_bu) self.mesh_bu.update() ############ args = (self, context) self.id = int(cArrID) self._handle = bpy.types.SpaceView3D.draw_handler_add( gui_update, args, 'WINDOW', 'POST_PIXEL') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} else: self.report({'WARNING'}, "No active object, could not finish") return {'CANCELLED'}
def drawBrick(cm, cm_id, bricksDict, key, loc, i, dimensions, zStep, brickSize, brickType, split, customData, brickScale, bricksCreated, allMeshes, logo, logo_details, mats, brick_mats, internalMat, brickHeight, logoResolution, logoDecimate, loopCut, buildIsDirty, materialType, materialName, randomMatSeed, studDetail, exposedUndersideDetail, hiddenUndersideDetail, randomRot, randomLoc, logoType, logoScale, logoInset, circleVerts, randS1, randS2, randS3): brickD = bricksDict[key] # check exposure of current [merged] brick if brickD["top_exposed"] is None or brickD[ "bot_exposed"] is None or buildIsDirty: topExposed, botExposed = setAllBrickExposures(bricksDict, zStep, key) else: topExposed, botExposed = isBrickExposed(bricksDict, zStep, key) # get brick material mat = getMaterial(cm, bricksDict, key, brickSize, zStep, materialType, materialName, randomMatSeed, brick_mats=brick_mats, seedInc=i) # set up arguments for brick mesh useStud = (topExposed and studDetail != "NONE") or studDetail == "ALL" logoToUse = logo if useStud else None undersideDetail = exposedUndersideDetail if botExposed else hiddenUndersideDetail ### CREATE BRICK ### # add brick with new mesh data at original location if brickD["type"].startswith("CUSTOM"): m = customData[int(brickD["type"][-1]) - 1] else: # get brick mesh m = getBrickData(brickD, randS3, dimensions, brickSize, brickType, brickHeight, logoResolution, logoDecimate, circleVerts, loopCut, undersideDetail, logoToUse, logoType, logo_details, logoScale, logoInset, useStud) # apply random rotation to edit mesh according to parameters randomRotMatrix = getRandomRotMatrix(randomRot, randS2, brickSize) if randomRot > 0 else None # get brick location locOffset = getRandomLoc( randomLoc, randS2, dimensions["width"], dimensions["height"]) if randomLoc > 0 else Vector((0, 0, 0)) brickLoc = getBrickCenter(bricksDict, key, loc, zStep) + locOffset if split: brick = bpy.data.objects.get(brickD["name"]) if brick: # NOTE: last brick mesh is left in memory (faster) # set brick.data to new mesh (resets materials) brick.data = m # add/remove edge split modifier if necessary eMod = brick.modifiers.get('Edge Split') if not eMod and useEdgeSplitMod(cm, brickD): addEdgeSplitMod(brick) elif eMod and not useEdgeSplitMod(cm, brickD): brick.modifiers.remove(eMod) else: # create new object with mesh data brick = bpy.data.objects.new(brickD["name"], m) brick.cmlist_id = cm_id # add edge split modifier if useEdgeSplitMod(cm, brickD): addEdgeSplitMod(brick) # rotate brick by random rotation if randomRotMatrix is not None: brick.matrix_world = Matrix.Identity(4) * randomRotMatrix # set brick location brick.location = brickLoc # set brick material if len(m.materials) > 0 or len(brick.material_slots) > 0: m.materials.clear() if mat is not None or internalMat is not None: m.materials.append(mat or internalMat) brick.material_slots[0].link = 'OBJECT' brick.material_slots[0].material = mat or internalMat # append to bricksCreated bricksCreated.append(brick) else: # apply rotation matrices to edit mesh if randomRotMatrix is not None: m.transform(randomRotMatrix) # transform brick mesh to coordinate on matrix m.transform(Matrix.Translation(brickLoc)) # keep track of mats already use if mat in mats: matIdx = mats.index(mat) elif mat is not None: mats.append(mat) matIdx = len(mats) - 1 # set material for mesh if len(m.materials) > 0: m.materials.clear() if mat is not None: m.materials.append(mat) brickD["mat_name"] = mat.name for p in m.polygons: p.material_index = matIdx # append mesh to allMeshes bmesh object allMeshes.from_mesh(m) # reset transformations for reference mesh m.transform(Matrix.Translation(-brickLoc)) if randomRotMatrix is not None: randomRotMatrix.invert() m.transform(randomRotMatrix) return bricksDict
def import_tabula4(tblzip, jsonmodel, animations_only, scene): with ExitStack() as stack: bm = bmesh.new() stack.callback(bm.free) model_name = jsonmodel['modelName'] author = jsonmodel['authorName'] mesh = bpy.data.meshes.new(model_name) mesh.mcprops.artist = author uvmap = mesh.uv_textures.new('UVMap') bm.from_mesh(mesh) uvloop = bm.loops.layers.uv[uvmap.name] identifier_to_cube = set() tex_width = jsonmodel['textureWidth'] tex_height = jsonmodel['textureHeight'] texture_matrix = Matrix.Identity(3) texture_matrix[0][0] = 1 / tex_width texture_matrix[1][1] = -1 / tex_height texture_matrix[1][2] = 1 print(texture_matrix) texture_name = 'texture.png' try: tblzip.extract(texture_name, path=bpy.app.tempdir) texture_file = os.path.join(bpy.app.tempdir, texture_name) except KeyError: Reporter.error("Missing texture file", texname=texture_file) else: image = bpy.data.images.load(texture_file) image.pack() image.use_alpha = True os.remove(texture_file) def Position(vec): s = Matrix.Identity(4) s.row[0][3], s.row[1][3], s.row[2][3] = vec return s def Scale(vec): s = Matrix.Identity(4) s.row[0][0], s.row[1][1], s.row[2][2] = vec return s def Rotation(rot): return Euler(rot, 'XYZ').to_matrix().to_4x4() def emit_cube(cube, local_to_global): offset = Position(cube['offset']) # Offset dim_x, dim_y, dim_z = cube['dimensions'] dimensions = Scale((dim_x, dim_y, dim_z)) matrix = local_to_global * offset * dimensions tx_transform = Matrix.Identity(3) tx_transform.col[2] =\ cube['txOffset'][0], cube['txOffset'][1], 1 tx_transform = texture_matrix * tx_transform print(tx_transform) v0 = bm.verts.new((matrix * Vector((0, 0, 0, 1)))[0:3]) v1 = bm.verts.new((matrix * Vector((0, 0, 1, 1)))[0:3]) v2 = bm.verts.new((matrix * Vector((0, 1, 0, 1)))[0:3]) v3 = bm.verts.new((matrix * Vector((0, 1, 1, 1)))[0:3]) v4 = bm.verts.new((matrix * Vector((1, 0, 0, 1)))[0:3]) v5 = bm.verts.new((matrix * Vector((1, 0, 1, 1)))[0:3]) v6 = bm.verts.new((matrix * Vector((1, 1, 0, 1)))[0:3]) v7 = bm.verts.new((matrix * Vector((1, 1, 1, 1)))[0:3]) bm.edges.new((v0, v1)) bm.edges.new((v0, v2)) bm.edges.new((v0, v4)) bm.edges.new((v1, v3)) bm.edges.new((v1, v5)) bm.edges.new((v2, v3)) bm.edges.new((v2, v6)) bm.edges.new((v3, v7)) bm.edges.new((v4, v5)) bm.edges.new((v4, v6)) bm.edges.new((v5, v7)) bm.edges.new((v6, v7)) f0 = bm.faces.new((v0, v1, v3, v2)) f1 = bm.faces.new((v0, v4, v5, v1)) f2 = bm.faces.new((v0, v2, v6, v4)) f3 = bm.faces.new((v4, v6, v7, v5)) f4 = bm.faces.new((v2, v3, v7, v6)) f5 = bm.faces.new((v1, v5, v7, v3)) f0.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z, 1)))[0:2] f0.loops[1][uvloop].uv = (tx_transform * Vector( (0, dim_z, 1)))[0:2] f0.loops[2][uvloop].uv = (tx_transform * Vector( (0, dim_z + dim_y, 1)))[0:2] f0.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z + dim_y, 1)))[0:2] f1.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z, 1)))[0:2] f1.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f1.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, 0, 1)))[0:2] f1.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z, 0, 1)))[0:2] f2.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z, 1)))[0:2] f2.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z + dim_y, 1)))[0:2] f2.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z + dim_y, 1)))[0:2] f2.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f3.loops[0][uvloop].uv = (tx_transform * Vector( (2 * dim_z + 2 * dim_x, dim_z, 1)))[0:2] f3.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z, 1)))[0:2] f3.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2] f3.loops[3][uvloop].uv = (tx_transform * Vector( (2 * dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2] f4.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z, 1)))[0:2] f4.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, 0, 1)))[0:2] f4.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, 0, 1)))[0:2] f4.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f5.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f5.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z + dim_y, 1)))[0:2] f5.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2] f5.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z, 1)))[0:2] bm.verts.index_update() bm.edges.index_update() bm.faces.index_update() bm.normal_update() return def make_cube(cube, to_global): identifier = cube['identifier'] name = cube['name'] position = Position(cube['position']) # Rotation point scale = Scale(cube['scale']) rotation = Rotation(cube['rotation']) local_to_global = to_global * position * rotation * scale if identifier in identifier_to_cube: Reporter.warning("Identifier reused in the model: {id}", id=identifier) identifier_to_cube.add(identifier) emit_cube(cube, local_to_global) for child in cube['children']: make_cube(child, local_to_global) def make_group(group, to_global): for cube in group['cubes']: make_cube(cube, to_global) for child in group['cubeGroups']: make_cube(child, to_global) model_transform = Matrix.Scale(1 / 16, 4) model_transform[1][2] = model_transform[2][2] model_transform[2][1] = -model_transform[1][1] model_transform[1][1] = model_transform[2][2] = 0 model_transform[2][3] = 51 / 32 model_transform *= Scale(jsonmodel['scale']) for group in jsonmodel['cubeGroups']: make_group(group, model_transform) for cube in jsonmodel['cubes']: make_cube(cube, model_transform) bm.to_mesh(mesh) object = bpy.data.objects.new(model_name, mesh) scene.objects.link(object) scene.update() def make_animation(*args): pass # TODO: import animations aswell? for animation in jsonmodel['anims']: make_animation(animation, model_transform)
def click_add_point(self,context,x,y, label = None): ''' x,y = event.mouse_region_x, event.mouse_region_y this will add a point into the bezier curve or close the curve into a cyclic curve ''' region = context.region rv3d = context.region_data coord = x, y view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) ray_target = ray_origin + (view_vector * 1000) hit = False if self.snap_type == 'SCENE': mx = Matrix.Identity(4) #loc is given in world loc...no need to multiply by obj matrix imx = Matrix.Identity(4) no_mx = Matrix.Identity(3) if bversion() < '002.077.000': res, obj, omx, loc, no = context.scene.ray_cast(ray_origin, ray_target) #changed in 2.77 else: res, loc, no, ind, obj, omx = context.scene.ray_cast(ray_origin, view_vector) iomx = omx.inverted() no_mx = iomx.to_3x3().transposed() hit = res if not hit: #cast the ray into a plane a #perpendicular to the view dir, at the last bez point of the curve view_direction = rv3d.view_rotation * Vector((0,0,-1)) if len(self.b_pts): plane_pt = self.b_pts[-1] else: plane_pt = context.scene.cursor_location loc = intersect_line_plane(ray_origin, ray_target,plane_pt, view_direction) hit = True elif self.snap_type == 'OBJECT': mx = self.snap_ob.matrix_world imx = mx.inverted() no_mx = imx.to_3x3().transposed() if bversion() < '002.077.000': loc, no, face_ind = self.snap_ob.ray_cast(imx * ray_origin, imx * ray_target) if face_ind != -1: hit = True else: ok, loc, no, face_ind = self.snap_ob.ray_cast(imx * ray_origin, imx * ray_target - imx*ray_origin) if ok: hit = True if face_ind != -1: hit = True if not hit: self.selected = -1 return if self.hovered[0] == None: #adding in a new point self.b_pts.append(mx * loc) self.normals.append(no_mx * no) self.labels.append(label) return True if self.hovered[0] == 'POINT': self.selected = self.hovered[1] return
def Position(vec): s = Matrix.Identity(4) s.row[0][3], s.row[1][3], s.row[2][3] = vec return s
def load(self, context, **options): """load a sketchup file""" self.context = context self.reuse_material = options['reuse_material'] self.reuse_group = options['reuse_existing_groups'] self.max_instance = options['max_instance'] self.component_stats = defaultdict(list) self.component_skip = proxy_dict() self.component_depth = proxy_dict() self.group_written = {} self.aspect_ratio = context.scene.render.resolution_x / context.scene.render.resolution_y sketchupLog('importing skp %r' % self.filepath) addon_name = __name__.split('.')[0] self.prefs = context.user_preferences.addons[addon_name].preferences time_main = time.time() try: self.skp_model = sketchup.Model.from_file(self.filepath) except Exception as e: sketchupLog('Error reading input file: %s' % self.filepath) sketchupLog(e) return {'FINISHED'} if options['import_scene']: for s in self.skp_model.scenes: if s.name == options['import_scene']: sketchupLog("Importing Scene \"{}\" ".format(s.name)) self.scene = s self.layers_skip = [l for l in s.layers] for l in s.layers: sketchupLog("SKIP: {}".format(l.name)) if not self.layers_skip: sketchupLog('Could not find scene {} importing default'.format( options['import_scene'])) if not self.layers_skip: self.layers_skip = [ l for l in self.skp_model.layers if not l.visible ] sketchupLog('Skipping layers: ') for l in sorted([l.name for l in self.layers_skip]): sketchupLog(l) self.skp_components = proxy_dict( self.skp_model.component_definition_as_dict) sketchupLog('parsed skp %r in %.4f sec.' % (self.filepath, (time.time() - time_main))) if options['scenes_as_camera']: for s in self.skp_model.scenes: self.write_camera(s.camera, s.name) if options['import_camera']: if self.scene: active_cam = self.write_camera(self.scene.camera, name=self.scene.name) context.scene.camera = active_cam else: active_cam = self.write_camera(self.skp_model.camera) context.scene.camera = active_cam t1 = time.time() self.write_materials(self.skp_model.materials) sketchupLog('imported materials in %.4f sec' % (time.time() - t1)) t1 = time.time() D = SKP_util() SKP_util.layers_skip = self.layers_skip for c in self.skp_model.component_definitions: self.component_depth[c.name] = D.component_deps(c.entities) sketchupLog('analyzed component depths in %.4f sec' % (time.time() - t1)) self.write_duplicateable_groups() if options["dedub_only"]: return {'FINISHED'} self.component_stats = defaultdict(list) self.write_entities(self.skp_model.entities, "Sketchup", Matrix.Identity(4)) for k, v in self.component_stats.items(): name, mat = k if options['dedub_type'] == "VERTEX": self.instance_group_dupli_vert(name, mat, self.component_stats) else: self.instance_group_dupli_face(name, mat, self.component_stats) sketchupLog('imported entities in %.4f sec' % (time.time() - t1)) sketchupLog('finished importing %s in %.4f sec ' % (self.filepath, time.time() - time_main)) return {'FINISHED'}
def Scale(vec): s = Matrix.Identity(4) s.row[0][0], s.row[1][1], s.row[2][2] = vec return s
def push_custom_matrix_if_present(self, sv_object, matrix): if matrix: # matrix = matrix_sanitizer(matrix) sv_object.matrix_local = matrix else: sv_object.matrix_local = Matrix.Identity(4)
def emit_cube(cube, local_to_global): offset = Position(cube['offset']) # Offset dim_x, dim_y, dim_z = cube['dimensions'] dimensions = Scale((dim_x, dim_y, dim_z)) matrix = local_to_global * offset * dimensions tx_transform = Matrix.Identity(3) tx_transform.col[2] =\ cube['txOffset'][0], cube['txOffset'][1], 1 tx_transform = texture_matrix * tx_transform print(tx_transform) v0 = bm.verts.new((matrix * Vector((0, 0, 0, 1)))[0:3]) v1 = bm.verts.new((matrix * Vector((0, 0, 1, 1)))[0:3]) v2 = bm.verts.new((matrix * Vector((0, 1, 0, 1)))[0:3]) v3 = bm.verts.new((matrix * Vector((0, 1, 1, 1)))[0:3]) v4 = bm.verts.new((matrix * Vector((1, 0, 0, 1)))[0:3]) v5 = bm.verts.new((matrix * Vector((1, 0, 1, 1)))[0:3]) v6 = bm.verts.new((matrix * Vector((1, 1, 0, 1)))[0:3]) v7 = bm.verts.new((matrix * Vector((1, 1, 1, 1)))[0:3]) bm.edges.new((v0, v1)) bm.edges.new((v0, v2)) bm.edges.new((v0, v4)) bm.edges.new((v1, v3)) bm.edges.new((v1, v5)) bm.edges.new((v2, v3)) bm.edges.new((v2, v6)) bm.edges.new((v3, v7)) bm.edges.new((v4, v5)) bm.edges.new((v4, v6)) bm.edges.new((v5, v7)) bm.edges.new((v6, v7)) f0 = bm.faces.new((v0, v1, v3, v2)) f1 = bm.faces.new((v0, v4, v5, v1)) f2 = bm.faces.new((v0, v2, v6, v4)) f3 = bm.faces.new((v4, v6, v7, v5)) f4 = bm.faces.new((v2, v3, v7, v6)) f5 = bm.faces.new((v1, v5, v7, v3)) f0.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z, 1)))[0:2] f0.loops[1][uvloop].uv = (tx_transform * Vector( (0, dim_z, 1)))[0:2] f0.loops[2][uvloop].uv = (tx_transform * Vector( (0, dim_z + dim_y, 1)))[0:2] f0.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z + dim_y, 1)))[0:2] f1.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z, 1)))[0:2] f1.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f1.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, 0, 1)))[0:2] f1.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z, 0, 1)))[0:2] f2.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z, 1)))[0:2] f2.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z, dim_z + dim_y, 1)))[0:2] f2.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z + dim_y, 1)))[0:2] f2.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f3.loops[0][uvloop].uv = (tx_transform * Vector( (2 * dim_z + 2 * dim_x, dim_z, 1)))[0:2] f3.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z, 1)))[0:2] f3.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2] f3.loops[3][uvloop].uv = (tx_transform * Vector( (2 * dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2] f4.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z, 1)))[0:2] f4.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, 0, 1)))[0:2] f4.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, 0, 1)))[0:2] f4.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f5.loops[0][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z, 1)))[0:2] f5.loops[1][uvloop].uv = (tx_transform * Vector( (dim_z + dim_x, dim_z + dim_y, 1)))[0:2] f5.loops[2][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2] f5.loops[3][uvloop].uv = (tx_transform * Vector( (dim_z + 2 * dim_x, dim_z, 1)))[0:2] bm.verts.index_update() bm.edges.index_update() bm.faces.index_update() bm.normal_update() return
def finish(self, context): #ray cast the entire grid into if 'Posterior Plane' in bpy.data.objects: Plane = bpy.data.objects['Posterior Plane'] Plane.hide = False else: me = bpy.data.meshes.new('Posterior Plane') Plane = bpy.data.objects.new('Posterior Plane', me) context.scene.objects.link(Plane) pbme = bmesh.new() pbme.verts.ensure_lookup_table() pbme.edges.ensure_lookup_table() pbme.faces.ensure_lookup_table() bmesh.ops.create_grid(pbme, x_segments = 200, y_segments = 200, size = 39.9) pbme.to_mesh(Plane.data) pt, pno = calculate_plane(self.crv.b_pts) if self.splint.jaw_type == 'MANDIBLE': Zw = Vector((0,0,-1)) Xw = Vector((1,0,0)) Yw = Vector((0,-1,1)) else: Zw = Vector((0,0,1)) Xw = Vector((1,0,0)) Yw = Vector((0,1,0)) Z = pno Z.normalize() if Zw.dot(Z) < 0: Z *= -1 Y = Z.cross(Xw) X = Y.cross(Z) R = Matrix.Identity(3) #make the columns of matrix U, V, W R[0][0], R[0][1], R[0][2] = X[0] ,Y[0], Z[0] R[1][0], R[1][1], R[1][2] = X[1], Y[1], Z[1] R[2][0] ,R[2][1], R[2][2] = X[2], Y[2], Z[2] R = R.to_4x4() T = Matrix.Translation(pt - 5 * Z) Plane.matrix_world = T * R pmx = Plane.matrix_world ipmx = pmx.inverted() bme_pln = bmesh.new() bme_pln.from_mesh(Plane.data) bme_pln.verts.ensure_lookup_table() bme_pln.edges.ensure_lookup_table() bme_pln.faces.ensure_lookup_table() bvh = BVHTree.FromBMesh(bme_pln) #we are going to raycast the user world coordinate points #into a grid, and identify all points in the grid from the local Z direction #Then we will store the local location of the user picked coordinate in a dictionary key_verts = {} for loc in self.crv.b_pts: res = bvh.ray_cast(ipmx * loc, -Z, 30) if res[0] != None: f = bme_pln.faces[res[2]] for v in f.verts: key_verts[v] = ipmx * loc v.select_set(True) continue res = bvh.ray_cast(ipmx * loc, Z, 30) if res[0] != None: f = bme_pln.faces[res[2]] for v in f.verts: key_verts[v] = ipmx * loc v.select_set(True) continue #bme_pln.to_mesh(Plane.data) #bme_pln.free() #return kdtree = KDTree(len(key_verts)) for v in key_verts.keys(): kdtree.insert(v.co, v.index) kdtree.balance() #raycast the shell if we can raycast_shell = False if 'Splint Shell' in bpy.data.objects: shell = bpy.data.objects.get('Splint Shell') bvh_shell = BVHTree.FromObject(shell, context.scene) mx_shell = shell.matrix_world imx_shell = mx_shell.inverted() Z_shell = imx_shell.to_3x3()*Z raycast_shell = True right_side = set() left_side = set() ray_casted = set() to_delete = set() for v in bme_pln.verts: if v in key_verts: v.co[2] = key_verts[v][2] if v.co[1] > 0: left_side.add(v) else: right_side.add(v) continue results = kdtree.find_range(v.co, .5) if len(results): N = len(results) r_total = 0 v_new = Vector((0,0,0)) for res in results: r_total += 1/res[2] v_new += (1/res[2]) * key_verts[bme_pln.verts[res[1]]] v_new *= 1/r_total v.co[2] = v_new[2] if v.co[1] > 0: left_side.add(v) else: right_side.add(v) continue results = kdtree.find_range(v.co, 6) if len(results): N = len(results) r_total = 0 v_new = Vector((0,0,0)) for res in results: r_total += (1/res[2])**2 v_new += ((1/res[2])**2) * key_verts[bme_pln.verts[res[1]]] v_new *= 1/r_total v.co[2] = v_new[2] if v.co[1] > 0: left_side.add(v) else: right_side.add(v) continue loc, no, index, d = bvh_shell.ray_cast(imx_shell * pmx * v.co, Z_shell) if loc: ray_casted.add(v) results = kdtree.find_n(v.co, 4) N = len(results) r_total = 0 v_new = Vector((0,0,0)) for res in results: r_total += (1/res[2])**2 v_new += ((1/res[2])**2) * key_verts[bme_pln.verts[res[1]]] v_new *= 1/r_total v.co[2] = v_new[2] continue total_verts = ray_casted | left_side | right_side ant_left = max(left_side, key = lambda x: x.co[0]) ant_right = max(right_side, key = lambda x: x.co[0]) new_verts = set() dilation_verts = set() for v in total_verts: for ed in v.link_edges: v_new = ed.other_vert(v) if v_new in total_verts or v_new in new_verts: continue else: new_verts.add(v_new) print('adding %i new verts' % len(new_verts)) total_verts.update(new_verts) dilation_verts.update(new_verts) #for v in ray_casted: # if v.co[1] > 0: # if v.co[0] > ant_left.co[0]: # to_delete.add(v) # else: # if v.co[0] > ant_right.co[0]: # to_delete.add(v) #print('added %i ray_casted' % len(ray_casted)) #total_verts = ray_casted | left_side | right_side #total_verts.difference_update(to_delete) #new_verts = set() #for v in total_verts: # for ed in v.link_edges: # v_new = ed.other_vert(v) # if v_new in total_verts: continue # if v_new.co[1] > 0 and v_new.co[0] < ant_left.co[0]: # if v in to_delete: # new_verts.add(v) # if v_new.co[1] <= 0 and v_new.co[0] < ant_right.co[0]: # if v in to_delete: # new_verts.add(v) #to_delete.difference_update(new_verts) #print('adding %i new verts' % len(new_verts)) for j in range(0,3): newer_verts = set() for v in new_verts: for ed in v.link_edges: v_new = ed.other_vert(v) if v_new in total_verts or v_new in newer_verts: continue newer_verts.add(v_new) total_verts.update(newer_verts) dilation_verts.update(newer_verts) new_verts = newer_verts to_delete = set(bme_pln.verts[:]) - total_verts #filter out anteior dilation for v in dilation_verts: if v.co[1] > 0 and v.co[0] > ant_left.co[0]: to_delete.add(v) continue if v.co[1] <= 0 and v.co[0] > ant_right.co[0]: to_delete.add(v) continue results = kdtree.find_n(v.co, 4) N = len(results) r_total = 0 v_new = Vector((0,0,0)) for res in results: r_total += (1/res[2])**2 v_new += ((1/res[2])**2) * key_verts[bme_pln.verts[res[1]]] v_new *= 1/r_total v.co[2] = v_new[2] #filter out anteior dilation for v in ray_casted: if v.co[1] > 0 and v.co[0] > ant_left.co[0]: to_delete.add(v) continue if v.co[1] <= 0 and v.co[0] > ant_right.co[0]: to_delete.add(v) continue bmesh.ops.delete(bme_pln, geom = list(to_delete), context = 1) bme_pln.to_mesh(Plane.data) Plane.data.update() smod = Plane.modifiers.new('Smooth', type = 'SMOOTH') smod.iterations = 5 smod.factor = 1 self.splint.ops_string += 'Mark Posterior Cusps:'
def scale_matrix(factor): m = Matrix.Identity(4) m[0][0] = factor m[1][1] = factor m[2][2] = factor return m
def getDefaultValue(cls): return Matrix.Identity(4)
def ImportMD3(model_name, zoffset, import_tags): mesh = None skip = False try: file = open(model_name, "rb") except: return mesh if (not skip): magic_nr = file.read(4) version_nr = struct.unpack("<i", file.read(4))[0] md3 = MD3(file, magic_nr, version_nr) if (not md3.valid): print("this md3 version is not supported\n") skip = True if (not skip): name = file.read(64).decode("utf-8", errors="ignore").strip("\0") print("Import MD3: " + name) flags = struct.unpack("<i", file.read(4))[0] numFrames = struct.unpack("<i", file.read(4))[0] numTags = struct.unpack("<i", file.read(4))[0] numSurfaces = struct.unpack("<i", file.read(4))[0] numSkins = struct.unpack("<i", file.read(4))[0] ofsFrames = struct.unpack("<i", file.read(4))[0] ofsTags = struct.unpack("<i", file.read(4))[0] ofsSurfaces = struct.unpack("<i", file.read(4))[0] ofsEnd = struct.unpack("<i", file.read(4))[0] print("flags: " + str(flags)) print("numFrames: " + str(numFrames)) print("numTags: " + str(numTags)) print("numSurfaces: " + str(numSurfaces)) print("numSkins: " + str(numSkins)) print("ofsFrames: " + str(ofsFrames)) print("ofsTags: " + str(ofsTags)) print("ofsSurfaces: " + str(ofsSurfaces)) print("ofsEnd: " + str(ofsEnd)) surface_lumps = [] for surface_lump in range(numSurfaces): surface = lump(md3.surface) surface.set_offset_count([ofsSurfaces,1]) surface.readFrom(file) surface.data[0].vertices.readFrom(file,ofsSurfaces) surface.data[0].tcs.readFrom(file,ofsSurfaces) surface.data[0].shaders.readFrom(file,ofsSurfaces) surface.data[0].triangles.readFrom(file,ofsSurfaces) surface_lumps.append(surface) ofsSurfaces += surface.data[0].off_end frames = lump(md3.frame) frames.set_offset_count([ofsFrames, numFrames]) frames.readFrom(file) for frame_id, frame in enumerate(frames.data): print("\tFrame Nr " + str(frame_id)) print("\t\tName: " + str(frame.name)) print("\t\tLocal Origin: " + str(frame.local_origin)) print("\t\tRadius: " + str(frame.radius)) if import_tags: tag_lump = lump(md3.tag) tag_lump.set_offset_count([ofsTags, numTags]) tag_lump.readFrom(file) for tag in range(numTags): bpy.ops.object.empty_add(type="ARROWS") tag_obj = bpy.context.object tag_obj.name = tag_lump.data[tag].name matrix = Matrix.Identity(4) matrix[0] = [*tag_lump.data[tag].axis_1, 0.0] matrix[1] = [*tag_lump.data[tag].axis_2, 0.0] matrix[2] = [*tag_lump.data[tag].axis_3, 0.0] matrix.transpose() matrix.translation = tag_lump.data[tag].origin tag_obj.matrix_world = matrix vertex_pos = [] vertex_nor = [] vertex_tc = [] face_indices = [] face_tcs = [] face_shaders = [] shaderindex = 0 face_index_offset = 0 face_material_index = [] #vertex groups surfaces = {} for surface_id, surface in enumerate(surface_lumps): print("\tSurface Nr " + str(surface_id)) n_indices = 0 surface_indices = [] for vertex, tc in zip(surface.data[0].vertices.data, surface.data[0].tcs.data): vertex_pos.append(vertex.position) vertex_nor.append(vertex.normal) vertex_tc.append(tc.tc) n_indices += 1 for triangle in surface.data[0].triangles.data: triangle_indices = [ triangle.indices[0] + face_index_offset, triangle.indices[1] + face_index_offset, triangle.indices[2] + face_index_offset] surface_indices.append(triangle_indices) face_indices.append(triangle_indices) face_tcs.append(vertex_tc[triangle_indices[0]]) face_tcs.append(vertex_tc[triangle_indices[1]]) face_tcs.append(vertex_tc[triangle_indices[2]]) face_material_index.append(shaderindex) print("\t\tnumTriangles: " + str(len(surface.data[0].triangles.data))) print("\t\tnumShaders: " + str(len(surface.data[0].shaders.data))) for shader_id, shader in enumerate(surface.data[0].shaders.data): print("\t\t\t" + str(shader_id) + ": " + str(shader.name)) surfaces[surface.data[0].name] = unpack_list(surface_indices) face_shaders.append(surface.data[0].shaders.data[0]) shaderindex += 1 face_index_offset += n_indices guessed_name = guess_model_name( model_name.lower() ).lower() if guessed_name.endswith(".md3"): guessed_name = guessed_name[:-len(".md3")] mesh = bpy.data.meshes.new( guessed_name ) mesh.from_pydata(vertex_pos, [], face_indices) #oh man... if zoffset == 0: material_suffix = ".grid" else: material_suffix = "." + str(zoffset) + "grid" for texture_instance in face_shaders: mat = bpy.data.materials.get(texture_instance.name + material_suffix) if (mat == None): mat = bpy.data.materials.new(name=texture_instance.name + material_suffix) mesh.materials.append(mat) mesh.polygons.foreach_set("material_index", face_material_index) for poly in mesh.polygons: poly.use_smooth = True mesh.vertices.foreach_set("normal", unpack_list(vertex_nor)) mesh.normals_split_custom_set_from_vertices(vertex_nor) mesh.uv_layers.new(do_init=False,name="UVMap") mesh.uv_layers["UVMap"].data.foreach_set("uv", unpack_list(face_tcs)) mesh.use_auto_smooth = True mesh.update() file.close return mesh
def main_SVD(context, down_sample, method, spin_res, make_box): start = time.time() world_mx = context.object.matrix_world scale = world_mx.to_scale() trans = world_mx.to_translation() tr_mx = Matrix.Identity(4) sc_mx = Matrix.Identity(4) tr_mx[0][3], tr_mx[1][3], tr_mx[2][3] = trans[0], trans[1], trans[2] sc_mx[0][0], sc_mx[1][1], sc_mx[2][2] = scale[0], scale[1], scale[2] r_mx = world_mx.to_quaternion().to_matrix().to_4x4() me = context.object.data bme = bmesh.new() bme.from_mesh(me) convex_hull = bmesh.ops.convex_hull(bme, input=bme.verts, use_existing_faces=True) total_hull = convex_hull['geom'] hull_verts = [item for item in total_hull if hasattr(item, 'co')] hull_faces = [item for item in total_hull if hasattr(item, 'no')] #hull_bme = bmesh.new() #hull_bme.verts = hull_verts #hull_bme.faces = hull_faces vert_data = [v.co for v in hull_verts] # ToDo...world coords better? v0 = np.array(vert_data, dtype=np.float64, copy=True) ndims = v0.shape[0] # move data to origin t0 = -np.mean(v0, axis=1) M0 = np.identity(ndims + 1) M0[:ndims, ndims] = t0 v0 += t0.reshape(ndims, 1) U, s, V = np.linalg.svd(v0, full_matrices=True) # make a rotation matrix from eigenvectors (easy) rmx = Matrix.Identity(4) rmx[0][0], rmx[0][1], rmx[0][2] = V[0][0], V[0][1], V[0][2] rmx[1][0], rmx[1][1], rmx[1][2] = V[1][0], V[1][1], V[1][2] rmx[2][0], rmx[2][1], rmx[2][2] = V[2][0], V[2][1], V[2][2] min_box = bbox_orient(vert_data, rmx) min_vol = bbox_vol(min_box) min_angle = 0 min_mx = rmx # these are our PCA directions X = Vector((V[0][0], V[0][1], V[0][2])) Y = Vector((V[1][0], V[1][1], V[1][2])) Z = Vector((V[2][0], V[2][1], V[2][2])) for n in range(0, 2 * spin_res): angle = math.pi * n / (2 * spin_res) rmx = Matrix.Identity(4) if method == 'pca_x': # keep x axis and rotate around it rmx[0][0], rmx[0][1], rmx[0][2] = X[0], X[1], X[2] y = math.cos(angle) * Y + math.sin(angle) * Z y.normalize() rmx[1][0], rmx[1][1], rmx[1][2] = y[0], y[1], y[2] z = -math.sin(angle) * Y + math.cos(angle) * Z z.normalize() rmx[2][0], rmx[2][1], rmx[2][2] = z[0], z[1], z[2] elif method == 'pca_y': # keep y axis and rotate around it x = math.cos(angle) * X - math.sin(angle) * Z x.normalize() rmx[0][0], rmx[0][1], rmx[0][2] = x[0], x[1], x[2] # keep y rmx[1][0], rmx[1][1], rmx[1][2] = Y[0], Y[1], Y[2] z = math.sin(angle) * X + math.cos(angle) * Z z.normalize() rmx[2][0], rmx[2][1], rmx[2][2] = z[0], z[1], z[2] else: x = math.cos(angle) * X + math.sin(angle) * Y x.normalize() rmx[0][0], rmx[0][1], rmx[0][2] = x[0], x[1], x[2] y = -math.sin(angle) * X + math.cos(angle) * Y y.normalize() rmx[1][0], rmx[1][1], rmx[1][2] = y[0], y[1], y[2] # Keep Z rmx[2][0], rmx[2][1], rmx[2][2] = Z[0], Z[1], Z[2] box = bbox_orient(vert_data, rmx) test_V = bbox_vol(box) if test_V < min_vol: min_angle = angle min_box = box min_mx = rmx min_vol = test_V if make_box: box_verts = box_cords(box) bpy.ops.mesh.primitive_cube_add() context.object.matrix_world = rmx.transposed().inverted( ) * world_mx context.object.draw_type = 'BOUNDS' for i, v in enumerate(box_verts): context.object.data.vertices[i].co = v elapsed_time = time.time() - start print( 'found bbox of volume %f in %f seconds with SVD followed by rotating calipers' % (min_vol, elapsed_time)) box_verts = box_cords(min_box) bpy.ops.mesh.primitive_cube_add() #FinalMatrix = TranslationMatrix * RotationMatrix * ScaleMatrix fmx = tr_mx * r_mx * min_mx.inverted() * sc_mx context.object.matrix_world = fmx context.object.draw_type = 'BOUNDS' for i, v in enumerate(box_verts): context.object.data.vertices[i].co = v bme.free()
def join_bmesh(source, target, src_trg_map, src_mx = None, trg_mx = None): ''' ''' L = len(target.verts) print('Target has %i verts' % L) print('Source has %i verts' % len(source.verts)) l = len(src_trg_map) print('is the src_trg_map being sticky...%i' % l) if not src_mx: src_mx = Matrix.Identity(4) if not trg_mx: trg_mx = Matrix.Identity(4) i_trg_mx = Matrix.Identity(4) else: i_trg_mx = trg_mx.inverted() new_bmverts = [] source.verts.ensure_lookup_table() for v in source.verts: if v.index not in src_trg_map: new_ind = len(target.verts) new_bv = target.verts.new(i_trg_mx * src_mx * v.co) new_bmverts.append(new_bv) #new_bv.index = new_ind src_trg_map[v.index] = new_ind #new_bmverts = [target.verts.new(i_trg_mx * src_mx * v.co) for v in source.verts]# if v.index not in src_trg_map] #def src_to_trg_ind(v): # subbed = False # if v.index in src_trg_map: # new_ind = src_trg_map[v.index] # subbed = True # else: # new_ind = v.index + L #TODO, this takes the actual versts from sources, these verts are in target # return new_ind, subbed #new_bmfaces = [target.faces.new(tuple(new_bmverts[v.index] for v in face.verts)) for face in source.faces] target.verts.index_update() #target.verts.sort() #does this still work? target.verts.ensure_lookup_table() #print('new faces') #for f in source.faces: #print(tuple(src_to_trg_ind(v) for v in f.verts)) #subbed = set() new_bmfaces = [] for f in source.faces: v_inds = [] for v in f.verts: new_ind = src_trg_map[v.index] v_inds.append(new_ind) new_bmfaces += [target.faces.new(tuple(target.verts[i] for i in v_inds))] #new_bmfaces = [target.faces.new(tuple(target.verts[src_to_trg_ind(v)] for v in face.verts)) for face in source.faces] target.faces.ensure_lookup_table() target.verts.ensure_lookup_table() target.verts.index_update() #throw away the loose verts...not very elegant with edges and what not #n_removed = 0 #for vert in new_bmverts: # if (vert.index - L) in src_trg_map: #these are verts that are not needed # target.verts.remove(vert) # n_removed += 1 #bmesh.ops.delete(target, geom=del_verts, context=1) target.verts.index_update() target.verts.ensure_lookup_table() target.faces.ensure_lookup_table() new_L = len(target.verts) if src_trg_map: if new_L != L + len(source.verts) -l: print('seems some verts were left in that should not have been') del src_trg_map
def join_bmesh_map(source, target, src_trg_map = None, src_mx = None, trg_mx = None): ''' ''' L = len(target.verts) if not src_trg_map: src_trg_map = {-1:-1} l = len(src_trg_map) print('There are %i items in the vert map' % len(src_trg_map)) if not src_mx: src_mx = Matrix.Identity(4) if not trg_mx: trg_mx = Matrix.Identity(4) i_trg_mx = Matrix.Identity(4) else: i_trg_mx = trg_mx.inverted() old_bmverts = [v for v in target.verts] #this will store them in order new_bmverts = [] #these will be created in order source.verts.ensure_lookup_table() for v in source.verts: if v.index not in src_trg_map: new_ind = len(target.verts) new_bv = target.verts.new(i_trg_mx * src_mx * v.co) new_bmverts.append(new_bv) #gross...append src_trg_map[v.index] = new_ind else: print('vert alread in the map %i' % v.index) lverts = old_bmverts + new_bmverts target.verts.index_update() target.verts.ensure_lookup_table() new_bmfaces = [] for f in source.faces: v_inds = [] for v in f.verts: new_ind = src_trg_map[v.index] v_inds.append(new_ind) if any([i > len(lverts)-1 for i in v_inds]): print('impending index error') print(len(lverts)) print(v_inds) if target.faces.get(tuple(lverts[i] for i in v_inds)): print(v_inds) continue new_bmfaces += [target.faces.new(tuple(lverts[i] for i in v_inds))] target.faces.ensure_lookup_table() target.verts.ensure_lookup_table() new_L = len(target.verts) if src_trg_map: if new_L != L + len(source.verts) -l: print('seems some verts were left in that should not have been')
def calc_vert_tangents_wire(self, obmat, viewmat): """self.loop_tris.bmのWIREフラグが立っている頂点のtangentを計算。 """ WIRE = self.WIRE loop_tris = self.loop_tris vert_tangents = {} # eve: Vector if viewmat: obmat3 = obmat.to_3x3() vmat3 = viewmat.to_3x3() else: obmat3 = Matrix.Identity(3) vmat3 = Matrix.Identity(3) edges = [ eed for eed in loop_tris.bm.edges if loop_tris.eflags[eed] & WIRE ] paths = vabm.make_paths_from_edges(edges=edges) for path in paths: verts = path[:] if verts[0] == verts[-1]: verts = verts[:-1] vecs = [v.co for v in verts] bbmat, bbscale = vam.get_obb(vecs) bbmat3 = bbmat.to_3x3() # 点 if bbscale[0] < EPS: pass # 直線。tangentの方向はview_matrixに依存 elif bbscale[1] < EPS: axis = vmat3 * obmat3 * bbmat3.col[0] axis.normalize() ax = Vector((-axis[1], axis[0], 0)) vec = obmat3.inverted() * (vmat3.inverted() * ax) vec.normalize() # vec: 画面と平行でpathと垂直なベクトル for eve in verts: if loop_tris.vflags[eve] & WIRE: vert_tangents[eve] = [vec.copy() for i in range(3)] else: # 平面、立体 imat3 = bbmat3.inverted() vecs2d = [(imat3 * v).to_2d() for v in vecs] # obb座標 # しばらくVectorを2Dで処理 tangents = [] # 内側のベクトル。最初は左回りを想定した計算を行う angles = [] # vec1からvec2への差。合計が負なら右回り rmat = Matrix.Rotation(math.pi / 2, 2) for i in range(len(vecs2d)): # .______________.______________. # v -(vec1)-> vec -(vec2)-> v vec = vecs2d[i] vec1 = vec - vecs2d[i - 1] vec2 = vecs2d[(i + 1) % len(vecs2d)] - vec # 先頭・末尾 if not path.cyclic and (i == 0 or i == len(vecs2d) - 1): if i == 0 and vec2.length > 0.0: tangents.append(rmat * vec2.normalized()) elif i == len(vecs2d) - 1 and vec1.length > 0.0: tangents.append(rmat * vec1.normalized()) else: tangents.append(Vector((0, 0))) angles.append(0.0) # 他 else: if vec1.length > 0.0 or vec2.length > 0.0: if vec1.length > 0.0: vec1.normalize() if vec2.length > 0.0: vec2.normalize() if vec1.length > 0.0 and vec2.length > 0.0: v = (rmat * ((vec1 + vec2) / 2)).normalized() f = abs(vam.cross2d(vec2, v)) if f > EPS: tangents.append(v / f) else: tangents.append(Vector((0, 0))) f = vam.cross2d(vec1, vec2) f = max(-1.0, min(f, 1.0)) angles.append(math.asin(f)) else: if vec1.length > 0.0: v = (rmat * vec1).normalized() else: v = (rmat * vec2).normalized() f = abs(vam.cross2d(vec2, v)) if f > EPS: tangents.append(v / f) else: tangents.append(Vector((0, 0))) angles.append(0.0) else: tangents.append(Vector((0, 0))) angles.append(0.0) # エッジが右回りだったならベクトルを反転する if sum(angles) < 0.0: for v in tangents: v.negate() for eve, vec in zip(verts, tangents): if loop_tris.vflags[eve] & WIRE: v = bbmat3 * vec.to_3d() vert_tangents[eve] = [v.copy() for i in range(3)] return vert_tangents