예제 #1
0
def bmesh_copy_from_object(ob, transform=True, triangulate=True, apply_modifiers=True):

	assert(ob.type == 'MESH')

	if apply_modifiers and ob.modifiers:
		import bpy
		me = ob.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_tessface=False)
		bm = bmesh.new()
		bm.from_mesh(me)
		bpy.data.meshes.remove(me)
		del bpy
	else:
		me = ob.data
		if ob.mode == 'EDIT':
			bm_orig = bmesh.from_edit_mesh(me)
			bm = bm_orig.copy()
		else:
			bm = bmesh.new()
			bm.from_mesh(me)

	if transform:
		bm.transform(ob.matrix_world)

	if triangulate:
		bmesh.ops.triangulate(bm, faces=bm.faces)

	return bm
예제 #2
0
 def preRender(self, element, layerIndex=None):
     op = self.op
     # <li> stands for 'layer index'
     li = element.li if layerIndex is None else layerIndex
     self.layerIndex = li
     
     if op.singleObject:
         if op.layered:
             mesh = Renderer.layerMeshes[li]
             obj = Renderer.layerObjects[li]
             materialIndices = Renderer.materialIndices[li]
             if not mesh:
                 mesh = bmesh.new()
                 Renderer.layerMeshes[li] = mesh
                 obj = self.createBlenderObject(
                     self.getLayerName(li, op),
                     self.parent
                 )
                 Renderer.layerObjects[li] = obj
                 materialIndices = {}
                 Renderer.materialIndices[li] = materialIndices
             self.bm = mesh
             self.obj = obj
             self.materialIndices = materialIndices
         else:
             self.bm = Renderer.bm
             self.obj = Renderer.obj
             self.materialIndices = Renderer.materialIndices
     else:
         self.obj = self.createBlenderObject(
             self.getName(element),
             self.getLayerParent() if op.layered else Renderer.parent
         )
         self.bm = bmesh.new()
         self.materialIndices = {}
예제 #3
0
파일: util.py 프로젝트: ctlee/gamer
def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False):
    """
    Returns a transformed, triangulated copy of the mesh
    """

    assert obj.type == 'MESH'

    if apply_modifiers and obj.modifiers:
        import bpy
        me = obj.to_mesh(bpy.context.scene, apply_modifiers=True, settings='PREVIEW')
        bm = bmesh.new()
        bm.from_mesh(me)
        bpy.data.meshes.remove(me)
        del bpy
    else:
        me = obj.data
        if obj.mode == 'EDIT':
            bm_orig = bmesh.from_edit_mesh(me)
            bm = bm_orig.copy()
        else:
            bm = bmesh.new()
            bm.from_mesh(me)

    if transform:
        bm.transform(obj.matrix_world)

    if triangulate:
        bmesh.ops.triangulate(bm, faces=bm.faces)

    return bm
def setSpriteFrame(src, dst):
    for vert in src.data.vertices:
        dst.data.vertices[vert.index].co = vert.co
        
    sbm = bmesh.new()
    dbm = bmesh.new()
    sbm.from_mesh(src.data)
    dbm.from_mesh(dst.data)
    
    suv_layer = sbm.loops.layers.uv.verify()
    duv_layer = dbm.loops.layers.uv.verify()
    dbm.faces.layers.tex.verify()
    
    # adjust UVs
    for f in dbm.faces:
        for l in f.loops:
            luv = l[duv_layer]
            luv.uv = sbm.faces[f.index].loops[l.index][suv_layer].uv
    
    dbm.to_mesh(dst.data)
    sbm.free()      
    dbm.free()      
    
    mat = src.data.materials[0]
    tex = mat.texture_slots[0].texture
    img = tex.image
    
    if len(dst.data.materials) > 0: dst.data.materials[0] = mat
    else: dst.data.materials.append(mat)
    
    # set uv faces image
    for uv_face in dst.data.uv_textures.active.data:
        uv_face.image = img
        
    dst['sprite'] = src.parent['name']+'|'+src['name']
예제 #5
0
def ControlPoints(ctrlnum, CtrlSeg):
	#_______________________________________________________
	#Creates 4 point bezier curves to act as guides for fibers
	#Parameters: ctrlnum- the number of control curves to create
	#_______________________________________________________  
	global mat, grav, tempbm
	grav = 0
	objects = bpy.context.selected_objects
	for num in range(len(objects)):
		i = 0
		original = objects[num].data

		if ctrlnum > len(original.polygons):
			ctnm = len(original.polygons)
		else:
			ctnm = ctrlnum
			
		mat = adapt(objects[num])

		vertex = [0,0,0]
	
		bm = bmesh.new()
		bm.from_mesh(original)
		
		newbm = bmesh.new()
		tempbm = bmesh.new()
		
		for fs in range(0, len(original.polygons), int(len(original.polygons) / ctnm)):
			bm.faces.ensure_lookup_table()
			f = bm.faces[fs]
			
			normal = renormal(multmat(mat, f.verts[0]),multmat(mat, f.verts[1]),multmat(mat, f.verts[2]))
					
			for z in range(3):
				vertex[z] = normal[z]
		
			#centerpoint coordinates
			vertex = [0,0,0]
			for va in f.verts:
				v = multmat(mat, va)
				for z in range(3):
					#z is the coordinate plane (x,y,or z)
					vertex[z] += v.co[z]
			for z in range(3):
				vertex[z] /= len(f.verts)
			
			for z in range(CtrlSeg):
				i += 1
				v =newbm.verts.new((vertex[0] + (z * normal[0]), vertex[1] + (z * normal[1]), vertex[2] + (z * normal[2])))

			for z in range(CtrlSeg-1):
				newbm.edges.ensure_lookup_table()
				newbm.verts.ensure_lookup_table()
				newbm.edges.new((newbm.verts[i-1-z], newbm.verts[i-2-z]))
	
		GuideMesh = bpy.data.meshes.new(original.name+"_Fiber.C")
		newbm.to_mesh(GuideMesh)
		obj = bpy.data.objects.new(name=original.name+"_Fiber.C", object_data=GuideMesh)
		scene = bpy.context.scene
		scene.objects.link(obj)
예제 #6
0
def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False):
    """
    Returns a transformed, triangulated copy of the mesh
    """

    assert(obj.type == 'MESH')

    if apply_modifiers and obj.modifiers:
        import bpy
        me = obj.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_tessface=False)
        bm = bmesh.new()
        bm.from_mesh(me)
        bpy.data.meshes.remove(me)
        del bpy
    else:
        me = obj.data
        if obj.mode == 'EDIT':
            bm_orig = bmesh.from_edit_mesh(me)
            bm = bm_orig.copy()
        else:
            bm = bmesh.new()
            bm.from_mesh(me)

    # TODO. remove all customdata layers.
    # would save ram

    if transform:
        bm.transform(obj.matrix_world)

    if triangulate:
        bmesh.ops.triangulate(bm, faces=bm.faces)

    return bm
def save_object(fw, global_matrix,
                scene, obj,
                use_mesh_modifiers):

    assert(obj.type == 'MESH')

    if use_mesh_modifiers:
        is_editmode = (obj.mode == 'EDIT')
        if is_editmode:
            bpy.ops.object.editmode_toggle()

        me = obj.to_mesh(scene, True, 'PREVIEW', calc_tessface=False)
        bm = bmesh.new()
        bm.from_mesh(me)

        if is_editmode:
            bpy.ops.object.editmode_toggle()
    else:
        me = obj.data
        if obj.mode == 'EDIT':
            bm_orig = bmesh.from_edit_mesh(me)
            bm = bm_orig.copy()
        else:
            bm = bmesh.new()
            bm.from_mesh(me)

    # Blender 2.74 fails triangulation if we do it after transform.
    # If we do it before, it's ok.
    bmesh.ops.triangulate(bm, faces=bm.faces)
    bm.transform(global_matrix * obj.matrix_world)

    save_bmesh(fw, bm, me.materials)

    bm.free()
예제 #8
0
파일: mesh.py 프로젝트: verse/verse-blender
    def update_references(self):
        """
        This method tries to update references at bmesh, when  old bmesh was removed
        """

        if self.bmesh is None:
            if bpy.context.edit_object is not None and \
                    bpy.context.edit_object.data == self.mesh:
                self.bmesh = bmesh.from_edit_mesh(self.mesh)
                self.bm_from_edit_mesh = True
            else:
                self.bmesh = bmesh.new()
                self.bmesh.from_mesh(self.mesh)
                self.bm_from_edit_mesh = False
        else:
            try:
                self.bmesh.verts
            except ReferenceError:
                if bpy.context.edit_object is not None and \
                        bpy.context.edit_object.data == self.mesh:
                    self.bmesh = bmesh.from_edit_mesh(self.mesh)
                    self.bm_from_edit_mesh = True
                else:
                    self.bmesh = bmesh.new()
                    self.bmesh.from_mesh(self.mesh)
                    self.bm_from_edit_mesh = False
                self.clear_ID_cache()
    def setMeshData(self, mesh, meshData):
        # clear existing mesh
        bmesh.new().to_mesh(mesh)

        if meshData.isValid():
            self.setValidMeshData(mesh, meshData.vertices, meshData.edges, meshData.polygons)
        else:
            self.errorMessage = "The mesh data is invalid"
예제 #10
0
파일: mesh.py 프로젝트: verse/verse-blender
    def cb_receive_layer_set_value(cls, session, node_id, layer_id, item_id, value):
        """
        This method is called, when new value of verse layer was set
        """
        face_layer = super(VerseFaces, cls).cb_receive_layer_set_value(session, node_id, layer_id, item_id, value)

        # Update mesh only in situation, when it was changed by someone else
        if face_layer.node.locked_by_me is False:

            vert_layer = face_layer.node.vertices
            edge_layer = face_layer.node.edges

            if face_layer.node.bmesh is None:
                face_layer.node.bmesh = bmesh.new()
                face_layer.node.bmesh.from_mesh(face_layer.node.mesh)
                face_layer.node.bm_from_edit_mesh = False
            else:
                try:
                    face_layer.node.bmesh.faces
                except ReferenceError:
                    face_layer.node.bmesh = bmesh.new()
                    face_layer.node.bmesh.from_mesh(face_layer.node.mesh)
                    vert_layer.id_cache = {}
                    edge_layer.id_cache = {}
                    face_layer.id_cache = {}

            _bmesh = face_layer.node.bmesh

            b3d_face = face_layer.find_b3d_face(item_id)

            # When face already exists, then remove the face
            if b3d_face is not None:
                try:
                    _bmesh.faces.remove(b3d_face)
                except ReferenceError:
                    # Face was already removed
                    pass

            # Add new one
            if value[3] == 0:
                b3d_face = _bmesh.faces.new([vert_layer.b3d_vertex(vert_id) for vert_id in value[0:3]])
            else:
                b3d_face = _bmesh.faces.new([vert_layer.b3d_vertex(vert_id) for vert_id in value])

            # Try to update last face ID
            if face_layer.node.last_face_ID is None or \
                    face_layer.node.last_face_ID < item_id:
                face_layer.node.last_face_ID = item_id

            face_layer.id_cache[item_id] = b3d_face
            id_layer = _bmesh.faces.layers.int.get('FaceIDs')
            b3d_face[id_layer] = item_id

            # Update Blender mesh
            _bmesh.to_mesh(face_layer.node.mesh)
            face_layer.node.mesh.update()

        return face_layer
예제 #11
0
def project_decal_old(mesh_src, mesh_dst):
	if isinstance(mesh_src, str):
		mesh_src = bpy.data.meshes.get(mesh_src)
		print (mesh_src)
	if isinstance(mesh_dst, str):
		mesh_dst = bpy.data.meshes.get(mesh_dst)
		print (mesh_dst)
	if mesh_src is None or mesh_dst is None:
		print ("src or dst is None")
		return
	
	bm_src = bmesh.new()
	bm_src.from_mesh(mesh_src)
	
	bm_dst = bmesh.new()
	bm_dst.from_mesh(mesh_dst)
	
	bm_out = bmesh.new()
	
	for face_src in bm_src.faces:
		verts_src = []
		for loop_src in face_src.loops:
			verts_src.append(loop_src.vert.co)
		for face_dst in bm_dst.faces:
			verts_dst = []
			for loop_dst in face_dst.loops:
				verts_dst.append(loop_dst.vert.co)
				
			# 目前做了这个假设,所以先测试到这一步
			if len(verts_src) != 4 or len(verts_dst) != 3:
				continue
			
			# adapt arguments && run
			rect = []
			for co in verts_src:
				rect.append((co.x, co.y, co.z))
			tri = []
			for co in verts_dst:
				tri.append((co.x, co.y, co.z))
			res = decal_algo.decal(rect, tri)
			# add verts
			for x, y, z in res:
				bm_out.verts.new((x, y, z + 0.01))
			# add face (all these verts will be on the same plane, so let's blender do triangulate for us)
			if res:
				bm_out.faces.new(bm_out.verts[-len(res):])
	
	print(len(bm_out.verts))
	if len(bm_out.verts) >= 0:
		mesh = bpy.data.meshes.new(name="_decal")
		bm_out.to_mesh(mesh)
		obj = bpy.context.scene.objects.get("_decal")
		if obj is None:
			obj = bpy.data.objects.new("_decal", mesh)
			bpy.context.scene.objects.link(obj)
		else:
			obj.data = mesh
예제 #12
0
def from_object(ob, apply_modifiers=True, settings='PREVIEW',
                modifier_types=None, layer_name='original',
                add_verts_layers=True, add_edges_layers=False,
                add_faces_layers=False):
    """対象のObjectがEditModeでも正常に動作する"""
    if ob.mode == 'EDIT':
        bm = bmesh.from_edit_mesh(ob.data)
    else:
        bm = bmesh.new()
        bm.from_mesh(ob.data)

    # カスタムレイヤの追加先
    def layer_add_to(bm):
        ls = []
        if add_verts_layers:
            ls.append(bm.verts)
        if add_edges_layers:
            ls.append(bm.edges)
        if add_faces_layers:
            ls.append(bm.faces)
        return ls

    for elem_seq in layer_add_to(bm):
        layer = elem_seq.layers.int.new(layer_name)
        for i, elem in enumerate(elem_seq):
            elem[layer] = i + 1

    mesh = bpy.data.meshes.new("tmp")
    bm.to_mesh(mesh)

    if ob.mode == 'EDIT':
        for elem_seq in layer_add_to(bm):
            layer = elem_seq.layers.int[layer_name]
            elem_seq.layers.int.remove(layer)

    obj = ob.copy()
    obj.data = mesh
    if apply_modifiers and modifier_types is not None:
        for mod in obj.modifiers:
            if mod.type not in modifier_types:
                mod.show_viewport = False

    dmesh = obj.to_mesh(bpy.context.scene, apply_modifiers, settings)
    bm = bmesh.new()
    bm.from_mesh(dmesh)

    for elem_seq in layer_add_to(bm):
        layer = elem_seq.layers.int[layer_name]
        for elem in elem_seq:
            elem[layer] -= 1

    bpy.data.objects.remove(obj)
    bpy.data.meshes.remove(mesh)
    bpy.data.meshes.remove(dmesh)

    return bm
예제 #13
0
def save_object(fw, global_matrix, scene, obj, use_mesh_modifiers, use_color, color_type, use_uv, path_mode, copy_set):

    assert obj.type == "MESH"

    if use_mesh_modifiers:
        is_editmode = obj.mode == "EDIT"
        if is_editmode:
            bpy.ops.object.editmode_toggle()

        me = obj.to_mesh(scene, True, "PREVIEW", calc_tessface=False)
        bm = bmesh.new()
        bm.from_mesh(me)

        if is_editmode:
            bpy.ops.object.editmode_toggle()
    else:
        me = obj.data
        if obj.mode == "EDIT":
            bm_orig = bmesh.from_edit_mesh(me)
            bm = bm_orig.copy()
        else:
            bm = bmesh.new()
            bm.from_mesh(me)

    bm.transform(global_matrix * obj.matrix_world)
    bmesh.ops.triangulate(bm, faces=bm.faces, use_beauty=True)

    # default empty
    material_colors = []
    uv_image = None

    if use_color:
        if color_type == "VERTEX":
            if bm.loops.layers.color.active is None:
                # fallback to material
                color_type = "MATERIAL"
        if color_type == "MATERIAL":
            if not me.materials:
                use_color = False
            else:
                material_colors = [
                    "%.2f %.2f %.2f " % (m.diffuse_color[:] if m else (1.0, 1.0, 1.0)) for m in me.materials
                ]
        assert color_type in {"VERTEX", "MATERIAL"}

    if use_uv:
        if bm.loops.layers.uv.active is None:
            use_uv = False
        uv_image = object_utils.object_image_guess(obj, bm=bm)
        if uv_image is None:
            use_uv = False

    save_bmesh(fw, bm, use_color, color_type, material_colors, use_uv, uv_image, path_mode, copy_set)

    bm.free()
예제 #14
0
파일: mesh.py 프로젝트: verse/verse-blender
    def cb_receive_layer_set_value(cls, session, node_id, layer_id, item_id, value):
        """
        This method is called, when new value of verse layer was set
        """
        edge_layer = super(VerseEdges, cls).cb_receive_layer_set_value(session, node_id, layer_id, item_id, value)

        # Update mesh only in situation, when it was changed by someone else
        if edge_layer.node.locked_by_me is False:

            vert_layer = edge_layer.node.vertices
            face_layer = edge_layer.node.quads

            if edge_layer.node.bmesh is None:
                edge_layer.node.bmesh = bmesh.new()
                edge_layer.node.bmesh.from_mesh(edge_layer.node.mesh)
                edge_layer.node.bm_from_edit_mesh = False
            else:
                try:
                    edge_layer.node.bmesh.edges
                except ReferenceError:
                    edge_layer.node.bmesh = bmesh.new()
                    edge_layer.node.bmesh.from_mesh(edge_layer.node.mesh)
                    vert_layer.id_cache = {}
                    edge_layer.id_cache = {}
                    face_layer.id_cache = {}

            _bmesh = edge_layer.node.bmesh

            b3d_edge = edge_layer.b3d_edge(item_id)

            # Try to update last vertex ID
            if edge_layer.node.last_edge_ID is None or \
                    edge_layer.node.last_edge_ID < item_id:
                edge_layer.node.last_edge_ID = item_id

            # Does edge with same id exist?
            if b3d_edge is not None:
                # Delete edge
                try:
                    _bmesh.edges.remove(b3d_edge)
                except ReferenceError:
                    # Edge was already removed
                    pass

            # Create new edge
            b3d_edge = _bmesh.edges.new([vert_layer.b3d_vertex(vert_id) for vert_id in value])
            edge_layer.id_cache[item_id] = b3d_edge
            id_layer = _bmesh.edges.layers.int.get('EdgeIDs')
            b3d_edge[id_layer] = item_id

            # Update Blender mesh
            _bmesh.to_mesh(edge_layer.node.mesh)
            edge_layer.node.mesh.update()

        return edge_layer
 def execute(self, meshData):
     try:
         bm = getBMeshFromMeshData(meshData)
         self.errorMessage = ""
     except IndexError as e:
         bm = bmesh.new()
         self.errorMessage = "Missing vertices"
     except ValueError as e:
         bm = bmesh.new()
         self.errorMessage = "Multiple identical edges or polygons"
     return bm
예제 #16
0
    def setMeshData(self, mesh, meshData):
        # clear existing mesh
        bmesh.new().to_mesh(mesh)

        isValidData = meshData.isValid(
            checkTupleLengths = self.checkTupleLengths,
            checkIndices = self.checkIndices)

        if isValidData:
            mesh.from_pydata(meshData.vertices, meshData.edges, meshData.polygons)
        else:
            self.errorMessage = "The mesh data is invalid"
예제 #17
0
def get_sceneColldersBVH(forObj, allowSelf):
	matrix_world_inv = None
	if forObj is not None:
		matrix_world = forObj.matrix_world
		matrix_world_inv = matrix_world.inverted()
	objs2checkAll = [obj for obj in bpy.data.objects]
	bvh2collides = []
	for obj in objs2checkAll:
		if allowSelf == False and forObj is not None and obj.name == forObj.name:
			continue
		if obj.hide == True:
			continue
		isColl = False
		if "_collider" in obj.name:
			isColl = True
		for md in obj.modifiers:
			if md.type == 'COLLISION':
				isColl = True
				break
		if isColl:
			print("- Collider found:",obj.name)
			bm_collide = None
			if obj.type != 'MESH':
				sel_mesh = None
				try:
					sel_mesh = obj.to_mesh(bpy.context.scene, True, 'PREVIEW')
				except:
					pass
				if sel_mesh is not None:
					bm_collide = bmesh.new()
					bm_collide.from_mesh(sel_mesh)
					bpy.data.meshes.remove(sel_mesh)
			else:
				bm_collide = bmesh.new()
				bm_collide.from_object(obj, bpy.context.scene)
			if bm_collide is not None:
				hiddenFaces = []
				for bm2f in bm_collide.faces:
					if bm2f.hide and bm2f not in hiddenFaces:
						hiddenFaces.append(bm2f)
				if len(hiddenFaces)>0:
					bmesh.ops.delete(bm_collide,geom=hiddenFaces,context=5)
				bm_collide.transform(obj.matrix_world)
				if matrix_world_inv is not None:
					bm_collide.transform(matrix_world_inv)
				bmesh.ops.recalc_face_normals(bm_collide, faces=bm_collide.faces) #??? strange results!!!
				bm_collide.verts.ensure_lookup_table()
				bm_collide.faces.ensure_lookup_table()
				bm_collide.verts.index_update()
				bvh_collide = BVHTree.FromBMesh(bm_collide, epsilon = kRaycastEpsilonCCL)
				bm_collide.free()
				bvh2collides.append(bvh_collide)
	return bvh2collides
예제 #18
0
파일: CMesh.py 프로젝트: dvochin/Blender
    def ConvertBackTo3D(self):
        bmUVS = bmesh.new()
        bm3DS = bmesh.new()
        bm3DD = bmesh.new()
        bmUVS.from_mesh(self.oMeshUVSO.data)
        bm3DS.from_mesh(self.oMesh3DSO.data)

        #=== Create new 3D-domain mesh so we can cut with a flattened mesh that doesn't move with user morphs ===
        oMesh3DDD = bpy.data.meshes.new("CMeshUV-3DD")          ###TODO#16
        self.oMesh3DDO = bpy.data.objects.new(oMesh3DDD.name, oMesh3DDD)
        bpy.context.scene.objects.link(self.oMesh3DDO)
        SetParent(self.oMesh3DDO.name, G.C_NodeFolder_Game)
        bm3DD.from_mesh(self.oMesh3DDO.data)

        #=== Create the verts in the destination 3D mesh ===
        aMapVertsUV2Verts3DD = {}
        bm3DS.verts.ensure_lookup_table()
        oLayVert3D = bmUVS.verts.layers.int[G.C_DataLayer_VertsSrc]
        for oVertUV in bmUVS.verts:
            nVert3DS = oVertUV[oLayVert3D]
            if nVert3DS >= G.C_OffsetVertIDs:
                oVert3DS = bm3DS.verts[nVert3DS - G.C_OffsetVertIDs]
                vecVert3D = oVert3DS.co
            else:           # New vert that was created by Boolean cuts... we must interpolate its 3D position
                vecLoc, nPoly, nDist = self.oTreeKD.find(oVertUV.co)                ###LEARN: How to extract multiple arguments out
                oPoly = self.oMesh3DSO.data.polygons[nPoly]
                aUV = [self.oMesh3DSO.data.uv_layers.active.data[nLoopIndex].uv for nLoopIndex in oPoly.loop_indices]
                #print("Loc search = ", vecLoc, nPoly, nDist)
                vecUV0 = Vector((aUV[0].x, 0, aUV[0].y))            # Expand 2D UV coordinate into a 3D vector with z = 0 so we can invoke barycentric_transform() below
                vecUV1 = Vector((aUV[1].x, 0, aUV[1].y))
                vecUV2 = Vector((aUV[2].x, 0, aUV[2].y))
                vecPoly0 = self.oMesh3DSO.data.vertices[oPoly.vertices[0]].co
                vecPoly1 = self.oMesh3DSO.data.vertices[oPoly.vertices[1]].co
                vecPoly2 = self.oMesh3DSO.data.vertices[oPoly.vertices[2]].co
                vecVert3D = geometry.barycentric_transform(oVertUV.co, vecUV0, vecUV1, vecUV2, vecPoly0, vecPoly1, vecPoly2)    ###LEARN: How to convert from a point in one triangle space to another triangle space
            aMapVertsUV2Verts3DD[oVertUV.index] = len(bm3DD.verts) 
            bm3DD.verts.new(vecVert3D)
                
        ###TODO#16: Duplicate verts along seams??
        
        #=== Create the polygons in the destination 3D mesh ===
        bm3DD.verts.ensure_lookup_table()
        for oFace in bmUVS.faces:
            aVertsNewFace3D = []
            for oVert in oFace.verts:
                nVert3DD = aMapVertsUV2Verts3DD[oVert.index]
                oVert3DD = bm3DD.verts[nVert3DD]  
                aVertsNewFace3D.append(oVert3DD)       # Traverse from UV-domain to 3D domain using map we created in loop above
            bm3DD.faces.new(aVertsNewFace3D)
                
        
        bm3DD.to_mesh(self.oMesh3DDO.data)
예제 #19
0
파일: mesh.py 프로젝트: verse/verse-blender
    def cb_receive_layer_unset_value(cls, session, node_id, layer_id, item_id):
        """
        This method is called, when some vertex was deleted
        """
        edge_layer = super(VerseEdges, cls).cb_receive_layer_unset_value(session, node_id, layer_id, item_id)

        # Update mesh only in situation, when it was changed by someone else
        if edge_layer.node.locked_by_me is False:

            vert_layer = edge_layer.node.vertices
            face_layer = edge_layer.node.quads

            if edge_layer.node.bmesh is None:
                edge_layer.node.bmesh = bmesh.new()
                edge_layer.node.bmesh.from_mesh(edge_layer.node.mesh)
                edge_layer.node.bm_from_edit_mesh = False
            else:
                try:
                    edge_layer.node.bmesh.edges
                except ReferenceError:
                    edge_layer.node.bmesh = bmesh.new()
                    edge_layer.node.bmesh.from_mesh(edge_layer.node.mesh)
                    vert_layer.id_cache = {}
                    edge_layer.id_cache = {}
                    face_layer.id_cache = {}

            _bmesh = edge_layer.node.bmesh

            b3d_edge = edge_layer.b3d_edge(item_id)

            # Try to update last vertex ID
            if edge_layer.node.last_vert_ID is None or \
                    edge_layer.node.last_edge_ID < item_id:
                edge_layer.node.last_edge_ID = item_id

            if b3d_edge is not None:
                # Delete edge
                try:
                    _bmesh.edges.remove(b3d_edge)
                except ReferenceError:
                    # Edge was already removed?
                    edge_layer.id_cache.pop(item_id)
                else:
                    # Update Blender mesh
                    _bmesh.to_mesh(edge_layer.node.mesh)
                    edge_layer.node.mesh.update()
                    edge_layer.id_cache.pop(item_id)

        return edge_layer
예제 #20
0
 def process(self):
     objm = bpy.data.objects[self.object_ref].data
     objm.update()
     if not objm.vertex_colors:
         objm.vertex_colors.new(name='Sv_VColor')
     if self.vertex_color not in objm.vertex_colors:
         return
     ovgs = objm.vertex_colors.get(self.vertex_color)
     Ind, Col = self.inputs     
     if Col.is_linked:
         sm, colors = self.mode, Col.sv_get()[0]
         idxs = Ind.sv_get()[0] if Ind.is_linked else [i.index for i in getattr(objm,sm)]
         idxs, colors = second_as_first_cycle(idxs, colors)
         bm = bmesh.new()
         bm.from_mesh(objm)
         if self.clear:
             for i in ovgs.data:
                 i.color = self.clear_c
         if sm == 'vertices':
             bv = bm.verts[:]
             for i, i2 in zip(idxs, colors):
                 for i in bv[i].link_loops:
                     ovgs.data[i.index].color = i2
         elif sm == 'polygons':
             bf = bm.faces[:]
             for i, i2 in zip(idxs, colors):
                 for i in bf[i].loops:
                     ovgs.data[i.index].color = i2
         bm.free()
     if self.outputs["OutColor"].is_linked:
         out = []
         sm= self.mode
         bm = bmesh.new()
         bm.from_mesh(objm)
         if sm == 'vertices':
             #output one color per vertex
             for v in bm.verts[:]:
                 c = ovgs.data[v.link_loops[0].index].color
                 out.append(list(c))
                 
             
         elif sm == 'polygons':
             #output one color per face
             for f in bm.faces[:]:
                 c = ovgs.data[f.loops[0].index].color
                 out.append(list(c))                    
         
         self.outputs["OutColor"].sv_set([out])
         bm.free()
예제 #21
0
def joinBoundaryVertexNormals(self, context, destobjs,
                              INFL=0.0, MAXDIST=0.01):
    '''
    Average smoothing over boundary verts, usually same-location.
    destobjs = list, generally context.selected_objects
    INFL = float, influence strength
    MAXDIST = float, distance to influence... probably not necessary
    '''
    bms = {}
    bmsrc = bmesh.new()
    scene = context.scene
    
    for obj in destobjs:
        # These type != 'MESH' checks could be alleviated by removing
        #  non-mesh objects in execute(), but, may wish to
        #  support non-mesh objects one day
        if obj.type != 'MESH':
            continue
        bms[obj.name] = bmesh.new()
        bm = bms[obj.name]
        bm.from_mesh(obj.to_mesh(scene, False, 'PREVIEW'))
        bm.transform(obj.matrix_world)
        destverts = bm.verts
        
        for otherobj in destobjs:
            if otherobj.type != 'MESH' or obj == otherobj:
                continue
            gatherSourceVerts(bmsrc, otherobj, scene, 'ONLY')
            sourceverts = bmsrc.verts
            
            for vert in destverts:
                near = nearestVertexNormal(sourceverts, vert, MAXDIST)
                if near:
                    offset = near * INFL
                    vert.normal = (vert.normal + offset) * 0.5
                    vert.normal.normalize()
            bmsrc.clear()
    
    for name in bms:
        # Everything's been modified by everything else's original state,
        #  time to apply the modified data to the original objects
        bm = bms[name]
        for obj in destobjs:
            if obj.name == name:
                bm.transform(obj.matrix_world.inverted())
                bm.to_mesh(obj.data)
                bm.free()
    bmsrc.free()
예제 #22
0
파일: qmtools.py 프로젝트: jcruz0x/qmtools
def get_snap_target(context, axis_index):
    bm = bmesh.new()
    bm.from_mesh(context.object.data)
    # bm = bmesh.from_edit_mesh(context.object.data) 

    snap_target = None
    
    if not bm.select_history:
        bm.free()
        return None

    vert = bm.select_history[-1]
    if isinstance(vert, bmesh.types.BMVert):
        snap_target = vert.co[axis_index]

    if snap_target == None:
        face = bm.select_history[-1]
        if isinstance(face, bmesh.types.BMFace):
            center = face.calc_center_median()
            snap_target = center[axis_index]

    if snap_target == None:
        edge = bm.select_history[-1]
        if isinstance(edge, bmesh.types.BMEdge):
            pos1 = edge.verts[0].co
            pos2 = edge.verts[1].co
            midpoint = pos1.lerp(pos2, 0.5)
            snap_target = midpoint[axis_index]

    bm.free()
    return snap_target
예제 #23
0
 def draw(self, context):
     ob = bpy.context.object
     
     if ob is None:
         return
     
     if ob.type != 'MESH':
         raise TypeError("Active object is not a Mesh")
     
     me = ob.data
     
     if me.is_editmode:
         # Gain direct access to the mesh
         bm = bmesh.from_edit_mesh(me)
     else:
         # Create a bmesh from mesh
         # (won't affect mesh, unless explicitly written back)
         bm = bmesh.new()
         bm.from_mesh(me)
     
     # Get active face
     face = bm.faces.active
     
     if face is None:
         return
     
     arxFaceType = bm.faces.layers.int.get('arx_facetype')
     arxTransVal = bm.faces.layers.float.get('arx_transval')
     
     faceType = PolyTypeFlag()
     faceType.asUInt = face[arxFaceType]
     
     transval = face[arxTransVal]
     
     obj = bpy.context.active_object
     
     layout = self.layout
     
     layout.label(text="transval: " + str(transval))
     layout.label(text="POLY_NO_SHADOW: " + str(faceType.POLY_NO_SHADOW))
     layout.label(text="POLY_DOUBLESIDED: " + str(faceType.POLY_DOUBLESIDED))
     layout.label(text="POLY_TRANS: " + str(faceType.POLY_TRANS))
     layout.label(text="POLY_WATER: " + str(faceType.POLY_WATER))
     layout.label(text="POLY_GLOW: " + str(faceType.POLY_GLOW))
     layout.label(text="POLY_IGNORE: " + str(faceType.POLY_IGNORE))
     layout.label(text="POLY_QUAD: " + str(faceType.POLY_QUAD))
     layout.label(text="POLY_METAL: " + str(faceType.POLY_METAL))
     layout.label(text="POLY_HIDE: " + str(faceType.POLY_HIDE))
     layout.label(text="POLY_STONE: " + str(faceType.POLY_STONE))
     layout.label(text="POLY_WOOD: " + str(faceType.POLY_WOOD))
     layout.label(text="POLY_GRAVEL: " + str(faceType.POLY_GRAVEL))
     layout.label(text="POLY_EARTH: " + str(faceType.POLY_EARTH))
     layout.label(text="POLY_NOCOL: " + str(faceType.POLY_NOCOL))
     layout.label(text="POLY_LAVA: " + str(faceType.POLY_LAVA))
     layout.label(text="POLY_CLIMB: " + str(faceType.POLY_CLIMB))
     layout.label(text="POLY_FALL: " + str(faceType.POLY_FALL))
     layout.label(text="POLY_NOPATH: " + str(faceType.POLY_NOPATH))
     layout.label(text="POLY_NODRAW: " + str(faceType.POLY_NODRAW))
     layout.label(text="POLY_PRECISE_PATH: " + str(faceType.POLY_PRECISE_PATH))
     layout.label(text="POLY_LATE_MIP: " + str(faceType.POLY_LATE_MIP))
def draw_dashed_line(mesh, start, end):
    '''Draw a dashed line.'''
    # Create a bmesh representation
    bm = bmesh.new()        # create an empty bmesh
    bm.from_mesh(mesh)      # fill it with the above mesh
    
    # modify the mesh here
    
    w = 0.04
    step = w * (end - start).normalized()
    n = len(bm.verts)
    
    for i in range(int(1 + 0.5 * (end - start).length / w)):
        a = start + 2 * i * step
        b = a + step
        if (b - end).length < step.length:
            b = end
        bm.verts.new(a)
        bm.verts.new(b)
        # use before accessing bm.verts[] with blender 2.73
        if hasattr(bm.verts, "ensure_lookup_table"):
            bm.verts.ensure_lookup_table()
        bm.edges.new([bm.verts[n + 2 * i], bm.verts[n + 2 * i + 1]])
        
    # write the bmesh back to the mesh
    bm.to_mesh(mesh)
    mesh.update()
예제 #25
0
def mesh_triangulate(me):
	import bmesh
	bm = bmesh.new()
	bm.from_mesh(me)
	bmesh.ops.triangulate(bm, faces=bm.faces)#, use_beauty=False)
	bm.to_mesh(me)
	bm.free()
예제 #26
0
파일: export_qor.py 프로젝트: dreamsxin/qor
def mesh_triangulate(mesh):
    import bmesh
    bm = bmesh.new()
    bm.from_mesh(mesh)
    bmesh.ops.triangulate(bm, faces=bm.faces)
    bm.to_mesh(mesh)
    bm.free()
예제 #27
0
def do_export(fileName, correctionMatrix):
    mats = [m for m in bpy.data.materials
        if any([m in [ms.material for ms in o.material_slots]
            for o in bpy.data.objects])]
    objs = [o for o in bpy.data.objects
        if o.type == 'MESH' and not o.hide]
    if not objs:
        return ("Nothing to export.",{'CANCELLED'})
    groups = prep_groups(objs)
    actions = [(
        o.name,
        (correctionMatrix * o.matrix_world.to_translation())[:])
        for o in bpy.data.objects
        if o.type == 'EMPTY'
        and o.parent in objs]
    bm = bmesh.new()
    for o in objs:
        bm = append_object(bm, o, mats, groups)
    bm.transform(correctionMatrix)
    bm.normal_update()
    model = Model(bm, [m.name for m in mats], groups, actions)
    bm.free()
    f = open(fileName, 'w+b')
    f.write(build_ftl(model))
    f.close()
    msg = "File \"" + fileName + "\" written successfully."
    result = {'FINISHED'}
    return (msg,result)
def draw_circle(mesh, numpoints, radius, matrix):
    '''Draw a circle.'''
    # bmesh repr.
    bm = bmesh.new()
    bm.from_mesh(mesh)
    
    # get the number of verts already in the mesh
    n = len(bm.verts)
    
    # make the verts
    for i in range(numpoints):
        angle = 2.0 * math.pi * i / numpoints
        v = Vector((radius * math.cos(angle), radius * math.sin(angle), 0))
        bm.verts.new((v * matrix))

    # use before accessing bm.verts[] with blender 2.73
    if hasattr(bm.verts, "ensure_lookup_table"):
        bm.verts.ensure_lookup_table()
    
    # make the edges
    for i in range(numpoints):
        i1 = (i + 1) % numpoints
        bm.edges.new([bm.verts[n + i], bm.verts[n + i1]])
    
    # write the bmesh back to the mesh
    bm.to_mesh(mesh)
    mesh.update()
예제 #29
0
def add_mesh(meshes, m):
    mesh = meshes.add()

    mesh.name = m.name
    mesh.type = 'gregory'

    bm = bmesh.new()
    bm.from_mesh(m)

    positions = []

    for f in bm.faces:
        fs = [f]
        
        if is_border_face(f):
            continue
        if len(f.loops) != 4:
            continue # Throw away
            #_,fs = local_subdivide(f)

        for g in fs:
            P = make_patch(g)
            positions += P

    mesh.init('positions', len(positions)*3)
    for i,pos in enumerate(positions):
        mesh.positions[i*3+0] = pos.x
        mesh.positions[i*3+1] = pos.y
        mesh.positions[i*3+2] = pos.z
예제 #30
0
    def execute(self, context):

        A = 6.283185307179586476925286766559 / 3

        verts = [(sin(A * 1), 0.0, cos(A * 1)),
                 (sin(A * 2), 0.0, cos(A * 2)),
                 (sin(A * 3), 0.0, cos(A * 3)),
                 ]

        faces = [(0, 1, 2)]

        mesh = bpy.data.meshes.new("Cube")

        bm = bmesh.new()

        for v_co in verts:
            bm.verts.new(v_co)

        for f_idx in faces:
            bm.faces.new([bm.verts[i] for i in f_idx])

        bm.to_mesh(mesh)
        mesh.update()

        object_utils.object_data_add(context, mesh)

        return{'FINISHED'}
예제 #31
0
    def add_solid(self, solid):
        '''
        Prune faces based on material names.
        '''
        # TODO: have this list be part of the settings!
        textures_to_ignore = {'NULL', 'AAATRIGGER', 'CLIP', 'SKY', '{BLUE'}
        faces = list(
            filter(lambda f: f.texture_name not in textures_to_ignore,
                   solid.faces))

        if len(faces) == 0:
            return None

        mesh_name = 'Solid.000'
        mesh = bpy.data.meshes.new(mesh_name)

        mesh_object = bpy.data.objects.new(mesh_name, mesh)
        '''
        Create or reuse materials 
        '''
        textures = []
        for f in faces:
            material = self.load_material(f.texture_name)
            if f.texture_name not in textures:
                textures.append(f.texture_name)
                mesh.materials.append(material)

        bm = bmesh.new()
        vertex_offset = 0
        for f in faces:
            for vertex in f.vertices:
                bm.verts.new(tuple(vertex))
            bm.verts.ensure_lookup_table()

            # The face order is reversed because of differences in winding order
            face = reversed(
                [bm.verts[vertex_offset + x] for x in range(len(f.vertices))])
            bmface = bm.faces.new(face)
            bmface.material_index = textures.index(f.texture_name)
            vertex_offset += len(f.vertices)

        bm.to_mesh(mesh)

        collection = self.get_collection_for_solid(solid)
        collection.objects.link(mesh_object)

        default_texture_size = 256, 256
        if self.should_import_textures:
            '''
            Assign texture coordinates
            '''
            uv_layer = mesh.uv_layers.new()
            j = 0
            for face_index, face in enumerate(faces):
                try:
                    texture_size = self.get_texture_size(face.texture_name)
                except LookupError:
                    # If we don't have the texture, just assume a texture size of 256x256
                    texture_size = default_texture_size
                uvs = convert_rmf_face_texture_coordinates_to_uvs(
                    face, texture_size)
                # NOTE: the UV order has to be reversed to match the reversed vertices due to winding order
                for uv in reversed(uvs):
                    uv[1] = -uv[1]
                    uv_layer.data[j].uv = uv.tolist()
                    j += 1

        return mesh_object
예제 #32
0
def cycle(ot, context, event, index=1, custom=None):
    global current_index
    global sum_index

    preference = addon.preference()
    bc = context.window_manager.bc

    bc.lattice.hide_set(False)

    original_active = context.active_object
    context.view_layer.objects.active = bc.shape
    bc.shape.select_set(True)

    matrix = bc.shape.matrix_world.copy()
    dimension = Vector(bc.shape.dimensions)

    if not custom and not bc.shape.bc.applied and not bc.shape.bc.applied_cycle:
        bc.shape.bc.applied_cycle = True
        keep_modifiers = [
            type for type in ['ARRAY', 'BEVEL', 'SOLIDIFY', 'SCREW', 'MIRROR']
            if getattr(preference.behavior, F'keep_{type.lower()}')
        ]
        modifier.apply(obj=bc.shape,
                       exclude=[
                           mod for mod in bc.shape.modifiers
                           if mod.type in keep_modifiers
                       ])

        for obj in ot.datablock['targets']:
            modifier.shape_bool(ot, obj).object = None

        for obj in ot.datablock['slices']:
            modifier.shape_bool(ot, obj).object = None

    objects = []
    for obj in bc.collection.objects:
        holdout = obj.bc.applied_cycle and not (
            sum_index > len(bc.collection.objects) - 1) or obj.bc.copy

        if obj.type == 'MESH' and obj != bc.shape and not holdout:
            objects.append(obj)

    obj = None
    if not custom:
        next_index = current_index + index

        if next_index > len(objects) - 1:
            next_index = 0

        elif next_index < -1:
            next_index = len(objects) - 1

        current_index = next_index
        sum_index += 1

        if objects:
            obj = objects[next_index if next_index < len(objects) - 1 else 0]
        else:
            return

    del objects

    if bc.shape.bc.copy:
        bpy.data.objects.remove(bc.shape)

    obj = obj if obj else custom

    if custom:
        bpy.data.objects.remove(bc.shape)
        bc.shape = None

    bc.shape = obj.copy()
    bc.collection.objects.link(bc.shape)
    context.view_layer.objects.active = bc.shape

    bc.shape.bc.copy = True
    bc.shape.data = obj.data.copy()

    bc.shape.data.use_auto_smooth = True

    del obj

    modifier.apply(
        bc.shape,
        exclude=[mod for mod in bc.shape.modifiers if mod.type == 'BEVEL'])

    scale = bc.shape.matrix_world.to_scale()
    bc.shape.data.transform(Matrix.Scale(scale.x, 4, Vector((1, 0, 0))))
    bc.shape.data.transform(Matrix.Scale(scale.y, 4, Vector((0, 1, 0))))
    bc.shape.data.transform(Matrix.Scale(scale.z, 4, Vector((0, 0, 1))))
    bc.shape.scale = Vector((1, 1, 1))
    bc.shape.location = Vector()
    bc.shape.rotation_euler = Vector()

    center = 0.125 * sum(
        (Vector(point) for point in bc.shape.bound_box), Vector())
    bc.shape.data.transform(Matrix.Translation(-center))

    scale_x = 1 / bc.shape.dimensions[0]
    scale_y = 1 / bc.shape.dimensions[1]
    scale_z = 1 / bc.shape.dimensions[2]

    if bc.shape.bc.shape and len(ot.datablock['targets']):
        scale_x = -scale_x

    if not bc.shape.bc.shape and ot.shape_type == 'CUSTOM':
        scale_y = -scale_y

    bc.shape.data.transform(Matrix.Scale(scale_x, 4, Vector((1, 0, 0))))
    bc.shape.data.transform(Matrix.Scale(scale_y, 4, Vector((0, 1, 0))))
    bc.shape.data.transform(Matrix.Scale(-scale_z, 4, Vector((0, 0, 1))))

    bm = bmesh.new()
    bm.from_mesh(bc.shape.data)

    bm.faces.ensure_lookup_table()
    bmesh.ops.recalc_face_normals(bm, faces=bm.faces)

    for f in bm.faces:
        f.smooth = True

    bm.to_mesh(bc.shape.data)
    bm.free()

    for obj in ot.datablock['targets']:
        for mod in obj.modifiers:
            if mod.type == 'BOOLEAN' and not mod.object:
                mod.object = bc.shape

    for obj in ot.datablock['slices']:
        for mod in obj.modifiers:
            if mod.type == 'BOOLEAN' and not mod.object:
                mod.object = bc.shape

    bc.lattice.matrix_world = Matrix()

    points = [Vector(point.co_deform) for point in bc.lattice.data.points]
    bc.lattice.data.points[0].co_deform = Vector((-0.5, -0.5, -0.5))
    bc.lattice.data.points[1].co_deform = Vector((0.5, -0.5, -0.5))
    bc.lattice.data.points[2].co_deform = Vector((-0.5, 0.5, -0.5))
    bc.lattice.data.points[3].co_deform = Vector((0.5, 0.5, -0.5))
    bc.lattice.data.points[4].co_deform = Vector((-0.5, -0.5, 0.5))
    bc.lattice.data.points[5].co_deform = Vector((0.5, -0.5, 0.5))
    bc.lattice.data.points[6].co_deform = Vector((-0.5, 0.5, 0.5))
    bc.lattice.data.points[7].co_deform = Vector((0.5, 0.5, 0.5))

    mod = bc.shape.modifiers.new(name='Lattice', type='LATTICE')
    mod.object = bc.lattice

    modifier.sort(ot, bc.shape, force=True)

    bc.lattice.data.transform(Matrix.Translation(Vector((0, 0, -0.5))))

    if ot.origin == 'CORNER':
        bc.lattice.data.transform(Matrix.Translation(Vector((0.5, 0.5, 0))))

    for pair in zip(points, bc.lattice.data.points):
        pair[1].co_deform = pair[0]

    bc.shape.display_type = 'WIRE'

    bc.lattice.matrix_world = matrix
    bc.shape.matrix_world = matrix

    bc.shape.hide_set(True)
    bc.lattice.hide_set(True)

    context.view_layer.objects.active = original_active
예제 #33
0
파일: imports.py 프로젝트: Guild-Hall/MCAnm
 def apply(self):
     if self.name is None:
         Reporter.fatal("Missing nametag in model")
     if self.shapes is None:
         Reporter.fatal("Missing shapes in model {name}", name=self.name)
     if self.obj_scale is None:
         Reporter.warning(
             "Missing GlScale in model {name}, assuming Identity",
             name=self.name)
     if self.uv_scale is None:
         Reporter.warning(
             "Missing texture-size in model {name}. Computing from texture anyway",
             name=self.name)
     elif self.img is not None and (
             self.uv_scale[0][0] != 1 / self.img.size[0]
             or self.uv_scale[1][1] != 1 / self.img.size[1]):
         Reporter.warning(
             "In Model {name}: Texture is ({x}, {y}) but .tcn file said ({x_xml}, {y_xml})",
             name=self.name,
             x=self.img.size[0],
             y=self.img.size[1],
             x_xml=self.uv_scale[0],
             y_xml=self.uv_scale[1])
     # make mesh
     mesh = bpy.data.meshes.new(self.name)
     bm = bmesh.new()
     uv = bm.loops.layers.uv.new('UVLayer')
     tex = bm.faces.layers.tex.new('UVLayer')
     mc_loop = bm.faces.layers.int.new('MCRenderGroupIndex')
     for shape_nbr, shape in enumerate(self.shapes):
         # points is a list of lists of points (representing a list of
         # faces)
         points, idx_uvs = shape.apply(True)
         bpoints = []
         for p in points:
             co = self.obj_scale * p[0]
             norm = self.obj_scale * p[1]
             co.y = 24 - co.y
             co = Matrix(
                 ((-1 / 16, 0, 0), (0, 0, -1 / 16), (0, 1 / 16, 0))) * co
             norm = Matrix(((-1, 0, 0), (0, 0, -1), (0, 1, 0))) * norm
             bp = bm.verts.new(co)
             bp.normal = norm
             bpoints.append(bp)
         for face in idx_uvs:
             bface = bm.faces.new([bpoints[l[0]] for l in face])
             for loop, (_, uvco) in zip(bface.loops, face):
                 uvco = self.uv_scale * uvco
                 uvco[1] = 1 - uvco[1]
                 loop[uv].uv = uvco
             bface[tex].image = self.img
             if mc_loop is not None:
                 bface[mc_loop] = shape_nbr + 1
     bm.verts.index_update()
     bm.faces.index_update()
     bm.to_mesh(mesh)
     # make obj
     obj = bpy.data.objects.new(self.name, mesh)
     props = mesh.mcprops
     props.name = self.name
     props.uv_layer = uv.name
     if self.img is not None:
         props.default_group.image = self.img.name
     for shape in self.shapes:
         group = props.render_groups.add()
         group.name = shape.name
         if self.img is not None:
             group.image = self.img.name
     return obj
예제 #34
0
 def get_bm(self, obj):
     bm = bmesh.new()
     bm.from_mesh(obj.data)
     bm.normal_update()
     bm.verts.ensure_lookup_table()
     return bm
예제 #35
0
    def execute(self, context):

        obj = context.active_object

        bpy.context.space_data.pivot_point = 'INDIVIDUAL_ORIGINS'

        bpy.ops.object.mode_set(mode='OBJECT')

        if len(bpy.context.selected_objects) == 2:

            first_obj = bpy.context.active_object

            obj_a, obj_b = context.selected_objects

            second_obj = obj_a if obj_b == first_obj else obj_b

            ### origin to top
            for i in range(self.set_plus_z):

                # active: second
                bpy.context.scene.objects.active = bpy.data.objects[
                    second_obj.name]  #["YourName"]
                bpy.data.objects[second_obj.name].select = True

                bpy.ops.tp_ops.origin_plus_z()

                # active: first
                bpy.context.scene.objects.active = bpy.data.objects[
                    first_obj.name]
                bpy.data.objects[first_obj.name].select = True

            ### origin to bottom
            for i in range(self.set_minus_z):

                # active: second
                bpy.context.scene.objects.active = bpy.data.objects[
                    second_obj.name]
                bpy.data.objects[second_obj.name].select = True

                bpy.ops.tp_ops.origin_minus_z()

                # active: first
                bpy.context.scene.objects.active = bpy.data.objects[
                    first_obj.name]
                bpy.data.objects[first_obj.name].select = True

            # active: first
            bpy.data.objects[second_obj.name].select = False

            if context.mode == 'EDIT_MESH':

                print(self)
                self.report({'INFO'}, "need a source and a target")

            else:

                bpy.ops.object.duplicate_move()

                bpy.context.object.name = "Dummy"

                bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM')

                bpy.ops.object.transform_apply(location=True,
                                               rotation=True,
                                               scale=True)

                copy_cursor = bpy.context.scene.cursor_location.copy()

                bm = bmesh.new()
                bm.from_mesh(obj.data)

                selected_faces = [f for f in bm.faces if f.select]

                for face in selected_faces:

                    face_location = face.calc_center_median()

                    loc_world_space = obj.matrix_world * Vector(face_location)

                    z = Vector((0, 0, 1))

                    angle = face.normal.angle(z)

                    axis = z.cross(face.normal)

                    bpy.ops.object.select_all(action='DESELECT')

                    # active: second
                    bpy.context.scene.objects.active = bpy.data.objects[
                        second_obj.name]
                    bpy.data.objects[second_obj.name].select = True

                    for i in range(self.dupli_linked):
                        bpy.ops.object.duplicate_move_linked(
                            OBJECT_OT_duplicate={
                                "linked": True,
                                "mode": 'TRANSLATION'
                            })

                    for i in range(self.dupli):
                        bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={
                            "linked": False,
                            "mode": 'TRANSLATION'
                        })

                    bpy.context.scene.cursor_location = loc_world_space

                    bpy.ops.view3d.snap_selected_to_cursor()

                    bpy.ops.transform.rotate(value=angle, axis=axis)

                bm.to_mesh(obj.data)
                bm.free()

                bpy.context.scene.cursor_location = copy_cursor

                bpy.ops.object.select_all(action='DESELECT')

                # active: dummy
                bpy.context.scene.objects.active = bpy.data.objects["Dummy"]
                bpy.data.objects["Dummy"].select = True

                bpy.ops.object.delete(use_global=False)

                #bpy.ops.object.select_all(action='DESELECT')

                for i in range(self.set_edit_source):

                    # active: second
                    bpy.context.scene.objects.active = bpy.data.objects[
                        second_obj.name]
                    bpy.data.objects[second_obj.name].select = True

                    bpy.ops.object.mode_set(mode='EDIT')

                for i in range(self.set_edit_target):

                    # active: first
                    bpy.context.scene.objects.active = bpy.data.objects[
                        first_obj.name]
                    bpy.data.objects[first_obj.name].select = True

                    bpy.ops.object.mode_set(mode='EDIT')

                    print(self)
                    self.report({'INFO'}, "Editmode")

        else:
            print(self)
            self.report({'INFO'}, "need a source and a target")

        return {"FINISHED"}
예제 #36
0
def cell_fracture_boolean(context, collection, obj, objects,
                          use_debug_bool=False,
                          clean=True,
                          use_island_split=False,
                          use_interior_hide=False,
                          use_debug_redraw=False,
                          level=0,
                          remove_doubles=True
                          ):

    objects_boolean = []
    scene = context.scene
    view_layer = context.view_layer

    if use_interior_hide and level == 0:
        # only set for level 0
        obj.data.polygons.foreach_set("hide", [False] * len(obj.data.polygons))

    for obj_cell in objects:
        mod = obj_cell.modifiers.new(name="Boolean", type='BOOLEAN')
        mod.object = obj
        mod.operation = 'INTERSECT'

        if not use_debug_bool:

            if use_interior_hide:
                obj_cell.data.polygons.foreach_set("hide", [True] * len(obj_cell.data.polygons))

    # Calculates all booleans at once (faster).
    depsgraph = context.evaluated_depsgraph_get()

    for obj_cell in objects:

        if not use_debug_bool:

            obj_cell_eval = obj_cell.evaluated_get(depsgraph)
            mesh_new = bpy.data.meshes.new_from_object(obj_cell_eval)
            mesh_old = obj_cell.data
            obj_cell.data = mesh_new
            obj_cell.modifiers.remove(obj_cell.modifiers[-1])

            # remove if not valid
            if not mesh_old.users:
                bpy.data.meshes.remove(mesh_old)
            if not mesh_new.vertices:
                collection.objects.unlink(obj_cell)
                if not obj_cell.users:
                    bpy.data.objects.remove(obj_cell)
                    obj_cell = None
                    if not mesh_new.users:
                        bpy.data.meshes.remove(mesh_new)
                        mesh_new = None

            # avoid unneeded bmesh re-conversion
            if mesh_new is not None:
                bm = None

                if clean:
                    if bm is None:  # ok this will always be true for now...
                        bm = bmesh.new()
                        bm.from_mesh(mesh_new)
                    bm.normal_update()
                    try:
                        bmesh.ops.dissolve_limit(bm, verts=bm.verts, edges=bm.edges, angle_limit=0.001)
                    except RuntimeError:
                        import traceback
                        traceback.print_exc()

                if remove_doubles:
                    if bm is None:
                        bm = bmesh.new()
                        bm.from_mesh(mesh_new)
                    bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005)

                if bm is not None:
                    bm.to_mesh(mesh_new)
                    bm.free()

            del mesh_new
            del mesh_old

        if obj_cell is not None:
            objects_boolean.append(obj_cell)

            if use_debug_redraw:
                _redraw_yasiamevil()

    if (not use_debug_bool) and use_island_split:
        # this is ugly and Im not proud of this - campbell
        for ob in view_layer.objects:
            ob.select_set(False)
        for obj_cell in objects_boolean:
            obj_cell.select_set(True)

        bpy.ops.mesh.separate(type='LOOSE')

        objects_boolean[:] = [obj_cell for obj_cell in view_layer.objects if obj_cell.select_get()]

    context.view_layer.update()

    return objects_boolean
예제 #37
0
    def execute(self, context):
        if (self.filepath.endswith(".vmf")):

            print("filepath=" + self.filepath)
            map = vmf.ValveMap()

            for ob in bpy.data.objects:
                if ob.type == 'MESH':
                    mesh = ob.to_mesh()

                    bm = bmesh.new()
                    bm.from_mesh(mesh)

                    # data = bmesh.ops.triangulate(bm, faces=bm.faces)

                    edges = bm.edges  #data['edges']
                    faces = bm.faces  #data['faces']

                    blk = Solid()

                    for f in faces:
                        mat = bpy.data.materials[f.material_index + 1]
                        verts = f.verts
                        pos = []
                        norms = []
                        for v in f.verts:
                            pos.append(ob.matrix_world @ v.co)
                            norms.append(ob.matrix_world @ v.normal)
                        if len(verts) >= 3:
                            scale = 102.4
                            vert0 = Vertex(pos[0].x * scale, pos[0].y * scale,
                                           pos[0].z * scale)
                            vert1 = Vertex(pos[1].x * scale, pos[1].y * scale,
                                           pos[1].z * scale)
                            vert2 = Vertex(pos[2].x * scale, pos[2].y * scale,
                                           pos[2].z * scale)
                            plane = Plane(vert2, vert1, vert0)
                            side = Side(plane, mat.name)
                            vertx = VmfVertex()
                            vertx.properties["count"] = len(pos)
                            for i in range(0, len(pos)):
                                p = -i + len(pos) - 1
                                vertx.properties["vertex" + str(p)] = Vertex(
                                    pos[i].x * scale, pos[i].y * scale,
                                    pos[i].z * scale)
                            # vertx.properties["vertex0"] = vert2
                            # vertx.properties["vertex1"] = vert1
                            # vertx.properties["vertex2"] = vert0
                            side.children.append(vertx)
                            # side.uaxis, side.vaxis = plane.sensible_axes()
                            # side.uaxis, side.vaxis = self.axis_calc(plane)

                            matrix = ob.matrix_world
                            matrix2 = ob.matrix_world.inverted()

                            ## world space
                            d = f.normal.copy()
                            d.normalize()
                            d = mathutils.Vector(
                                (abs(d.x), abs(d.y), abs(d.z)))
                            d = self.nearest_axis(d)
                            ua = mathutils.Vector((1.0, 0.0, 0.0))
                            if (d.x != 0.0):
                                ua = mathutils.Vector((0.0, 1.0, 0.0))
                            va = mathutils.Vector((0.0, 0.0, -1.0))
                            if (d.z != 0.0):
                                va = mathutils.Vector((0.0, -1.0, 0.0))

                            ## face space
                            # ua = f.normal.copy()
                            # ua.normalize()
                            # ua = mathutils.Vector((abs(ua.x), abs(ua.y), abs(ua.z)))
                            # ua = self.nearest_axis(ua)
                            # va = mathutils.Vector((0.0, 0.0, -1.0))
                            # if (ua.z == 1.0):
                            #     va = mathutils.Vector((0.0, -1.0, 0.0))
                            # ua = f.normal.copy()
                            # ua.normalize()
                            # ua.cross(va)
                            # va = f.normal.copy()
                            # va.normalize()
                            # va.cross(ua)

                            side.uaxis = Axis(ua.x, ua.y, ua.z)
                            side.vaxis = Axis(va.x, va.y, va.z)

                            uv_layer = 0

                            xmin = min(
                                min(f.loops[0][bm.loops.layers.uv.active].uv.x,
                                    f.loops[1][
                                        bm.loops.layers.uv.active].uv.x),
                                f.loops[2][bm.loops.layers.uv.active].uv.x)
                            xmax = max(
                                max(f.loops[0][bm.loops.layers.uv.active].uv.x,
                                    f.loops[1][
                                        bm.loops.layers.uv.active].uv.x),
                                f.loops[2][bm.loops.layers.uv.active].uv.x)
                            ymin = min(
                                min(f.loops[0][bm.loops.layers.uv.active].uv.y,
                                    f.loops[1][
                                        bm.loops.layers.uv.active].uv.y),
                                f.loops[2][bm.loops.layers.uv.active].uv.y)
                            ymax = max(
                                max(f.loops[0][bm.loops.layers.uv.active].uv.y,
                                    f.loops[1][
                                        bm.loops.layers.uv.active].uv.y),
                                f.loops[2][bm.loops.layers.uv.active].uv.y)

                            side.uaxis.scale = xmax - xmin
                            side.uaxis.translate = xmin
                            side.vaxis.scale = ymax - ymin
                            side.vaxis.translate = ymin

                            xs = f.loops[0][
                                bm.loops.layers.uv.active].uv.x + f.loops[1][
                                    bm.loops.layers.uv.active].uv.x + f.loops[
                                        2][bm.loops.layers.uv.active].uv.x
                            ys = f.loops[0][
                                bm.loops.layers.uv.active].uv.y + f.loops[1][
                                    bm.loops.layers.uv.active].uv.y + f.loops[
                                        2][bm.loops.layers.uv.active].uv.y

                            # side.uaxis.scale = xs / 3.0
                            # side.vaxis.scale = ys / 3.0
                            blk.children.append(side)
                        else:
                            print("a face was missed! " + str(f))

                    map.world.children.append(blk)

                    bm.free()
            map.children.append(VersionInfo())
            map.world.skyname = None
            map.world.properties["mapversion"] = 1
            map.cordon.maxs.x = 1024.0
            map.cordon.maxs.y = 1024.0
            map.cordon.maxs.z = 1024.0
            map.cordon.mins.x = -1024.0
            map.cordon.mins.y = -1024.0
            map.cordon.mins.z = -1024.0

            # write to disk
            map.write_vmf(str(self.filepath))
        return {'FINISHED'}
def export_object(file, ob, apply_modifiers):
    # create temp mesh
    temp_mesh = None
    if apply_modifiers:
        dg = bpy.context.evaluated_depsgraph_get()
        eval_obj = ob.evaluated_get(dg)
        temp_mesh = eval_obj.to_mesh()
    else:
        temp_mesh = ob.to_mesh()
        
    # get bmesh
    bm = bmesh.new()
    bm.from_mesh(temp_mesh)

    # get and sort triangles
    triangles_unsorted = bm.calc_loop_triangles()
    triangles = []
    triangles_unwrapped = []
   
    triangles_buckets = {}   
    for luple in triangles_unsorted:
        face = luple[0].face
        material_index = face.material_index
        
        bucket = []
        if not material_index in triangles_buckets:
            triangles_buckets[material_index] = bucket
        else:
            bucket = triangles_buckets[material_index]
            
        bucket.append(luple)
        
    for key in sorted(triangles_buckets):
        triangles += triangles_buckets[key]
        
    for luple in triangles:
        triangles_unwrapped += luple
        
    # vars
    uv_layer = bm.loops.layers.uv.active
    vc_layer = bm.loops.layers.color.active
    
    num_materials = len(ob.material_slots)
    
    max_dimension = max(ob.dimensions)
    center = translate_vertex(ob.location)
    
    triangles_loops_len = len(triangles) * 3
    triangles_count = len(triangles)
    
    # calculate offsets
    submesh_offset = 64
    vertex_offset = submesh_offset + (16 * num_materials)
    normals_offset = vertex_offset + (44 * triangles_loops_len)
    
    # header
    file.write(struct.pack('L', 259))
    file.write(struct.pack('LL', num_materials, triangles_loops_len))
    file.write(struct.pack('f', max_dimension))
    file.write(struct.pack('fff', *center))
    file.write(struct.pack('LLLL', 0, 0, 0, 0))
    file.write(struct.pack('LLL', submesh_offset, vertex_offset, normals_offset))
    file.write(struct.pack('LL', 0, 0))
    
    # submeshes
    for submesh in range(num_materials):
        submesh_triangles_count = len(triangles_buckets[submesh])
        material = ob.material_slots[submesh].material
        texnum = submesh
        
        if material is not None and "TD5TextureNumber" in material:
            texnum = int(material["TD5TextureNumber"])
        
        file.write(struct.pack('H', 0))
        file.write(struct.pack('H', texnum))
        file.write(struct.pack('L', 0))
        file.write(struct.pack('HH', submesh_triangles_count, 0))
        file.write(struct.pack('L', 0))
    
    # 'vertices'
    for loop in triangles_unwrapped:
        color = (1,1,1,1)
        uv = (0, 0)
        co = translate_vertex(loop.vert.co)
        
        if uv_layer is not None:
            uv = translate_uv(loop[uv_layer].uv)
        if vc_layer is not None:
            color = loop[vc_layer]
            
        file.write(struct.pack('fff', *co)) # position
        file.write(struct.pack('LLLL', 0, 0, 0, 0)) # unknown
        file.write(struct.pack('ff', *uv)) # uv
        file.write(struct.pack('L', 0)) # unknown
        
        cr = int(max(min(color[0], 1.0), 0.0) * 255)
        cg = int(max(min(color[1], 1.0), 0.0) * 255)
        cb = int(max(min(color[2], 1.0), 0.0) * 255)
        ca = int(max(min(color[3], 1.0), 0.0) * 255)
        file.write(struct.pack('BBBB', cr, cg, cb, ca)) # color
        
    # 'normals'
    for loop in triangles_unwrapped:
        normal = translate_normal(loop.vert.normal)
       
        file.write(struct.pack('fff', *normal))
        file.write(struct.pack('L', 0))
    
    # finish off
    bm.free()
    file.close()
    return
예제 #39
0
    def execute(self, context):

        cleaning = True

        #cleaning loop
        while cleaning:
            #{

            bpy.ops.object.mode_set(mode='OBJECT')
            me = bpy.context.object.data
            bm = bmesh.new()
            bm.from_mesh(me)

            # Find average edge size
            average_lenght = 0
            edgecount = 0
            for e in bm.edges:
                average_lenght += e.calc_length()
                edgecount += 1
            average_lenght = average_lenght / edgecount

            # Collapse short edges
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.remove_doubles(threshold=(average_lenght / 3))

            # Count non-manifold verts
            nmvcount = 0
            for v in bm.verts:
                if not v.is_manifold:
                    nmvcount += 1
            if nmvcount is 0:
                cleaning = False
            else:
                cleaning = True

                # MACRO - dissolve and patch up broken vertices
                bpy.ops.object.mode_set(mode='EDIT')
                bpy.ops.mesh.select_all(action='DESELECT')
                context.tool_settings.mesh_select_mode = (True, False, False)
                bpy.ops.mesh.select_non_manifold()
                bpy.ops.mesh.dissolve_verts()
                bpy.ops.mesh.poke()
                bpy.ops.mesh.select_all(action='DESELECT')
                bpy.ops.mesh.select_non_manifold()
                bpy.ops.mesh.delete(type='VERT')
                bpy.ops.mesh.fill_holes(sides=0)

                #fix non planar faces
                bpy.ops.mesh.select_all(action='DESELECT')
                bpy.ops.mesh.vert_connect_nonplanar(angle_limit=0.333)
                bpy.ops.mesh.select_all(action='SELECT')
                context.tool_settings.mesh_select_mode = (False, False, True)
                bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY',
                                                   ngon_method='BEAUTY')

        #}

        bpy.ops.mesh.select_all(action='DESELECT')
        bpy.ops.object.mode_set(mode='OBJECT')

        return {'FINISHED'}
예제 #40
0
 def getDefaultValue(cls):
     return bmesh.new()
예제 #41
0
    def do_import(self, b_model, armature, container):
        print('Importing group: \'', b_model.name, '\'', sep='')

        # Create object and mesh
        mesh = bpy.data.meshes.new(b_model.name)
        mesh.use_auto_smooth = True
        mesh.auto_smooth_angle = 3.14

        object = bpy.data.objects.new(b_model.name, mesh)
        object.parent = container
        bpy.context.collection.objects.link(object)
        bpy.context.view_layer.objects.active = object

        # Assign custom properties
        self.__add_property(obj=object,
                            key="opacity",
                            value=b_model.opacity_amount,
                            range=[-1, 255],
                            description="Opacity of this mesh.")
        self.__add_property(obj=object,
                            key="is_shadow",
                            value="shadow" in object.name,
                            range=[0, 1],
                            description="Is this a shadow mesh?")
        do_tangents = object.get("is_shadow") == False
        self.__add_property(
            obj=object,
            key="calc_tangents",
            value=do_tangents,
            range=[0, 1],
            description="Should tangents be calculated on export?")
        self.__add_property(obj=object,
                            key="neck_fix",
                            value=-1,
                            range=[-1, 5],
                            description="Neck fix to apply (See GMDC Panel)")

        # Load vertices and faces
        mesh.from_pydata(b_model.vertices, [], b_model.faces)

        # Load normals
        for i, vert in enumerate(mesh.vertices):
            vert.normal = b_model.normals[i]

        # Create UV layer and load UV coordinates
        mesh.uv_layers.new(name='UVMap')
        for i, polygon in enumerate(mesh.polygons):
            for j, loopindex in enumerate(polygon.loop_indices):
                meshuvloop = mesh.uv_layers.active.data[loopindex]

                vertex_index = b_model.faces[i][j]
                meshuvloop.uv = b_model.uvs[vertex_index]

        # Load bone assignments and weights
        # Check for mismatches in index counts
        if armature:
            # Create vertex groups for bone assignments
            for b in armature.data.bones:
                object.vertex_groups.new(name=b.name)


            if len(b_model.vertices) != len(b_model.bone_assign) or \
                len(b_model.vertices) != len(b_model.bone_weight):

                #Assign armature modifier anyway.
                object.modifiers.new("Armature", 'ARMATURE')
                object.modifiers["Armature"].object = armature
                object.modifiers["Armature"].use_deform_preserve_volume = False

                error = 'ERROR: Group ' + b_model.name + '\'s vertex index counts don\'t match.'
                return error

            print('Applying bone weights...')
            for i in range(len(b_model.bone_assign)):
                remainder = 1.0  # Used for an implied 4th bone weight
                # print(i, b_model.bone_assign[i])
                for j in range(len(b_model.bone_assign[i])):
                    # If it's a sim skeleton, use boneparent table
                    # Otherwise use bone names
                    if len(armature.data.bones) == 65:
                        grpname = BoneData.bone_parent_table[
                            b_model.bone_assign[i][j]][0]
                    else:
                        # print(b_model.bone_assign[i][j])
                        grpname = armature.data.bones[b_model.bone_assign[i]
                                                      [j]].name

                    vertgroup = object.vertex_groups[grpname]
                    if j != 3:
                        weight = b_model.bone_weight[i][j]
                        remainder -= weight
                        vertgroup.add([i], weight, 'ADD')
                    else:
                        vertgroup.add([i], remainder, 'ADD')

            # Add Armature modifier
            object.modifiers.new("Armature", 'ARMATURE')
            object.modifiers["Armature"].object = armature
            object.modifiers["Armature"].use_deform_preserve_volume = False

        # Apply Morphs(if any) as shape keys
        print('Loading morphs as shape keys...')
        if b_model.morphs:
            # Blender always needs a base shape key
            shpkey = object.shape_key_add(from_mix=False)
            shpkey.name = "Basis"

            try:
                for morph in b_model.morphs:
                    if morph.name == ', ':
                        continue

                    shpkey = object.shape_key_add(from_mix=False)
                    shpkey.name = morph.name

                    for i, vert in enumerate(mesh.vertices):
                        shpkey.data[vert.index].co = Vector(
                            (vert.co[0] + morph.deltas[i][0],
                             vert.co[1] + morph.deltas[i][1],
                             vert.co[2] + morph.deltas[i][2]))
            except:
                print("Additional morphs were discarded.")

        # Add vertex group to control which verts keep their old normals
        # object.vertex_groups.new("__NORMALS__")
        # vertgroup = object.vertex_groups['__NORMALS__']
        ## Should be done manually by user before exporting
        # for i in range (len(mesh.vertices)):
        #     vertgroup.add( [i], 1, 'ADD' )

        # Import Original normals as vertex colors
        mesh.vertex_colors.new(name="__NORMALS__")
        color_map = mesh.vertex_colors['__NORMALS__']
        for poly in mesh.polygons:
            for vert_idx, loop_idx in zip(poly.vertices, poly.loop_indices):
                # Convert Vertex normal to a valid Color
                normal = Vector(b_model.normals[vert_idx])
                normal.normalize()
                rgb = (normal + Vector((1.0, 1.0, 1.0))) * 0.5
                rgba = rgb.to_4d()
                # Set Vertex color to new color
                color_map.data[loop_idx].color = rgba
        print(
            "Original normals imported as vertex colors on layer '__NORMALS__'"
        )
        print()

        # After all that, merge doubles and make originally hard edges sharp
        bm = bmesh.new()
        bm.from_mesh(mesh)

        edges = self.get_sharp(b_model)

        bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001)

        # Check mesh edges against edge dictionary, mark hard edges sharp after removing doubles
        numedges = 0
        for e in bm.edges:
            edgemid = tuple((e.verts[0].co + e.verts[1].co) / 2)
            if edgemid in edges and len(edges[edgemid]) > 2:
                numedges += 1
                e.smooth = False

        print(numedges, 'Hard edges found.')
        print()

        bm.to_mesh(mesh)
        bm.free()

        object.select_set(state=True)
        bpy.ops.object.shade_smooth()

        # Delete loose geometry in case of Maxis object imports
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.select_all(action='SELECT')
        bpy.ops.mesh.delete_loose()
        bpy.ops.object.mode_set(mode='OBJECT')

        return 'Group \'' + b_model.name + '\' imported.\n'
예제 #42
0
    def write_mesh(self, obj, parent):
        """ Internal method to process a mesh during the export process """

        char = None
        armature = None
        restore_armature_modifier = None

        for modifier in obj.modifiers:
            if modifier.type == "PARTICLE_SYSTEM":
                particle_system = modifier.particle_system
                self.writer.handle_particle_system(obj, parent,
                                                   particle_system)

            elif modifier.type == "ARMATURE":
                # The geometry modified by the armature needs to be
                # parented under the character node.
                armature = modifier.object.data
                char = self.writer.characters[armature]
                parent = char

                if modifier.show_viewport:
                    # Prevent the modifier from being applied.
                    modifier.show_viewport = False
                    restore_armature_modifier = modifier

        # Check if we alrady have the geom node cached
        key = (obj.data.name, armature)
        if key in self.geom_cache:
            virtual_geom_node = self.geom_cache[key]

        else:

            # Create a new geom node to store all geoms
            virtual_geom_node = GeomNode(obj.data.name)

            # Convert the object to a mesh, so we can read the polygons
            mesh = obj.to_mesh(self.writer.context.scene,
                               apply_modifiers=True,
                               settings='PREVIEW',
                               calc_tessface=True,
                               calc_undeformed=True)

            # Get a BMesh representation
            b_mesh = bmesh.new()
            b_mesh.from_mesh(mesh)

            # Triangulate the mesh. This makes stuff simpler, and panda can't handle
            # polygons with more than 3 vertices.
            bmesh.ops.triangulate(b_mesh, faces=b_mesh.faces)

            # Copy the bmesh back to the original mesh
            b_mesh.to_mesh(mesh)

            # Find the active uv layer and its name, in case there is one.
            if mesh.uv_layers.active:
                active_uv_layer = mesh.uv_layers.active.data
                active_uv_name = mesh.uv_layers.active.name
            else:
                active_uv_layer = None
                active_uv_name = ""

            # Group the polygons by their material index. We have to perform this
            # operation, because we have to create a single geom for each material
            polygons_by_material = self._group_mesh_faces_by_material(mesh)

            # Calculate the per-vertex normals, in case blender did not do that yet.
            mesh.calc_normals()

            # Extract material slots, but ensure there is always one slot, so objects
            # with no actual material get exported, too
            material_slots = obj.material_slots

            if len(material_slots) == 0:
                material_slots = [None]

            # Create the different geoms, 1 per material
            for index, slot in enumerate(material_slots):

                # Skip the material slot if no polygon references it
                if len(polygons_by_material[index]) < 1:
                    continue

                # Create a virtual material if the slot contains a material. Otherwise
                # just use an empty material
                if slot:
                    render_state = self.writer.material_writer.create_state_from_material(
                        slot.material)
                else:
                    render_state = RenderState.empty

                # Extract the per-material polygon list
                polygons = polygons_by_material[index]

                # Create a geom from those polygons
                virtual_geom = self._create_geom_from_polygons(obj,
                                                               mesh,
                                                               polygons,
                                                               active_uv_layer,
                                                               char=char)

                # Add that geom to the geom node
                virtual_geom_node.add_geom(virtual_geom, render_state)

            bpy.data.meshes.remove(mesh)

            self.geom_cache[key] = virtual_geom_node

        parent.add_child(virtual_geom_node)

        if restore_armature_modifier:
            restore_armature_modifier.show_viewport = True
예제 #43
0
def dot_mesh(ob,
             path,
             force_name=None,
             ignore_shape_animation=False,
             normals=True,
             tangents=4,
             isLOD=False,
             **kwargs):
    """
    export the vertices of an object into a .mesh file

    ob: the blender object
    path: the path to save the .mesh file to. path MUST exist
    force_name: force a different name for this .mesh
    kwargs:
      * material_prefix - string. (optional)
      * overwrite - bool. (optional) default False
    """
    obj_name = force_name or ob.data.name
    obj_name = clean_object_name(obj_name)
    target_file = os.path.join(path, '%s.mesh.xml' % obj_name)

    material_prefix = kwargs.get('material_prefix', '')
    overwrite = kwargs.get('overwrite', False)

    if os.path.isfile(target_file) and not overwrite:
        return []

    if not os.path.isdir(path):
        os.makedirs(path)

    start = time.time()

    cleanup = False
    if ob.modifiers:
        cleanup = True
        copy = ob.copy()
        #bpy.context.scene.collection.objects.link(copy)
        rem = []
        for mod in copy.modifiers:  # remove armature and array modifiers before collaspe
            if mod.type in 'ARMATURE ARRAY'.split(): rem.append(mod)
        for mod in rem:
            copy.modifiers.remove(mod)
    else:
        copy = ob

    # bake mesh
    mesh = copy.to_mesh()  # collaspe
    mesh.update()
    # Blender by default does not calculate these.
    # When querying the quads/tris of the object blender would crash if calc_tessface was not updated
    mesh.calc_loop_triangles()

    Report.meshes.append(obj_name)
    Report.faces += len(mesh.loop_triangles)
    Report.orig_vertices += len(mesh.vertices)

    logger.info('* Generating: %s.mesh.xml' % obj_name)

    try:
        with open(target_file, 'w') as f:
            f.flush()
    except Exception as e:
        show_dialog("Invalid mesh object name: %s" % obj_name)
        return

    with open(target_file, 'w') as f:
        doc = SimpleSaxWriter(f, 'mesh', {})

        # Very ugly, have to replace number of vertices later
        doc.start_tag('sharedgeometry',
                      {'vertexcount': '__TO_BE_REPLACED_VERTEX_COUNT__'})

        logger.info('* Writing shared geometry')

        # Textures
        dotextures = False
        if mesh.uv_layers.active:
            dotextures = True
        else:
            tangents = 0

        doc.start_tag(
            'vertexbuffer', {
                'positions': 'true',
                'normals': 'true',
                'tangents': str(bool(tangents)),
                'tangent_dimensions': str(tangents),
                'colours_diffuse': str(bool(mesh.vertex_colors)),
                'texture_coords': '%s' % len(mesh.uv_layers) * dotextures
            })

        # Materials
        # saves tuples of material name and material obj (or None)
        materials = []
        # a material named 'vertex.color.<yourname>' will overwrite
        # the diffuse color in the mesh file!

        for mat in ob.data.materials:
            mat_name = "_missing_material_"
            if mat is not None:
                mat_name = mat.name
            mat_name = material_name(mat_name, prefix=material_prefix)
            extern = False
            if mat_name.startswith("extern."):
                mat_name = mat_name[len("extern."):]
                extern = True
            if mat:
                materials.append((mat_name, extern, mat))
            else:
                logger.warn('Bad material data in: %s' % ob.name)
                materials.append(('_missing_material_', True,
                                  None))  # fixed dec22, keep proper index
        if not materials:
            materials.append(('_missing_material_', True, None))
        vertex_groups = {}
        material_faces = []
        for matidx, mat in enumerate(materials):
            material_faces.append([])

        shared_vertices = {}
        _remap_verts_ = []
        _remap_normals_ = []
        _face_indices_ = []

        numverts = 0

        # Create bmesh to help obtain custom vertex normals
        bm = bmesh.new()
        if mesh.has_custom_normals:
            mesh.calc_normals_split()
            bm.from_mesh(mesh)
            bm.verts.ensure_lookup_table()
        else:
            bm.from_mesh(mesh)

        # Ogre only supports triangles
        bmesh_return = bmesh.ops.triangulate(bm, faces=bm.faces)
        bm.to_mesh(mesh)

        # Map the original face indices to the tesselated ones
        face_map = bmesh_return['face_map']

        _tess_polygon_face_map_ = {}

        for tess_face in face_map:
            #print("tess_face.index : %s <---> polygon_face.index : %s" % (tess_face.index, face_map[tess_face].index))
            _tess_polygon_face_map_[
                tess_face.index] = face_map[tess_face].index

        # Vertex colors
        vertex_color_lookup = VertexColorLookup(mesh)

        if tangents:
            mesh.calc_tangents(uvmap=mesh.uv_layers.active.name)

        progressScale = 1.0 / len(mesh.polygons)

        # Process mesh after triangulation
        for F in mesh.polygons:
            percent = (F.index + 1) * progressScale
            sys.stdout.write("\r + Faces [" + '=' * int(percent * 50) + '>' +
                             '.' * int(50 - percent * 50) + "] " +
                             str(int(percent * 10000) / 100.0) + "%   ")
            sys.stdout.flush()

            smooth = F.use_smooth
            tri = (F.vertices[0], F.vertices[1], F.vertices[2])
            face = []
            for loop_idx, idx in zip(F.loop_indices, tri):
                v = mesh.vertices[idx]

                if smooth:
                    n = mathutils.Vector()
                    if mesh.has_custom_normals:
                        for loop in bm.verts[idx].link_loops:
                            n += mesh.loops[loop.index].normal
                        n.normalize()
                        nx, ny, nz = swap(n)
                    # when no custom normals or mesh.loops[...].normal is zero vector
                    # use normal vector from vertex
                    if n.length_squared == 0:
                        nx, ny, nz = swap(v.normal)  # fixed june 17th 2011
                        n = mathutils.Vector([nx, ny, nz])
                elif tangents:
                    nx, ny, nz = swap(mesh.loops[loop_idx].normal)
                    n = mathutils.Vector([nx, ny, nz])
                else:
                    nx, ny, nz = swap(F.normal)
                    n = mathutils.Vector([nx, ny, nz])

                if tangents:
                    tx, ty, tz = swap(mesh.loops[loop_idx].tangent)
                    tw = mesh.loops[loop_idx].bitangent_sign

                r, g, b, ra = vertex_color_lookup.get(loop_idx)

                # Texture maps
                vert_uvs = []
                if dotextures:
                    for layer in mesh.uv_layers:
                        vert_uvs.append(layer.data[loop_idx].uv)
                ''' Check if we already exported that vertex with same normal, do not export in that case,
                    (flat shading in blender seems to work with face normals, so we copy each flat face'
                    vertices, if this vertex with same normals was already exported,
                    todo: maybe not best solution, check other ways (let blender do all the work, or only
                    support smooth shading, what about seems, smoothing groups, materials, ...)
                '''
                vert = VertexNoPos(numverts, nx, ny, nz, r, g, b, ra, vert_uvs)
                alreadyExported = False
                if idx in shared_vertices:
                    for vert2 in shared_vertices[idx]:
                        #does not compare ogre_vidx (and position at the moment)
                        if vert == vert2:
                            face.append(vert2.ogre_vidx)
                            alreadyExported = True
                            #print(idx,numverts, nx,ny,nz, r,g,b,ra, vert_uvs, "already exported")
                            break
                    if not alreadyExported:
                        face.append(vert.ogre_vidx)
                        shared_vertices[idx].append(vert)
                        #print(numverts, nx,ny,nz, r,g,b,ra, vert_uvs, "appended")
                else:
                    face.append(vert.ogre_vidx)
                    shared_vertices[idx] = [vert]
                    #print(idx, numverts, nx,ny,nz, r,g,b,ra, vert_uvs, "created")

                if alreadyExported:
                    continue

                numverts += 1
                _remap_verts_.append(v)
                _remap_normals_.append(n)

                # Use mapping from tesselated face to polygon face if the mapping exists
                if F.index in _tess_polygon_face_map_:
                    _face_indices_.append(_tess_polygon_face_map_[F.index])
                else:
                    _face_indices_.append(F.index)

                x, y, z = swap(v.co)  # xz-y is correct!

                doc.start_tag('vertex', {})
                doc.leaf_tag('position', {
                    'x': '%6f' % x,
                    'y': '%6f' % y,
                    'z': '%6f' % z
                })

                doc.leaf_tag('normal', {
                    'x': '%6f' % nx,
                    'y': '%6f' % ny,
                    'z': '%6f' % nz
                })

                if tangents:
                    doc.leaf_tag(
                        'tangent', {
                            'x': '%6f' % tx,
                            'y': '%6f' % ty,
                            'z': '%6f' % tz,
                            'w': '%6f' % tw
                        })

                if vertex_color_lookup.has_color_data:
                    doc.leaf_tag('colour_diffuse',
                                 {'value': '%6f %6f %6f %6f' % (r, g, b, ra)})

                # Texture maps
                if dotextures:
                    for uv in vert_uvs:
                        doc.leaf_tag('texcoord', {
                            'u': '%6f' % uv[0],
                            'v': '%6f' % (1.0 - uv[1])
                        })

                doc.end_tag('vertex')

            append_triangle_in_vertex_group(mesh, ob, vertex_groups, face, tri)
            material_faces[F.material_index].append(face)

        Report.vertices += numverts

        doc.end_tag('vertexbuffer')
        doc.end_tag('sharedgeometry')

        print("")
        logger.info('- Done at %s seconds' % timer_diff_str(start))
        logger.info('* Writing submeshes')

        doc.start_tag('submeshes', {})
        for matidx, (mat_name, extern, mat) in enumerate(materials):
            if not len(material_faces[matidx]):
                Report.warnings.append(
                    'BAD SUBMESH "%s": material %r, has not been applied to any faces - not exporting as submesh.'
                    % (obj_name, mat_name))
                continue  # fixes corrupt unused materials

            submesh_attributes = {
                'usesharedvertices': 'true',
                # Maybe better look at index of all faces, if one over 65535 set to true;
                # Problem: we know it too late, postprocessing of file needed
                "use32bitindexes": str(bool(numverts > 65535)),
                "operationtype": "triangle_list"
            }
            if mat_name != "_missing_material_":
                submesh_attributes['material'] = mat_name

            doc.start_tag('submesh', submesh_attributes)
            doc.start_tag('faces', {'count': str(len(material_faces[matidx]))})
            for fidx, (v1, v2, v3) in enumerate(material_faces[matidx]):
                doc.leaf_tag('face', {
                    'v1': str(v1),
                    'v2': str(v2),
                    'v3': str(v3)
                })
            doc.end_tag('faces')
            doc.end_tag('submesh')
            Report.triangles += len(material_faces[matidx])

        for name, ogre_indices in vertex_groups.items():
            if len(ogre_indices) <= 0:
                continue
            submesh_attributes = {
                'usesharedvertices': 'true',
                "use32bitindexes": str(bool(numverts > 65535)),
                "operationtype": "triangle_list",
                "material": "none",
            }
            doc.start_tag('submesh', submesh_attributes)
            doc.start_tag('faces', {'count': len(ogre_indices)})
            for (v1, v2, v3) in ogre_indices:
                doc.leaf_tag('face', {
                    'v1': str(v1),
                    'v2': str(v2),
                    'v3': str(v3)
                })
            doc.end_tag('faces')
            doc.end_tag('submesh')

        del material_faces
        del shared_vertices
        doc.end_tag('submeshes')

        # Submesh names
        # todo: why is the submesh name taken from the material
        # when we have the blender object name available?
        doc.start_tag('submeshnames', {})
        for matidx, (mat_name, extern, mat) in enumerate(materials):
            doc.leaf_tag('submesh', {'name': mat_name, 'index': str(matidx)})
        idx = len(materials)
        for name in vertex_groups.keys():
            name = name[len('ogre.vertex.group.'):]
            doc.leaf_tag('submesh', {'name': name, 'index': idx})
            idx += 1
        doc.end_tag('submeshnames')

        logger.info('- Done at %s seconds' % timer_diff_str(start))

        # Generate lod levels
        if isLOD == False and ob.type == 'MESH' and config.get(
                'LOD_LEVELS') > 0 and config.get('LOD_MESH_TOOLS') == False:
            lod_levels = config.get('LOD_LEVELS')
            lod_distance = config.get('LOD_DISTANCE')
            lod_ratio = config.get('LOD_PERCENT') / 100.0
            lod_pre_mesh_count = len(bpy.data.meshes)

            # Cap lod levels to something sensible (what is it?)
            if lod_levels > 10:
                lod_levels = 10

            def duplicate_object(scene, name, copyobj):
                # Create new mesh
                mesh = bpy.data.meshes.new(name)

                # Create new object associated with the mesh
                ob_new = bpy.data.objects.new(name, mesh)

                # Copy data block from the old object into the new object
                ob_new.data = copyobj.data.copy()
                ob_new.location = copyobj.location
                ob_new.rotation_euler = copyobj.rotation_euler
                ob_new.scale = copyobj.scale

                # Link new object to the given scene and select it
                scene.collection.objects.link(ob_new)
                ob_new.select_set(True)

                return ob_new, mesh

            # Create a temporary duplicate
            ob_copy, ob_copy_mesh = duplicate_object(
                bpy.context.scene, obj_name + "_LOD_TEMP_COPY", ob)
            ob_copy_meshes = [ob_copy.data, ob_copy_mesh]

            # Activate clone for modifier manipulation
            decimate = ob_copy.modifiers.new(name="Ogre-LOD_Decimate",
                                             type='DECIMATE')
            if decimate is not None:
                decimate.decimate_type = 'COLLAPSE'
                decimate.show_viewport = True
                decimate.show_render = True

                lod_generated = []
                lod_ratio_multiplier = 1.0 - lod_ratio
                lod_current_ratio = 1.0 * lod_ratio_multiplier
                lod_current_distance = lod_distance
                lod_current_vertice_count = len(mesh.vertices)
                lod_min_vertice_count = 12

                for level in range(lod_levels + 1)[1:]:
                    decimate.ratio = lod_current_ratio

                    # https://docs.blender.org/api/current/bpy.types.Depsgraph.html
                    depsgraph = bpy.context.evaluated_depsgraph_get()
                    object_eval = ob_copy.evaluated_get(depsgraph)
                    lod_mesh = bpy.data.meshes.new_from_object(object_eval)

                    ob_copy_meshes.append(lod_mesh)

                    # Check min vertice count and that the vertice count got reduced from last iteration
                    lod_mesh_vertices = len(lod_mesh.vertices)

                    if lod_mesh_vertices < lod_min_vertice_count:
                        logger.info(
                            '- LOD level: %s, vertice count: %s too small. Ignoring LOD.'
                            % (level, lod_mesh_vertices))
                        break
                    if lod_mesh_vertices >= lod_current_vertice_count:
                        logger.info(
                            '- LOD level: %s, vertice count: %s cannot be decimated any longer. Ignoring LOD.'
                            % (level - 1, lod_mesh_vertices))
                        break
                    # todo: should we check if the ratio gets too small? although its up to the user to configure from the export panel

                    lod_generated.append({
                        'level': level,
                        'distance': lod_current_distance,
                        'ratio': lod_current_ratio,
                        'mesh': lod_mesh
                    })
                    lod_current_distance += lod_distance
                    lod_current_vertice_count = lod_mesh_vertices
                    lod_current_ratio *= lod_ratio_multiplier

                # Create lod .mesh files and generate LOD XML to the original .mesh.xml
                if len(lod_generated) > 0:
                    # 'manual' means if the geometry gets loaded from a
                    # different file that this LOD list references
                    # NOTE: This is the approach at the moment. Another option would be to
                    # references to the same vertex indexes in the shared geometry. But the
                    # decimate approach wont work with this as it generates a fresh geometry.
                    doc.start_tag(
                        'levelofdetail',
                        {
                            'strategy': 'default',
                            'numlevels': str(
                                len(lod_generated) + 1
                            ),  # The main mesh is + 1 (kind of weird Ogre logic)
                            'manual': "true"
                        })

                    logger.info(
                        '- Generating: %s LOD meshes. Original: vertices %s, faces: %s'
                        % (len(lod_generated), len(
                            mesh.vertices), len(mesh.loop_triangles)))
                    for lod in lod_generated:
                        ratio_percent = round(lod['ratio'] * 100.0, 0)
                        logger.info(
                            "- Writing LOD %s for distance %s and ratio %s/100, with %s vertices, %s faces"
                            % (lod['level'], lod['distance'],
                               str(ratio_percent), len(lod['mesh'].vertices),
                               len(lod['mesh'].loop_triangles)))
                        lod_ob_temp = bpy.data.objects.new(
                            obj_name, lod['mesh'])
                        lod_ob_temp.data.name = obj_name + '_LOD_' + str(
                            lod['level'])
                        dot_mesh(lod_ob_temp,
                                 path,
                                 lod_ob_temp.data.name,
                                 ignore_shape_animation,
                                 normals,
                                 tangents,
                                 isLOD=True)

                        # 'value' is the distance this LOD kicks in for the 'Distance' strategy.
                        doc.leaf_tag(
                            'lodmanual', {
                                'value': str(lod['distance']),
                                'meshname': lod_ob_temp.data.name + ".mesh"
                            })

                        # Delete temporary LOD object.
                        # The clone meshes will be deleted later.
                        lod_ob_temp.user_clear()
                        logger.debug("Removing temporary LOD object: %s" %
                                     lod_ob_temp.name)
                        bpy.data.objects.remove(lod_ob_temp, do_unlink=True)
                        del lod_ob_temp

                    doc.end_tag('levelofdetail')

            # Delete temporary LOD object
            logger.debug("Removing temporary LOD object: %s" % ob_copy.name)
            bpy.data.objects.remove(ob_copy, do_unlink=True)
            del ob_copy

            # Delete temporary data/mesh objects
            bpy.context.evaluated_depsgraph_get().update()
            for mesh_iter in ob_copy_meshes:
                mesh_iter.user_clear()
                logger.debug("Removing temporary LOD mesh: %s" %
                             mesh_iter.name)
                bpy.data.meshes.remove(mesh_iter)
                del mesh_iter
            ob_copy_meshes = []

            if lod_pre_mesh_count != len(bpy.data.meshes):
                logger.warn(
                    '- After LOD generation, cleanup failed to erase all temporary data!'
                )

        arm = ob.find_armature()
        if arm:
            doc.leaf_tag('skeletonlink', {'name': '%s.skeleton' % obj_name})
            doc.start_tag('boneassignments', {})
            boneOutputEnableFromName = {}
            boneIndexFromName = {}
            for bone in arm.pose.bones:
                boneOutputEnableFromName[bone.name] = True
                if config.get('ONLY_DEFORMABLE_BONES'):
                    # if we found a deformable bone,
                    if bone.bone.use_deform:
                        # visit all ancestor bones and mark them "output enabled"
                        parBone = bone.parent
                        while parBone:
                            boneOutputEnableFromName[parBone.name] = True
                            parBone = parBone.parent
                    else:
                        # non-deformable bone, no output
                        boneOutputEnableFromName[bone.name] = False
            boneIndex = 0
            for bone in arm.pose.bones:
                boneIndexFromName[bone.name] = boneIndex
                if boneOutputEnableFromName[bone.name]:
                    boneIndex += 1
            badverts = 0
            for vidx, v in enumerate(_remap_verts_):
                check = 0
                for vgroup in v.groups:
                    if vgroup.weight > config.get('TRIM_BONE_WEIGHTS'):
                        groupIndex = vgroup.group
                        if groupIndex < len(copy.vertex_groups):
                            vg = copy.vertex_groups[groupIndex]
                            if vg.name in boneIndexFromName:  # allows other vertex groups, not just armature vertex groups
                                bnidx = boneIndexFromName[
                                    vg.
                                    name]  # find_bone_index(copy,arm,vgroup.group)
                                doc.leaf_tag(
                                    'vertexboneassignment', {
                                        'vertexindex': str(vidx),
                                        'boneindex': str(bnidx),
                                        'weight': '%6f' % vgroup.weight
                                    })
                                check += 1
                        else:
                            logger.warn(
                                'Mesh: %s vertex groups not in sync with armature %s (groupIndex = %s)'
                                % (mesh.name, arm.name, groupIndex))
                if check > 4:
                    badverts += 1
                    logger.warn(
                        '<%s> vertex %s is in more than 4 vertex groups (bone weights). This maybe Ogre incompatible'
                        % (mesh.name, vidx))
            if badverts:
                Report.warnings.append(
                    'Mesh "%s" has %s vertices weighted to too many bones (Ogre limits a vertex to 4 bones). Try increasing the Trim-Weights threshold option'
                    % (mesh.name, badverts))
            doc.end_tag('boneassignments')

        # Updated June3 2011 - shape animation works
        if config.get('SHAPE_ANIMATIONS') and ob.data.shape_keys and len(
                ob.data.shape_keys.key_blocks):
            logger.info('* Writing shape keys')

            doc.start_tag('poses', {})
            for sidx, skey in enumerate(ob.data.shape_keys.key_blocks):
                if sidx == 0: continue
                if len(skey.data) != len(mesh.vertices):
                    failure = 'FAILED to save shape animation - you can not use a modifier that changes the vertex count! '
                    failure += '[ mesh : %s ]' % mesh.name
                    Report.warnings.append(failure)
                    logger.error(failure)
                    break

                doc.start_tag(
                    'pose',
                    {
                        'name': skey.name,
                        # If target is 'mesh', no index needed, if target is submesh then submesh identified by 'index'
                        #'index' : str(sidx-1),
                        #'index' : '0',
                        'target': 'mesh'
                    })

                snormals = None

                if config.get('SHAPE_NORMALS'):
                    if smooth:
                        snormals = skey.normals_vertex_get()
                    else:
                        snormals = skey.normals_polygon_get()

                for vidx, v in enumerate(_remap_verts_):
                    pv = skey.data[v.index]
                    x, y, z = swap(pv.co - v.co)

                    if config.get('SHAPE_NORMALS'):
                        n = _remap_normals_[vidx]

                        if smooth:
                            pn = mathutils.Vector([
                                snormals[v.index * 3 + 0],
                                snormals[v.index * 3 + 1],
                                snormals[v.index * 3 + 2]
                            ])
                        else:
                            vindex = _face_indices_[vidx]

                            pn = mathutils.Vector([
                                snormals[vindex * 3 + 0],
                                snormals[vindex * 3 + 1],
                                snormals[vindex * 3 + 2]
                            ])

                        if mesh.has_custom_normals:
                            nx, ny, nz = n
                        else:
                            nx, ny, nz = swap(pn)

                    #for i,p in enumerate( skey.data ):
                    #x,y,z = p.co - ob.data.vertices[i].co
                    #x,y,z = swap( ob.data.vertices[i].co - p.co )
                    #if x==.0 and y==.0 and z==.0: continue        # the older exporter optimized this way, is it safe?
                    if config.get('SHAPE_NORMALS'):
                        doc.leaf_tag(
                            'poseoffset',
                            {
                                'x': '%6f' % x,
                                'y': '%6f' % y,
                                'z': '%6f' % z,
                                'nx': '%6f' % nx,
                                'ny': '%6f' % ny,
                                'nz': '%6f' % nz,
                                'index': str(vidx)  # is this required?
                            })
                    else:
                        doc.leaf_tag(
                            'poseoffset',
                            {
                                'x': '%6f' % x,
                                'y': '%6f' % y,
                                'z': '%6f' % z,
                                'index': str(vidx)  # is this required?
                            })
                doc.end_tag('pose')
            doc.end_tag('poses')

            logger.info('- Done at %s seconds' % timer_diff_str(start))

            if ob.data.shape_keys.animation_data and len(
                    ob.data.shape_keys.animation_data.nla_tracks):
                logger.info('* Writing shape animations')
                doc.start_tag('animations', {})
                _fps = float(bpy.context.scene.render.fps)
                for nla in ob.data.shape_keys.animation_data.nla_tracks:
                    for idx, strip in enumerate(nla.strips):
                        doc.start_tag(
                            'animation', {
                                'name':
                                strip.name,
                                'length':
                                str((strip.frame_end - strip.frame_start) /
                                    _fps)
                            })
                        doc.start_tag('tracks', {})
                        doc.start_tag(
                            'track',
                            {
                                'type': 'pose',
                                'target': 'mesh'
                                # If target is 'mesh', no index needed, if target is submesh then submesh identified by 'index'
                                #'index' : str(idx)
                                #'index' : '0'
                            })
                        doc.start_tag('keyframes', {})
                        for frame in range(
                                int(strip.frame_start),
                                int(strip.frame_end) + 1,
                                bpy.context.scene.frame_step):  #thanks to Vesa
                            bpy.context.scene.frame_set(frame)
                            doc.start_tag(
                                'keyframe', {
                                    'time': str(
                                        (frame - strip.frame_start) / _fps)
                                })
                            for sidx, skey in enumerate(
                                    ob.data.shape_keys.key_blocks):
                                if sidx == 0: continue
                                doc.leaf_tag(
                                    'poseref', {
                                        'poseindex': str(sidx - 1),
                                        'influence': str(skey.value)
                                    })
                            doc.end_tag('keyframe')
                        doc.end_tag('keyframes')
                        doc.end_tag('track')
                        doc.end_tag('tracks')
                        doc.end_tag('animation')
                doc.end_tag('animations')
                logger.info('- Done at %s seconds' % timer_diff_str(start))

        ## Clean up and save
        if cleanup:
            #bpy.context.collection.objects.unlink(copy)
            copy.user_clear()
            logger.debug("Removing temporary object: %s" % copy.name)
            bpy.data.objects.remove(copy)
            del copy

        del _remap_verts_
        del _remap_normals_
        del _face_indices_
        doc.close()  # reported by Reyn
        f.close()

        logger.info('- Created %s.mesh.xml at %s seconds' %
                    (obj_name, timer_diff_str(start)))

    # todo: Very ugly, find better way
    def replaceInplace(f, searchExp, replaceExp):
        import fileinput
        for line in fileinput.input(f, inplace=1):
            if searchExp in line:
                line = line.replace(searchExp, replaceExp)
            sys.stdout.write(line)
        fileinput.close()  # reported by jakob

    replaceInplace(target_file, '__TO_BE_REPLACED_VERTEX_COUNT__' + '"',
                   str(numverts) + '"')  #+ ' ' * (ls - lr))
    del (replaceInplace)

    # Start .mesh.xml to .mesh convertion tool
    util.xml_convert(target_file, has_uvs=dotextures)

    logger.info('- Created %s.mesh in total time %s seconds' %
                (obj_name, timer_diff_str(start)))

    # If requested by the user, generate LOD levels through OgreMeshUpgrader
    if config.get('LOD_LEVELS') > 0 and config.get('LOD_MESH_TOOLS') == True:
        target_mesh_file = os.path.join(path, '%s.mesh' % obj_name)
        util.lod_create(target_mesh_file)

    # Note that exporting the skeleton does not happen here anymore
    # It was moved to the function dot_skeleton in its own module (skeleton.py)

    mats = []
    for mat_name, extern, mat in materials:
        # _missing_material_ is marked as extern
        if not extern:
            mats.append(mat_name)
        else:
            logger.info("Extern material: %s" % mat_name)

    return mats
예제 #44
0
def makeInvertedSlope(dimensions: dict,
                      brickSize: list,
                      brickType: str,
                      loopCut: bool,
                      direction: str = None,
                      circleVerts: int = None,
                      detail: str = "LOW",
                      stud: bool = True,
                      bme: bmesh = None):
    # TODO: Add support for loopCut
    """
    create slope brick with bmesh

    NOTE: brick created with slope facing +X direction, then translated/rotated as necessary

    Keyword Arguments:
        dimensions  -- dictionary containing brick dimensions
        brickSize   -- size of brick (e.g. 2x3 slope -> [2, 3, 3])
        brickType   -- cm.brickType
        loopCut     -- loop cut cylinders so bevels can be cleaner
        direction   -- direction slant faces in ("X+", "X-", "Y+", "Y-")
        circleVerts -- number of vertices per circle of cylinders
        detail      -- level of brick detail (options: ("FLAT", "LOW", "MEDIUM", "HIGH"))
        stud        -- create stud on top of brick
        bme         -- bmesh object in which to create verts

    """
    # create new bmesh object
    bme = bmesh.new() if not bme else bme

    # set direction to longest side if None (defaults to X if sides are the same)
    maxIdx = brickSize.index(max(brickSize[:2]))
    directions = ["X+", "Y+", "X-", "Y-"]
    # default to "X+" if X is larger, "Y+" if Y is larger
    direction = direction or directions[maxIdx]
    # verify direction is valid
    assert direction in directions

    # get halfScale
    bAndPBrick = flatBrickType(brickType) and brickSize[2] == 3
    height = dimensions["height"] * (3 if bAndPBrick else 1)
    d = Vector((dimensions["width"] / 2, dimensions["width"] / 2, height / 2))
    # get scalar for d in positive xyz directions
    adjustedBrickSize = (brickSize[:2] if "X" in direction else
                         brickSize[1::-1]) + brickSize[2:]
    scalar = Vector(
        (adjustedBrickSize[0] * 2 - 1, adjustedBrickSize[1] * 2 - 1, 1))
    # get thickness of brick from inside to outside
    thick = Vector([dimensions["thickness"]] * 3)

    # make brick body cube
    coord1 = -d
    coord2 = vec_mult(d, [1, scalar.y, 1])
    v1, v2, v3, v4, v5, v6, v7, v8 = makeCube(
        coord1,
        coord2, [0 if stud else 1, 1 if detail == "FLAT" else 0, 0, 0, 1, 1],
        bme=bme)
    if adjustedBrickSize[0] > 1:
        # remove bottom verts on slope side
        bme.verts.remove(v6)
        bme.verts.remove(v7)
    # add face to opposite side from slope
    bme.faces.new((v1, v5, v8, v2))

    # make square at end of slope
    coord1 = vec_mult(d, [scalar.x, -1, 1])
    coord2 = vec_mult(d, [scalar.x, scalar.y, 1])
    coord1.z -= thick.z
    v9, v10, v11, v12 = makeSquare(coord1, coord2, bme=bme)

    # connect square to body cube
    bme.faces.new([v8, v11, v10, v3, v2])
    bme.faces.new([v9, v12, v5, v1, v4])
    if max(brickSize[:2]) == 2 or detail in ["FLAT", "LOW"]:
        bme.faces.new((v4, v3, v10, v9))
    else:
        pass
        # TODO: Draw inset half-cylinder

    # add details on top
    if not stud:
        bme.faces.new((v12, v11, v8, v5))
    else:
        if adjustedBrickSize[0] > 1:
            # make upper square over slope
            coord1 = Vector(
                (d.x, -d.y + thick.y / 2,
                 -d.z * (0.5 if max(adjustedBrickSize[:2]) == 2 else 0.625)))
            coord2 = Vector(
                (d.x * scalar.x - thick.x, d.y * scalar.y - thick.y / 2, d.z))
            # v13, v14, v15, v16, v17, v18, v19, v20 = makeCube(coord1, coord2, [0, 0, 1, 0 if sum(adjustedBrickSize[:2]) == 5 else 1, 1, 1], flipNormals=True, bme=bme)
            # TODO: replace the following line with line above to add support details later
            print()
            print(coord1)
            print(coord2)
            print(scalar)
            v13, v14, v15, v16, v17, v18, v19, v20 = makeCube(
                coord1, coord2, [0, 0, 1, 1, 1, 1], flipNormals=True, bme=bme)
            v15.co.z += (d.z * 2 - thick.z) * (0.9 if max(
                adjustedBrickSize[:2]) == 3 else 0.8)
            v16.co.z = v15.co.z
            # make faces on edges of new square
            bme.faces.new((v18, v17, v5, v12))
            bme.faces.new((v19, v18, v12, v11))
            bme.faces.new((v20, v19, v11, v8))
            addSlopeStuds(dimensions,
                          height,
                          adjustedBrickSize,
                          brickType,
                          circleVerts,
                          bme,
                          edgeXp=[v14, v13],
                          edgeXn=[v16, v15],
                          edgeYp=[v13, v16],
                          edgeYn=[v15, v14],
                          loopCut=loopCut)
        else:
            v17, v20 = v6, v7

        addStuds(dimensions,
                 height, [1, adjustedBrickSize[1], adjustedBrickSize[2]],
                 brickType,
                 circleVerts,
                 bme,
                 edgeXp=[v20, v17],
                 edgeXn=[v8, v5],
                 edgeYp=[v20, v8],
                 edgeYn=[v17, v5],
                 hollow=False,
                 loopCut=loopCut)
        pass

    # add details underneath
    if detail != "FLAT":
        # making verts for hollow portion
        coord1 = -d + Vector((thick.x, thick.y, 0))
        coord2 = Vector(
            (d.x + (dimensions["tick_depth"] if detail == "HIGH" else 0),
             d.y * scalar.y, d.z * scalar.z)) - thick
        sides = [
            1 if detail == "LOW" else 0, 0, 0 if detail == "HIGH" else 1, 1, 1,
            1
        ]
        v21, v22, v23, v24, v25, v26, v27, v28 = makeCube(coord1,
                                                          coord2,
                                                          sides,
                                                          flipNormals=True,
                                                          bme=bme)
        # make faces on bottom edges of brick
        bme.faces.new((v1, v21, v24, v4))
        bme.faces.new((v1, v2, v22, v21))
        bme.faces.new((v23, v22, v2, v3))

        # make tick marks inside
        if detail == "HIGH":
            bottomVertsD = addTickMarks(
                dimensions,
                [1, min(adjustedBrickSize[:2]), adjustedBrickSize[2]],
                circleVerts,
                detail,
                d,
                thick,
                bme,
                nno=v1,
                npo=v2,
                ppo=v3,
                pno=v4,
                nni=v21,
                npi=v22,
                ppi=v23,
                pni=v24,
                nnt=v25,
                npt=v28,
                ppt=v27,
                pnt=v26,
                inverted_slope=True,
                sideMarks=False)
            bottomVerts = bottomVertsD["X+"][::-1]
        else:
            bme.faces.new((v23, v3, v4, v24))
            bottomVerts = []

        # add supports
        if detail in ("MEDIUM", "HIGH") and min(adjustedBrickSize[:2]) == 2:
            addOblongSupport(
                dimensions, height, loopCut, circleVerts, "SLOPE_INVERTED",
                detail, d, scalar, thick, bme
            )  # [v27] + bottomVerts + [v26], [v28, v25], [v27, v28], [v26, v25], bme)

        # add small inner cylinders inside brick
        if detail in ("MEDIUM", "HIGH"):
            addInnerCylinders(
                dimensions,
                [1, min(adjustedBrickSize[:2]), adjustedBrickSize[2]],
                circleVerts,
                d, [v27] + bottomVerts + [v26], [v28, v25], [v27, v28],
                [v26, v25],
                bme,
                loopCut=loopCut)

        # add half-cylinder insets on slope underside
        if detail in ("MEDIUM", "HIGH") and max(adjustedBrickSize[:2]) == 3:
            # TODO: Rewrite this as dedicated function
            # TODO: Add loopCut functionality for half-cylinder insets
            addSlopeStuds(
                dimensions,
                height,
                [2, min(adjustedBrickSize[:2]), adjustedBrickSize[2]],
                brickType,
                circleVerts,
                bme,
                edgeXp=[v3, v4],
                edgeXn=[v9, v10],
                edgeYp=[v4, v9],
                edgeYn=[v10, v3],
                underside=True,
                loopCut=loopCut)

    # translate slope to adjust for flipped brick
    for v in bme.verts:
        v.co.y -= d.y * (scalar.y - 1) if direction in ("X-", "Y+") else 0
        v.co.x -= d.x * (scalar.x - 1) if direction in ("X-", "Y-") else 0
    # rotate slope to the appropriate orientation
    mult = directions.index(direction)
    bmesh.ops.rotate(bme,
                     verts=bme.verts,
                     cent=(0, 0, 0),
                     matrix=Matrix.Rotation(math.radians(90) * mult, 3, 'Z'))

    return bme
예제 #45
0
def draw_callback1_px(self, context):

    # Getting the first object and face that raycast hits:
    mode = self.mode
    np_print('mode:', mode)
    region = self.region
    np_print('region', region)
    rv3d = self.rv3d
    np_print('rv3d', rv3d)
    co2d = self.co2d
    np_print('self.co2d', co2d)
    co3d = 1
    center = Vector((0, 0, 0))
    normal = Vector((0.0, 0.0, 1.0))
    scenecast = scene_cast(region, rv3d, co2d)
    np_print('scenecast', scenecast)
    hitob = scenecast[4]
    np_print('hitob', hitob)

    if mode == 0:
        instruct = 'paint material on object / objects'

    elif mode == 1:
        instruct = 'pick material to paint with'

    elif mode == 2:
        instruct = 'pick material to paint with'

    elif mode == 3:
        instruct = 'paint material on single face'

    elif mode == 4:
        instruct = 'paint material on object / objects'
        if hitob is not None:
            acob = bpy.context.view_layer.objects.active
            bpy.context.view_layer.objects.active = hitob
            slots = hitob.material_slots
            for i, s in enumerate(slots):
                hitob.active_material_index = i
                bpy.ops.object.material_slot_remove()
            if self.shader is not None:
                hitob.data.materials.append(self.shader)
            np_print(hitob.select)
            if hitob.select_get() is True:
                np_print('true')
                for ob in self.selob:
                    bpy.context.view_layer.objects.active = ob
                    slots = ob.material_slots
                    for i, s in enumerate(slots):
                        ob.active_material_index = i
                        bpy.ops.object.material_slot_remove()
                    if self.shader is not None:
                        ob.data.materials.append(self.shader)
            bpy.context.view_layer.objects.active = acob
            #bpy.context.scene.update()
            np_print('040')

    elif mode == 5:
        instruct = 'pick material to paint with'
        if hitob is not None:
            mat = None
            findex = scenecast[3]
            np_print('findex', findex)
            me = hitob.data
            np_print('me', me)
            bme = bmesh.new()
            bme.from_mesh(me)
            bme.faces.ensure_lookup_table()
            np_print('faces', bme.faces)
            np_print('face', bme.faces[findex])
            bmeface = bme.faces[findex]
            matindex = bmeface.material_index
            np_print('material_index', matindex)
            slots = list(hitob.material_slots)
            np_print('slots', slots)
            np_print('len slots', len(slots))
            np_print('slots', slots)
            if len(slots) == 0:
                self.shader = None
                self.shadername = 'None'
            elif slots[matindex].material is not None:
                self.shader = slots[matindex].material
                self.shadername = slots[matindex].material.name
            else:
                self.shader = None
                self.shadername = 'None'
            bpy.context.view_layer.objects.active = hitob
            hitob.active_material_index = matindex
            np_print('self.shader', self.shader)
            np_print('050')
        else:
            self.shader = None
            self.shadername = 'None'

    elif mode == 6:
        instruct = 'pick material to paint with'

    elif mode == 7:
        instruct = 'paint material on single face'
        if hitob is not None:
            acob = bpy.context.view_layer.objects.active
            bpy.context.view_layer.objects.active = hitob
            findex = scenecast[3]
            np_print('findex', findex)
            me = hitob.data
            np_print('me', me)
            bpy.ops.object.mode_set(mode='EDIT')
            bme = bmesh.from_edit_mesh(me)
            bme.faces.ensure_lookup_table()
            np_print('faces', bme.faces)
            np_print('face', bme.faces[findex])
            bmeface = bme.faces[findex]
            slots = list(hitob.material_slots)
            np_print('slots', list(slots))
            m = 0
            if list(slots) == []:
                hitob.data.materials.append(None)
            slots = list(hitob.material_slots)
            for i, s in enumerate(slots):
                np_print('s', s)
                if s.name == self.shadername:
                    m = 1
                    matindex = i
                elif s.material == None and self.shader == None:
                    m = 1
                    matindex = i
            if m == 0:
                hitob.data.materials.append(self.shader)
                matindex = len(slots) - 1
            hitob.active_material_index = matindex
            bpy.context.tool_settings.mesh_select_mode = False, False, True
            bpy.ops.mesh.select_all(action='DESELECT')
            bmeface.select = True
            bmesh.update_edit_mesh(me, True)
            bpy.ops.object.material_slot_assign()
            bpy.ops.mesh.select_all(action='DESELECT')
            bpy.ops.object.mode_set(mode='OBJECT')
            bpy.context.view_layer.objects.active = acob

    # ON-SCREEN INSTRUCTIONS:

    keys_aff = 'LMB - paint object / objects, CTRL - take material, ALT - paint single face'
    keys_nav = 'MMB, SCROLL - navigate'
    keys_neg = 'ESC - quit'

    display_instructions(region, rv3d, instruct, keys_aff, keys_nav, keys_neg)

    col_bg_fill_main_run = addon_settings_graph('col_bg_fill_main_run')
    col_bg_fill_main_nav = addon_settings_graph('col_bg_fill_main_nav')

    # Drawing the small icon near the cursor and the shader name:
    # First color is for lighter themes, second for default and darker themes:
    if mode in {1, 2, 5, 6}:
        square = [[17, 30], [17, 39], [26, 39], [26, 30]]
        cur = [[17, 36], [18, 35], [14, 31], [14, 30], [15, 30], [19, 34],
               [18, 35], [20, 37], [21, 37], [21, 36], [19, 34], [20, 33]]
        curpipe = [[18, 35], [14, 31], [14, 30], [15, 30], [19, 34], [18, 35]]
        curcap = [[18, 35], [20, 37], [21, 37], [21, 36], [19, 34], [18, 35]]
        scale = 2.8
        col_square = col_bg_fill_main_run
        for co in square:
            co[0] = round((co[0] * scale), 0) - 35 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 88 + co2d[1]
        for co in cur:
            co[0] = round((co[0] * scale), 0) - 25 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 86 + co2d[1]
        for co in curcap:
            co[0] = round((co[0] * scale), 0) - 25 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 86 + co2d[1]
        for co in curpipe:
            co[0] = round((co[0] * scale), 0) - 25 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 86 + co2d[1]
        bgl.glColor4f(*col_square)
        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
        for x, y in square:
            bgl.glVertex2f(x, y)
        bgl.glEnd()
        #bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
        bgl.glColor4f(1.0, 1.0, 1.0, 0.8)
        bgl.glBegin(bgl.GL_LINE_STRIP)
        for x, y in cur:
            bgl.glVertex2f(x, y)
        bgl.glEnd()
        if mode in {2, 6}:
            bgl.glColor4f(1.0, 0.5, 0.5, 1.0)
        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
        for x, y in curcap:
            bgl.glVertex2f(x, y)
        bgl.glEnd()

    else:
        square = [[17, 30], [17, 39], [26, 39], [26, 30]]
        cur = [[18, 30], [21, 33], [18, 36], [14, 32], [16, 32], [18, 30]]
        curtip = [[14, 32], [16, 32], [15, 33], [14, 32]]
        curbag = [[18, 30], [15, 33], [21, 33], [18, 30]]
        scale = 2.8
        if mode in (3, 7): col_square = col_bg_fill_main_nav
        else: col_square = (0.25, 0.35, 0.4, 0.87)
        for co in square:
            co[0] = round((co[0] * scale), 0) - 35 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 88 + co2d[1]
        for co in cur:
            co[0] = round((co[0] * scale), 0) - 25 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 84 + co2d[1]
        for co in curtip:
            co[0] = round((co[0] * scale), 0) - 25 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 84 + co2d[1]
        for co in curbag:
            co[0] = round((co[0] * scale), 0) - 25 + co2d[0]
            co[1] = round((co[1] * scale), 0) - 84 + co2d[1]
        bgl.glColor4f(*col_square)
        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
        for x, y in square:
            bgl.glVertex2f(x, y)
        bgl.glEnd()
        #bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
        bgl.glColor4f(1.0, 1.0, 1.0, 0.8)
        bgl.glBegin(bgl.GL_LINE_STRIP)
        for x, y in cur:
            bgl.glVertex2f(x, y)
        bgl.glEnd()
        '''
        if mode in {3, 7}:
            bgl.glBegin(bgl.GL_TRIANGLE_FAN)
            for x,y in curtip:
                bgl.glVertex2f(x,y)
            bgl.glEnd()
            bgl.glLineWidth(2)
            bgl.glBegin(bgl.GL_LINE_STRIP)
            for x,y in curtip:
                bgl.glVertex2f(x,y)
            bgl.glEnd()
            bgl.glLineWidth(1)
        '''
        if self.shader is not None:
            bgl.glBegin(bgl.GL_TRIANGLE_FAN)
            for x, y in curbag:
                bgl.glVertex2f(x, y)
            bgl.glEnd()

    bgl.glColor4f(0.25, 0.35, 0.4, 0.87)
    font_id = 0
    blf.size(font_id, 15, 72)
    blf.position(font_id, co2d[0] + 47, co2d[1] - 3, 0)
    blf.draw(font_id, self.shadername)

    bgl.glColor4f(1.0, 1.0, 1.0, 0.8)
    font_id = 0
    blf.size(font_id, 15, 72)
    blf.position(font_id, co2d[0] + 46, co2d[1] - 2, 0)
    blf.draw(font_id, self.shadername)

    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
예제 #46
0
    def execute(self, context):

        #Set cursor representation to 'loading' icon
        w = context.window
        w.cursor_set('WAIT')
        t0 = time.clock()

        #Toogle object mode and deselect all
        try:
            bpy.ops.object.mode_set(mode='OBJECT')
        except:
            pass

        bpy.ops.object.select_all(action='DESELECT')

        #Path
        shpName = os.path.basename(self.filepath)[:-4]

        #Get shp reader
        print("Read shapefile...")
        try:
            shp = shpReader(self.filepath)
        except:
            self.report({'ERROR'}, "Unable to read shapefile")
            return {'FINISHED'}

        #Check shape type
        shpType = featureType[shp.shapeType]
        print('Feature type : ' + shpType)
        if shpType not in [
                'Point', 'PolyLine', 'Polygon', 'PointZ', 'PolyLineZ',
                'PolygonZ'
        ]:
            self.report({
                'ERROR'
            }, "Cannot process multipoint, multipointZ, pointM, polylineM, polygonM and multipatch feature type"
                        )
            return {'FINISHED'}

        #Get fields
        fields = [field for field in shp.fields if field[0] != 'DeletionFlag'
                  ]  #ignore default DeletionFlag field
        fieldsNames = [field[0] for field in fields]
        #print("DBF fields : "+str(fieldsNames))

        if self.fieldElevName or (self.fieldObjName and self.separateObjects
                                  ) or self.fieldExtrudeName:
            self.useDbf = True
        else:
            self.useDbf = False

        if self.fieldObjName and self.separateObjects:
            try:
                nameFieldIdx = fieldsNames.index(self.fieldObjName)
            except:
                self.report({'ERROR'}, "Unable to find name field")
                return {'FINISHED'}

        if self.fieldElevName:
            try:
                zFieldIdx = fieldsNames.index(self.fieldElevName)
            except:
                self.report({'ERROR'}, "Unable to find elevation field")
                return {'FINISHED'}

            if fields[zFieldIdx][1] not in ['N', 'F', 'L']:
                self.report({'ERROR'},
                            "Elevation field do not contains numeric values")
                return {'FINISHED'}

        if self.fieldExtrudeName:
            try:
                extrudeFieldIdx = fieldsNames.index(self.fieldExtrudeName)
            except ValueError:
                self.report({'ERROR'}, "Unable to find extrusion field")
                return {'FINISHED'}

            if fields[extrudeFieldIdx][1] not in ['N', 'F', 'L']:
                self.report({'ERROR'},
                            "Extrusion field do not contains numeric values")
                return {'FINISHED'}

        #Get shp and scene georef infos
        shpCRS = self.shpCRS
        geoscn = GeoScene()
        if geoscn.isBroken:
            self.report({'ERROR'},
                        "Scene georef is broken, please fix it beforehand")
            return {'FINISHED'}
        scale = geoscn.scale  #TODO
        if not geoscn.hasCRS:
            try:
                geoscn.crs = shpCRS
            except Exception as e:
                self.report({'ERROR'}, str(e))
                return {'FINISHED'}

        #Init reprojector class
        if geoscn.crs != shpCRS:
            print("Data will be reprojected from " + shpCRS + " to " +
                  geoscn.crs)
            try:
                rprj = Reproj(shpCRS, geoscn.crs)
            except Exception as e:
                self.report({'ERROR'}, "Unable to reproject data. " + str(e))
                return {'FINISHED'}
            if rprj.iproj == 'EPSGIO':
                if shp.numRecords > 100:
                    self.report({
                        'ERROR'
                    }, "Reprojection through online epsg.io engine is limited to 100 features. \nPlease install GDAL or pyproj module."
                                )
                    return {'FINISHED'}

        #Get bbox
        bbox = BBOX(shp.bbox)
        if geoscn.crs != shpCRS:
            bbox = rprj.bbox(bbox)

        #Get or set georef dx, dy
        if not geoscn.isGeoref:
            dx, dy = bbox.center
            geoscn.setOriginPrj(dx, dy)
        else:
            dx, dy = geoscn.getOriginPrj()

        #Tag if z will be extracted from shp geoms
        if shpType[-1] == 'Z' and not self.fieldElevName:
            self.useZGeom = True
        else:
            self.useZGeom = False

        #Get reader iterator (using iterator avoids loading all data in memory)
        #warn, shp with zero field will return an empty shapeRecords() iterator
        #to prevent this issue, iter only on shapes if there is no field required
        if self.useDbf:
            #Note: using shapeRecord solve the issue where number of shapes does not match number of table records
            #because it iter only on features with geom and record
            shpIter = shp.iterShapeRecords()
        else:
            shpIter = shp.iterShapes()
        nbFeats = shp.numRecords

        #Create an empty BMesh
        bm = bmesh.new()
        #Extrusion is exponentially slow with large bmesh
        #it's fastest to extrude a small bmesh and then join it to a final large bmesh
        if not self.separateObjects and self.fieldExtrudeName:
            finalBm = bmesh.new()

        progress = -1

        #Main iteration over features
        for i, feat in enumerate(shpIter):

            if self.useDbf:
                shape = feat.shape
                record = feat.record
            else:
                shape = feat

            #Progress infos
            pourcent = round(((i + 1) * 100) / nbFeats)
            if pourcent in list(range(0, 110, 10)) and pourcent != progress:
                progress = pourcent
                if pourcent == 100:
                    print(str(pourcent) + '%')
                else:
                    print(str(pourcent), end="%, ")
                sys.stdout.flush(
                )  #we need to flush or it won't print anything until after the loop has finished

            #Deal with multipart features
            #If the shape record has multiple parts, the 'parts' attribute will contains the index of
            #the first point of each part. If there is only one part then a list containing 0 is returned
            if (shpType == 'PointZ' or shpType
                    == 'Point'):  #point layer has no attribute 'parts'
                partsIdx = [0]
            else:
                try:  #prevent "_shape object has no attribute parts" error
                    partsIdx = shape.parts
                except:
                    partsIdx = [0]
            nbParts = len(partsIdx)

            #Get list of shape's points
            pts = shape.points
            nbPts = len(pts)

            #Skip null geom
            if nbPts == 0:
                continue  #go to next iteration of the loop

            #Reproj geom
            if geoscn.crs != shpCRS:
                pts = rprj.pts(pts)

            #Get extrusion offset
            if self.fieldExtrudeName:
                try:
                    offset = float(record[extrudeFieldIdx])
                except:
                    offset = 0  #null values will be set to zero

            #Iter over parts
            for j in range(nbParts):

                # EXTRACT 3D GEOM

                geom = []  #will contains a list of 3d points

                #Find first and last part index
                idx1 = partsIdx[j]
                if j + 1 == nbParts:
                    idx2 = nbPts
                else:
                    idx2 = partsIdx[j + 1]

                #Build 3d geom
                for k, pt in enumerate(pts[idx1:idx2]):
                    if self.fieldElevName:
                        try:
                            z = float(record[zFieldIdx])
                        except:
                            z = 0  #null values will be set to zero
                    elif self.useZGeom:
                        z = shape.z[idx1:idx2][k]
                    else:
                        z = 0
                    geom.append((pt[0], pt[1], z))

                #Shift coords
                geom = [(pt[0] - dx, pt[1] - dy, pt[2]) for pt in geom]

                # BUILD BMESH

                # POINTS
                if (shpType == 'PointZ' or shpType == 'Point'):
                    vert = [bm.verts.new(pt) for pt in geom]
                    #Extrusion
                    if self.fieldExtrudeName and offset > 0:
                        vect = (0, 0, offset)  #along Z
                        result = bmesh.ops.extrude_vert_indiv(bm, verts=vert)
                        verts = result['verts']
                        bmesh.ops.translate(bm, verts=verts, vec=vect)

                # LINES
                if (shpType == 'PolyLine' or shpType == 'PolyLineZ'):
                    #Split polyline to lines
                    n = len(geom)
                    lines = [(geom[i], geom[i + 1]) for i in range(n)
                             if i < n - 1]
                    #Build edges
                    edges = []
                    for line in lines:
                        verts = [bm.verts.new(pt) for pt in line]
                        edge = bm.edges.new(verts)
                        edges.append(edge)
                    #Extrusion
                    if self.fieldExtrudeName and offset > 0:
                        vect = (0, 0, offset)  # along Z
                        result = bmesh.ops.extrude_edge_only(bm, edges=edges)
                        verts = [
                            elem for elem in result['geom']
                            if isinstance(elem, bmesh.types.BMVert)
                        ]
                        bmesh.ops.translate(bm, verts=verts, vec=vect)

                # NGONS
                if (shpType == 'Polygon' or shpType == 'PolygonZ'):
                    #According to the shapefile spec, polygons points are clockwise and polygon holes are counterclockwise
                    #in Blender face is up if points are in anticlockwise order
                    geom.reverse()  #face up
                    geom.pop(
                    )  #exlude last point because it's the same as first pt
                    if len(geom) >= 3:  #needs 3 points to get a valid face
                        verts = [bm.verts.new(pt) for pt in geom]
                        face = bm.faces.new(verts)
                        #update normal to avoid null vector
                        face.normal_update()
                        if face.normal.z < 0:  #this is a polygon hole, bmesh cannot handle polygon hole
                            pass  #TODO
                        #Extrusion
                        if self.fieldExtrudeName and offset > 0:
                            #build translate vector
                            if self.extrusionAxis == 'NORMAL':
                                normal = face.normal
                                vect = normal * offset
                            elif self.extrusionAxis == 'Z':
                                vect = (0, 0, offset)
                            faces = bmesh.ops.extrude_discrete_faces(
                                bm, faces=[face])  #return {'faces': [BMFace]}
                            verts = faces['faces'][0].verts
                            ##result = bmesh.ops.extrude_face_region(bm, geom=[face]) #return dict {"geom":[BMVert, BMEdge, BMFace]}
                            ##verts = [elem for elem in result['geom'] if isinstance(elem, bmesh.types.BMVert)] #geom type filter
                            bmesh.ops.translate(bm, verts=verts, vec=vect)

            if self.separateObjects:

                if self.fieldObjName:
                    try:
                        name = record[nameFieldIdx]
                    except:
                        name = ''
                    # null values will return a bytes object containing a blank string of length equal to fields length definition
                    if isinstance(name, bytes):
                        name = ''
                    else:
                        name = str(name)
                else:
                    name = shpName

                #Calc bmesh bbox
                _bbox = BBOX.fromBmesh(bm)

                #Calc bmesh geometry origin and translate coords according to it
                #then object location will be set to initial bmesh origin
                #its a work around to bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
                ox, oy, oz = _bbox.center
                oz = _bbox.zmin
                bmesh.ops.translate(bm, verts=bm.verts, vec=(-ox, -oy, -oz))

                #Create new mesh from bmesh
                mesh = bpy.data.meshes.new(name)
                bm.to_mesh(mesh)
                bm.clear()

                #Validate new mesh
                mesh.validate(verbose=False)

                #Place obj
                obj = bpy.data.objects.new(name, mesh)
                context.scene.objects.link(obj)
                context.scene.objects.active = obj
                obj.select = True
                obj.location = (ox, oy, oz)

                # bpy operators can be very cumbersome when scene contains lot of objects
                # because it cause implicit scene updates calls
                # so we must avoid using operators when created many objects with the 'separate objects' option)
                ##bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')

            elif self.fieldExtrudeName:
                #Join to final bmesh (use from_mesh method hack)
                buff = bpy.data.meshes.new(".temp")
                bm.to_mesh(buff)
                finalBm.from_mesh(buff)
                bpy.data.meshes.remove(buff)
                bm.clear()

        #Write back the whole mesh
        if not self.separateObjects:

            mesh = bpy.data.meshes.new(shpName)

            if self.fieldExtrudeName:
                bm.free()
                bm = finalBm

            bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
            bm.to_mesh(mesh)

            #Finish
            #mesh.update(calc_edges=True)
            mesh.validate(
                verbose=False)  #return true if the mesh has been corrected
            obj = bpy.data.objects.new(shpName, mesh)
            context.scene.objects.link(obj)
            context.scene.objects.active = obj
            obj.select = True
            bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')

        #free the bmesh
        bm.free()

        t = time.clock() - t0
        print('Build in %f seconds' % t)

        #Adjust grid size
        bbox.shift(-dx, -dy)  #convert shapefile bbox in 3d view space
        adjust3Dview(context, bbox)

        return {'FINISHED'}
예제 #47
0
def cell_fracture_objects(context, collection, obj,
                          source={'PARTICLE_OWN'},
                          source_limit=0,
                          source_noise=0.0,
                          clean=True,
                          # operator options
                          use_smooth_faces=False,
                          use_data_match=False,
                          use_debug_points=False,
                          margin=0.0,
                          material_index=0,
                          use_debug_redraw=False,
                          cell_scale=(1.0, 1.0, 1.0),
                          ):

    from . import fracture_cell_calc
    depsgraph = context.evaluated_depsgraph_get()
    scene = context.scene
    view_layer = context.view_layer

    # -------------------------------------------------------------------------
    # GET POINTS

    points = _points_from_object(depsgraph, scene, obj, source)

    if not points:
        # print using fallback
        points = _points_from_object(depsgraph, scene, obj, {'VERT_OWN'})

    if not points:
        print("no points found")
        return []

    # apply optional clamp
    if source_limit != 0 and source_limit < len(points):
        import random
        random.shuffle(points)
        points[source_limit:] = []

    # saddly we cant be sure there are no doubles
    from mathutils import Vector
    to_tuple = Vector.to_tuple
    points = list({to_tuple(p, 4): p for p in points}.values())
    del to_tuple
    del Vector

    # end remove doubles
    # ------------------

    if source_noise > 0.0:
        from random import random
        # boundbox approx of overall scale
        from mathutils import Vector
        matrix = obj.matrix_world.copy()
        bb_world = [matrix @ Vector(v) for v in obj.bound_box]
        scalar = source_noise * ((bb_world[0] - bb_world[6]).length / 2.0)

        from mathutils.noise import random_unit_vector

        points[:] = [p + (random_unit_vector() * (scalar * random())) for p in points]

    if use_debug_points:
        bm = bmesh.new()
        for p in points:
            bm.verts.new(p)
        mesh_tmp = bpy.data.meshes.new(name="DebugPoints")
        bm.to_mesh(mesh_tmp)
        bm.free()
        obj_tmp = bpy.data.objects.new(name=mesh_tmp.name, object_data=mesh_tmp)
        collection.objects.link(obj_tmp)
        del obj_tmp, mesh_tmp

    mesh = obj.data
    matrix = obj.matrix_world.copy()
    verts = [matrix @ v.co for v in mesh.vertices]

    cells = fracture_cell_calc.points_as_bmesh_cells(verts,
                                                     points,
                                                     cell_scale,
                                                     margin_cell=margin)

    # some hacks here :S
    cell_name = obj.name + "_cell"

    objects = []

    for center_point, cell_points in cells:

        # ---------------------------------------------------------------------
        # BMESH

        # create the convex hulls
        bm = bmesh.new()

        # WORKAROUND FOR CONVEX HULL BUG/LIMIT
        # XXX small noise
        import random
        def R():
            return (random.random() - 0.5) * 0.001
        # XXX small noise

        for i, co in enumerate(cell_points):

            # XXX small noise
            co.x += R()
            co.y += R()
            co.z += R()
            # XXX small noise

            bm_vert = bm.verts.new(co)

        import mathutils
        bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005)
        try:
            bmesh.ops.convex_hull(bm, input=bm.verts)
        except RuntimeError:
            import traceback
            traceback.print_exc()

        if clean:
            bm.normal_update()
            try:
                bmesh.ops.dissolve_limit(bm, verts=bm.verts, angle_limit=0.001)
            except RuntimeError:
                import traceback
                traceback.print_exc()
        # Smooth faces will remain only inner faces, after applying boolean modifier.
        if use_smooth_faces:
            for bm_face in bm.faces:
                bm_face.smooth = True

        if material_index != 0:
            for bm_face in bm.faces:
                bm_face.material_index = material_index


        # ---------------------------------------------------------------------
        # MESH
        mesh_dst = bpy.data.meshes.new(name=cell_name)

        bm.to_mesh(mesh_dst)
        bm.free()
        del bm

        if use_data_match:
            # match materials and data layers so boolean displays them
            # currently only materials + data layers, could do others...
            mesh_src = obj.data
            for mat in mesh_src.materials:
                mesh_dst.materials.append(mat)
            for lay_attr in ("vertex_colors", "uv_layers"):
                lay_src = getattr(mesh_src, lay_attr)
                lay_dst = getattr(mesh_dst, lay_attr)
                for key in lay_src.keys():
                    lay_dst.new(name=key)

        # ---------------------------------------------------------------------
        # OBJECT

        obj_cell = bpy.data.objects.new(name=cell_name, object_data=mesh_dst)
        collection.objects.link(obj_cell)
        # scene.objects.active = obj_cell
        obj_cell.location = center_point

        objects.append(obj_cell)

        # support for object materials
        if use_data_match:
            for i in range(len(mesh_dst.materials)):
                slot_src = obj.material_slots[i]
                slot_dst = obj_cell.material_slots[i]

                slot_dst.link = slot_src.link
                slot_dst.material = slot_src.material

        if use_debug_redraw:
            view_layer.update()
            _redraw_yasiamevil()

    view_layer.update()

    return objects
예제 #48
0
def scene_to_ge1(context, scene):  # TODO use BMesh
    """Export scene geometry in FDS GE1 notation."""
    # Cursor
    w = context.window_manager.windows[0]
    w.cursor_modal_set("WAIT")
    # Get GE1 appearances from materials
    appearances = list()
    ma_to_appearance = dict()
    for index, ma in enumerate(bpy.data.materials):
        ma_to_appearance[ma.name] = index
        appearances.append(
            "{desc}\n{i} {r} {g} {b} 0. 0. {alpha:.3f} 0. 0. 0.\n\n".format(
                desc=ma.name,
                i=index,
                r=int(ma.diffuse_color[0] * 255),
                g=int(ma.diffuse_color[1] * 255),
                b=int(ma.diffuse_color[2] * 255),
                alpha=0.0,  # FIXME alpha=ma.alpha,
            ))
    # Append dummy material for holes: BF_HOLE
    ma_to_appearance["BF_HOLE"] = index + 1
    appearances.append(
        "{desc}\n{i} {r} {g} {b} 0. 0. {alpha:.3f} 0. 0. 0.\n\n".format(
            desc="BF_HOLE", i=index + 1, r=150, g=150, b=150, alpha=0.5))
    # Select GE1 objects
    obs = (
        ob for ob in context.scene.objects if ob.type == "MESH"
        and not ob.hide_render  # hide some objects if requested
        and not ob.bf_is_tmp  # do not show temporary objects
        and ob.bf_export  # show only exported objects
        and ob.bf_namelist_cls in ("ON_OBST", "ON_GEOM", "ON_VENT",
                                   "ON_HOLE")  # show only some namelists
        and getattr(ob.active_material, "name",
                    None) != "OPEN"  # do not show open VENTs
    )
    # Get GE1 faces from selected objects
    gefaces = list()
    for ob in obs:
        # Get the new bmesh from the Object, apply modifiers, set in world coordinates, and triangulate
        bm = bmesh.new()
        bm.from_object(ob,
                       context.scene,
                       deform=True,
                       render=False,
                       cage=False,
                       face_normals=True)
        bm.transform(ob.matrix_world)
        bmesh.ops.triangulate(bm, faces=bm.faces)
        # Get ob material_slots
        material_slots = ob.material_slots
        # Get default_material_name
        if ob.bf_namelist_cls == "ON_HOLE":
            default_material_name = "BF_HOLE"
        elif ob.bf_namelist_cls == "ON_GEOM":
            default_material_name = None
        elif ob.active_material:
            default_material_name = ob.active_material.name
        else:
            default_material_name = "INERT"
        scale_length = context.scene.unit_settings.scale_length
        for f in bm.faces:
            # Grab ordered vertices coordinates
            coos = [co for v in f.verts for co in v.co]
            coos.extend((coos[-3], coos[-2], coos[-1]))  # tri to quad
            items = ["{:.6f}".format(coo * scale_length) for coo in coos]
            # Get appearance_index
            if default_material_name:
                material_name = default_material_name
            else:
                material_name = material_slots[f.material_index].material.name
            appearance_index = str(ma_to_appearance.get(material_name,
                                                        0)) + "\n"
            items.append(appearance_index)
            # Append GE1 face
            gefaces.append(" ".join(items))

    # Prepare GE1 file and return
    ge1_file_a = "[APPEARANCE]\n{}\n{}".format(len(appearances),
                                               "".join(appearances))
    ge1_file_f = "[FACES]\n{}\n{}".format(len(gefaces), "".join(gefaces))
    w.cursor_modal_restore()
    return "".join((ge1_file_a, ge1_file_f))
예제 #49
0
def cell_boolean(context,
                 original,
                 cells,
                 use_debug_bool=False,
                 clean=True,
                 use_island_split=False,
                 use_interior_hide=False,
                 use_debug_redraw=False,
                 level=0,
                 remove_doubles=True):

    cells_boolean = []
    collection = context.collection
    scene = context.scene
    view_layer = context.view_layer

    if use_interior_hide and level == 0:
        # only set for level 0
        original.data.polygons.foreach_set("hide", [False] *
                                           len(original.data.polygons))

    # The first object can't be applied by bool, so it is used as a no-effect first straw-man.
    bpy.ops.mesh.primitive_cube_add(enter_editmode=False,
                                    location=(original.location.x +
                                              10000000000.0, 0, 0))
    temp_cell = bpy.context.active_object
    cells.insert(0, temp_cell)

    bpy.ops.object.select_all(action='DESELECT')
    for i, cell in enumerate(cells):
        mod = cell.modifiers.new(name="Boolean", type='BOOLEAN')
        mod.object = original
        mod.operation = 'INTERSECT'

        if not use_debug_bool:
            if use_interior_hide:
                cell.data.polygons.foreach_set("hide", [True] *
                                               len(cell.data.polygons))

            # mesh_old should be made before appling boolean modifier.
            mesh_old = cell.data

            original.select_set(True)
            cell.select_set(True)
            bpy.context.view_layer.objects.active = cell
            bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")

            if i == 0:
                bpy.data.objects.remove(cell, do_unlink=True)
                continue

            cell = bpy.context.active_object
            cell.select_set(False)

            # depsgraph sould be gotten after applied boolean modifier, for new_mesh.
            depsgraph = context.evaluated_depsgraph_get()
            cell_eval = cell.evaluated_get(depsgraph)

            mesh_new = bpy.data.meshes.new_from_object(cell_eval)
            cell.data = mesh_new
            '''
            check_hide = [11] * len(cell.data.polygons)
            cell.data.polygons.foreach_get("hide", check_hide)
            print(check_hide) 
            '''

            # remove if not valid
            if not mesh_old.users:
                bpy.data.meshes.remove(mesh_old)
            if not mesh_new.vertices:
                collection.objects.unlink(cell)
                if not cell.users:
                    bpy.data.objects.remove(cell)
                    cell = None
                    if not mesh_new.users:
                        bpy.data.meshes.remove(mesh_new)
                        mesh_new = None

            # avoid unneeded bmesh re-conversion
            if mesh_new is not None:
                bm = None

                if clean:
                    if bm is None:  # ok this will always be true for now...
                        bm = bmesh.new()
                        bm.from_mesh(mesh_new)
                    bm.normal_update()
                    try:
                        bmesh.ops.dissolve_limit(bm,
                                                 verts=bm.verts,
                                                 edges=bm.edges,
                                                 angle_limit=0.001)
                    except RuntimeError:
                        import traceback
                        traceback.print_exc()

                if remove_doubles:
                    if bm is None:
                        bm = bmesh.new()
                        bm.from_mesh(mesh_new)
                    bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005)

                if bm is not None:
                    bm.to_mesh(mesh_new)
                    bm.free()

            del mesh_new
            del mesh_old

        if cell is not None:
            cells_boolean.append(cell)

            if use_debug_redraw:
                _redraw_yasiamevil()

    bpy.context.view_layer.objects.active = original

    if (not use_debug_bool) and use_island_split:
        # this is ugly and Im not proud of this - campbell
        for ob in view_layer.objects:
            ob.select_set(False)
        for cell in cells_boolean:
            cell.select_set(True)
        # If new separated meshes are made, selected objects is increased.
        if cells_boolean:
            bpy.ops.mesh.separate(type='LOOSE')

        cells_boolean[:] = [
            cell for cell in scene.objects if cell.select_get()
        ]

    context.view_layer.update()
    return cells_boolean
예제 #50
0
    def import_gnd(filepath, options: GndImportOptions):
        gnd = GndReader.from_file(filepath)
        name = os.path.splitext(os.path.basename(filepath))[0]
        directory_name = os.path.dirname(filepath)

        mesh = bpy.data.meshes.new(name)
        mesh_object = bpy.data.objects.new(name, mesh)

        if options.should_import_lightmaps:
            '''
            Generate light map image.
            '''
            lightmap_size = int(
                math.ceil(math.sqrt(len(gnd.lightmaps) * 64) / 8) * 8)
            lightmap_tiles_per_dimension = lightmap_size / 8
            pixel_count = lightmap_size * lightmap_size
            pixels = [0.0] * (pixel_count * 4)
            for i, lightmap in enumerate(gnd.lightmaps):
                x, y = int(i % lightmap_tiles_per_dimension) * 8, int(
                    i / lightmap_tiles_per_dimension) * 8
                for y2 in range(8):
                    for x2 in range(8):
                        idx = y2 * 8 + x2
                        lum = lightmap.luminosity[idx]
                        j = int(((y + y2) * lightmap_size) + (x + x2)) * 4
                        r = lum / 255.0
                        pixels[j + 0] = r
                        pixels[j + 1] = r
                        pixels[j + 2] = r
                        pixels[j + 3] = 1.0
            lightmap_image = bpy.data.images.new('lightmap', lightmap_size,
                                                 lightmap_size)
            lightmap_image.pixels = pixels
            ''' Create light map texture. '''
            lightmap_texture = bpy.data.textures.new('lightmap', type='IMAGE')
            lightmap_texture.image = lightmap_image
        ''' Create materials. '''
        materials = []
        for i, texture in enumerate(gnd.textures):
            texture_path = texture.path
            material = bpy.data.materials.new(texture_path)
            material.diffuse_intensity = 1.0
            material.specular_intensity = 0.0
            materials.append(material)
            ''' Load diffuse texture. '''
            diffuse_texture = bpy.data.textures.new(texture_path, type='IMAGE')
            data_path = get_data_path(directory_name)
            texpath = os.path.join(data_path, 'texture', texture_path)
            try:
                diffuse_texture.image = bpy.data.images.load(
                    texpath, check_existing=True)
            except RuntimeError:
                pass
            ''' Add diffuse texture slot to material. '''
            diffuse_texture_slot = material.texture_slots.add()
            diffuse_texture_slot.texture = diffuse_texture

            if options.should_import_lightmaps:
                ''' Add light map texture slot to material.'''
                lightmap_texture_slot = material.texture_slots.add()
                lightmap_texture_slot.texture = lightmap_texture
                lightmap_texture_slot.diffuse_color_factor = options.lightmap_factor
                lightmap_texture_slot.blend_type = 'MULTIPLY'

        bm = bmesh.new()
        bm.from_mesh(mesh)

        for y in range(gnd.height):
            for x in range(gnd.width):
                tile_index = y * gnd.width + x
                tile = gnd.tiles[tile_index]
                if tile.face_indices[0] != -1:  # +Z
                    bm.verts.new(
                        ((x + 0) * gnd.scale, (y + 0) * gnd.scale, -tile[0]))
                    bm.verts.new(
                        ((x + 1) * gnd.scale, (y + 0) * gnd.scale, -tile[1]))
                    bm.verts.new(
                        ((x + 1) * gnd.scale, (y + 1) * gnd.scale, -tile[3]))
                    bm.verts.new(
                        ((x + 0) * gnd.scale, (y + 1) * gnd.scale, -tile[2]))
                if tile.face_indices[1] != -1:  # +Y
                    adjacent_tile = gnd.tiles[tile_index + gnd.width]
                    bm.verts.new(
                        ((x + 0) * gnd.scale, (y + 1) * gnd.scale, -tile[2]))
                    bm.verts.new(
                        ((x + 1) * gnd.scale, (y + 1) * gnd.scale, -tile[3]))
                    bm.verts.new(((x + 1) * gnd.scale, (y + 1) * gnd.scale,
                                  -adjacent_tile[1]))
                    bm.verts.new(((x + 0) * gnd.scale, (y + 1) * gnd.scale,
                                  -adjacent_tile[0]))
                if tile.face_indices[2] != -1:  # +X
                    adjacent_tile = gnd.tiles[tile_index + 1]
                    bm.verts.new(
                        ((x + 1) * gnd.scale, (y + 1) * gnd.scale, -tile[3]))
                    bm.verts.new(
                        ((x + 1) * gnd.scale, (y + 0) * gnd.scale, -tile[1]))
                    bm.verts.new(((x + 1) * gnd.scale, (y + 0) * gnd.scale,
                                  -adjacent_tile[0]))
                    bm.verts.new(((x + 1) * gnd.scale, (y + 1) * gnd.scale,
                                  -adjacent_tile[2]))

        bm.verts.ensure_lookup_table()

        vertex_offset = 0
        for y in range(gnd.height):
            for x in range(gnd.width):
                tile_index = y * gnd.width + x
                tile = gnd.tiles[tile_index]
                for face_index in filter(lambda x: x >= 0, tile.face_indices):
                    face = gnd.faces[face_index]
                    vertex_indices = [vertex_offset + i for i in range(4)]
                    bmface = bm.faces.new(
                        [bm.verts[x] for x in vertex_indices])
                    bmface.material_index = face.texture_index
                    vertex_offset += 4

        bm.faces.ensure_lookup_table()

        bm.to_mesh(mesh)
        ''' Add materials to mesh. '''
        uv_texture = mesh.uv_textures.new()
        lightmap_uv_texture = mesh.uv_textures.new()
        for material in materials:
            ''' Create UV map. '''
            mesh.materials.append(material)
            material.texture_slots[0].uv_layer = uv_texture.name
            if options.should_import_lightmaps:
                material.texture_slots[1].uv_layer = lightmap_uv_texture.name
        '''
        Assign texture coordinates.
        '''
        uv_texture = mesh.uv_layers[0]
        lightmap_uv_layer = mesh.uv_layers[1]
        for face_index, face in enumerate(gnd.faces):
            uvs = list(face.uvs)
            '''
            Since we are adding quads and not triangles, we need to
            add the UVs in quad clockwise winding order.
            '''
            uvs = [uvs[x] for x in [0, 1, 3, 2]]
            for i, uv in enumerate(uvs):
                # UVs have to be V-flipped
                uv = uv[0], 1.0 - uv[1]
                uv_texture.data[face_index * 4 + i].uv = uv
            if options.should_import_lightmaps:
                x1 = (face.lightmap_index % lightmap_tiles_per_dimension
                      ) / lightmap_tiles_per_dimension
                y1 = int(face.lightmap_index / lightmap_tiles_per_dimension
                         ) / lightmap_tiles_per_dimension
                x2 = x1 + (1.0 / lightmap_tiles_per_dimension)
                y2 = y1 + (1.0 / lightmap_tiles_per_dimension)
                lightmap_uvs = [(x1, y1), (x2, y1), (x2, y2), (x1, y2)]
                for i, uv in enumerate(lightmap_uvs):
                    lightmap_uv_layer.data[face_index * 4 + i].uv = uv

        bpy.context.scene.objects.link(mesh_object)
        return mesh_object
예제 #51
0
    def geometry(self):

        bm = bmesh.new()

        verts = self.__class__.verts
        edges = self.__class__.edges
        faces = self.__class__.faces

        for n, v in enumerate(verts):
            bm.verts.new(v)
        bm.verts.ensure_lookup_table()  # ensures bm.verts can be indexed
        bm.verts.index_update(
        )  # ensures all bm.verts have an index (= different thing!)
        if hasattr(self.__class__, 'vert_attributes'):
            for attr, values in self.__class__.vert_attributes.items():
                for v, val in zip(bm.verts, values):
                    setattr(v, attr, val)

        for n, e in enumerate(edges):
            edge = bm.edges.new(bm.verts[v] for v in e)
        bm.edges.ensure_lookup_table()
        bm.edges.index_update()
        if hasattr(self.__class__, 'edge_attributes'):
            for attr, values in self.__class__.edge_attributes.items():
                for e, val in zip(bm.edges, values):
                    setattr(e, attr, val)

        for n, f in enumerate(faces):
            bm.faces.new(bm.verts[v] for v in f)
        bm.faces.ensure_lookup_table()
        bm.faces.index_update()
        if hasattr(self.__class__, 'face_attributes'):
            for attr, values in self.__class__.face_attributes.items():
                for f, val in zip(bm.faces, values):
                    setattr(f, attr, val)

        for etype in ('verts', 'edges', 'faces'):
            seq = getattr(bm, etype)
            bmlayers = seq.layers
            if hasattr(self.__class__, etype + '_layers'):
                for layertype, layers in getattr(self.__class__,
                                                 etype + '_layers').items():
                    bmlayertype = getattr(bmlayers, layertype)
                    for layername, values in layers.items():
                        bmlayer = bmlayertype.new(
                            layername
                        )  # fresh object so we don't check if the layer already exists
                        valmap = self.valmap(seq[0][bmlayer])
                        for n, ele in enumerate(seq):
                            if valmap is None:
                                ele[bmlayer] = values[n]
                            else:
                                valmap(ele[bmlayer], values[n])

        bmlayers = bm.loops.layers
        if hasattr(self.__class__, 'loops_layers'):
            for layertype, layers in getattr(self.__class__,
                                             'loops_layers').items():
                bmlayertype = getattr(bmlayers, layertype)
                attrname = self.__class__.attributemapping[
                    layertype] if layertype in self.__class__.attributemapping else None
                for layername, values in layers.items():
                    bmlayer = bmlayertype.new(
                        layername
                    )  # fresh object so we don't check if the layer already exists
                    # we assume all loops will be numbered in ascending order
                    # bm.faces[i].loops.index_update() is of no use, since it
                    # start numbering again at 0 for this set of loops, so there
                    # is no way to update the indices of all loop in in go,
                    # except by converting the bm to a regular mesh, in which
                    # case it happens automagically.
                    loopindex = 0
                    for face in bm.faces:
                        for loop in face.loops:
                            val = values[face.index][loopindex]
                            valmap = self.valmap(loop[bmlayer])
                            if valmap is None:
                                loop[bmlayer] = val
                            else:
                                valmap(loop[bmlayer], val)
                            loopindex += 1

        return bm
예제 #52
0
    def execute(self, context):
        objectselection_props = context.window_manager.objectselection_props
        obj = context.active_object

        #go in EDIT MODE to see the results as it's a mesh operation
        bpy.ops.object.mode_set(mode='EDIT')
        cpobj = objectselection_props.cuttingplane

        #only accept mesh
        if cpobj.type != 'MESH':
            return {'CANCELED'}

        bm = bmesh.new()
        bm.from_mesh(cpobj.data)

        bm.faces.ensure_lookup_table()
        bm.faces[0].select = True

        if len(bm.faces) > 1:
            return {'CANCELED'}

        bm.verts.ensure_lookup_table()
        v1 = cpobj.matrix_world @ bm.verts[0].co
        v2 = cpobj.matrix_world @ bm.verts[1].co
        v3 = cpobj.matrix_world @ bm.verts[2].co
        v4 = cpobj.matrix_world @ bm.verts[3].co

        nv2 = v4 - v3
        nv3 = v3 - v2
        vn = nv2.cross(nv3)
        vn.normalize()
        face = bm.faces[0]

        origin = cpobj.matrix_world @ face.calc_center_median()
        normal = vn

        #keep the manual selection saved in a vertex group
        if objectselection_props.rememberselection:
            obj.vertex_groups.new(name="prebisectselection")
            bpy.ops.object.vertex_group_assign()

        #only works in Object Mode
        bpy.ops.object.mode_set(mode='OBJECT')
        if objectselection_props.selectionoverride:
            #all vertices need to be selected
            for v in obj.data.vertices:
                v.select = True
        bpy.ops.object.mode_set(mode='EDIT')

        #call bisect with the selected plane
        bpy.ops.mesh.bisect(
            plane_co=origin,
            plane_no=normal,
            use_fill=objectselection_props.fill,
            clear_inner=objectselection_props.clearinner,
            clear_outer=objectselection_props.clearouter,
            threshold=objectselection_props.axisthreshold,
        )

        obj.vertex_groups.new(name="bisectionloop")
        bpy.ops.object.vertex_group_assign()
        mat = obj.matrix_world

        sideA = obj.vertex_groups["bisectionloop"]
        sideA = obj.vertex_groups.new(name="FrontSide")
        sideB = obj.vertex_groups["bisectionloop"]
        sideB = obj.vertex_groups.new(name="BackSide")

        indexarrayA = []
        for vertex in obj.data.vertices:
            pos = mat @ vertex.co
            distance = mathutils.geometry.distance_point_to_plane(
                pos, origin, normal)
            if distance > objectselection_props.axisthreshold:
                indexarrayA.append(vertex.index)

        indexarrayB = []
        for vertex in obj.data.vertices:
            pos = mat @ vertex.co
            distance = mathutils.geometry.distance_point_to_plane(
                pos, origin, normal)
            if distance < objectselection_props.axisthreshold:
                indexarrayB.append(vertex.index)

        #only works in Object Mode
        bpy.ops.object.mode_set(mode='OBJECT')
        sideA.add(indexarrayA, 1.0, 'REPLACE')
        sideB.add(indexarrayB, 1.0, 'REPLACE')
        bpy.ops.object.mode_set(mode='EDIT')

        bpy.ops.object.vertex_group_set_active(group='bisectionloop')
        bpy.ops.object.vertex_group_select()
        bpy.ops.object.vertex_group_set_active(group='FrontSide')
        bpy.ops.object.vertex_group_select()
        bpy.ops.object.vertex_group_assign()
        bpy.ops.object.vertex_group_deselect()

        bpy.ops.object.vertex_group_set_active(group='bisectionloop')
        bpy.ops.object.vertex_group_select()
        bpy.ops.object.vertex_group_set_active(group='BackSide')
        bpy.ops.object.vertex_group_select()
        bpy.ops.object.vertex_group_assign()
        bpy.ops.object.vertex_group_deselect()

        if objectselection_props.rememberselection:
            bpy.ops.object.vertex_group_set_active(group='prebisectselection')
            bpy.ops.object.vertex_group_select()
            bpy.ops.object.vertex_group_set_active(group='bisectionloop')
            bpy.ops.object.vertex_group_deselect()
            bpy.ops.object.vertex_group_set_active(group='prebisectselection')
            bpy.ops.object.vertex_group_remove()

        if objectselection_props.clearouter:
            bpy.ops.object.vertex_group_set_active(group='FrontSide')
            bpy.ops.object.vertex_group_remove()
            bpy.ops.object.vertex_group_set_active(group='BackSide')
            #Object Mode needed for the selection of the vertices
            bpy.ops.object.mode_set(mode='OBJECT')
            for v in obj.data.vertices:
                v.select = True
            bpy.ops.object.mode_set(mode='EDIT')

            bpy.ops.object.vertex_group_assign()
        if objectselection_props.clearinner:
            bpy.ops.object.vertex_group_set_active(group='BackSide')
            bpy.ops.object.vertex_group_remove()
            bpy.ops.object.vertex_group_set_active(group='FrontSide')
            #Object Mode needed for the selection of the vertices
            bpy.ops.object.mode_set(mode='OBJECT')
            for v in obj.data.vertices:
                v.select = True
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.object.vertex_group_assign()

        #clean up
        bm.free()
        return {'FINISHED'}
예제 #53
0
    def execute(self, context):
        obj = bpy.context.object
        om = obj.mode
        bpy.context.tool_settings.mesh_select_mode = [False, False, True]
        origin = Vector([0.0, 0.0, 0.0])

        # bmesh operations
        bpy.ops.object.mode_set()
        bm = bmesh.new()
        bm.from_mesh(obj.data)
        sel = [f for f in bm.faces if f.select]

        after = []

        # faces loop
        for i, of in enumerate(sel):
            nro = nrot(self, of.normal)
            off = vloc(self, i)
            loc = gloc(self, i)
            of.normal_update()

            # initial rotation noise
            if self.opt3 is False:
                rot = vrot(self, i)
            # initial scale noise
            if self.opt4 is False:
                s = vsca(self, i)

            # extrusion loop
            for r in range(self.num):
                # random probability % for extrusions
                if self.var4 > int(random.random() * 100):
                    nf = of.copy()
                    nf.normal_update()
                    no = nf.normal.copy()

                    # face/obj coordinates
                    if self.opt1 is True:
                        ce = nf.calc_center_bounds()
                    else:
                        ce = origin

                    # per step rotation noise
                    if self.opt3 is True:
                        rot = vrot(self, i + r)
                    # per step scale noise
                    if self.opt4 is True:
                        s = vsca(self, i + r)

                    # proportional, scale * offset
                    if self.opt2 is True:
                        off = s * off

                    for v in nf.verts:
                        v.co -= ce
                        v.co.rotate(nro)
                        v.co.rotate(rot)
                        v.co += ce + loc + no * off
                        v.co = v.co.lerp(ce, 1 - s)

                    # extrude code from TrumanBlending
                    for a, b in zip(of.loops, nf.loops):
                        sf = bm.faces.new((a.vert, a.link_loop_next.vert,
                                           b.link_loop_next.vert, b.vert))
                        sf.normal_update()
                    bm.faces.remove(of)
                    of = nf

            after.append(of)

        for v in bm.verts:
            v.select = False
        for e in bm.edges:
            e.select = False

        for f in after:
            if f not in sel:
                f.select = True
            else:
                f.select = False

        bm.to_mesh(obj.data)
        obj.data.update()

        # restore user settings
        bpy.ops.object.mode_set(mode=om)

        if not len(sel):
            self.report(
                {"WARNING"},
                "No suitable Face selection found. Operation cancelled")
            return {'CANCELLED'}

        return {'FINISHED'}
예제 #54
0
    def execute(self, context):
        if self.option_sel:
            objects = context.selected_objects
        else:
            objects = context.scene.objects
        objects = [obj for obj in objects if obj.type == 'MESH']

        geo = []
        fw = geo.append
        if not self.option_dest == 'Append':
            fw('// Game: Quake\n')
            if self.option_format == 'Valve':
                fw('// Format: Valve\n')
                fw('"mapversion" "220"\n')
            else:
                fw('// Format: Quake\n')
            fw('{\n"classname" "worldspawn"\n')
            fw('}\n')

        group_id = uuid.uuid4().int
        if self.option_geo == 'Faces' and objects != []:
            for obj in objects:
                ob = obj.evaluated_get(bpy.context.evaluated_depsgraph_get())
                bm = bmesh.new()
                bm.from_mesh(ob.data)
                bmesh.ops.connect_verts_concave(bm, faces=bm.faces)
                if self.option_triangulate:
                    bmesh.ops.triangulate(bm, faces=bm.faces)
                else:
                    bmesh.ops.connect_verts_concave(bm, faces=bm.faces)
                bmesh.ops.transform(bm,
                                    matrix=obj.matrix_world *
                                    self.option_scale,
                                    verts=bm.verts)
                for vert in bm.verts:
                    vert.co = self.gridsnap(vert.co)
                bm.faces.ensure_lookup_table()

                islands = [
                    island for island in self.get_islands(bm, verts=bm.verts)
                    ["islands"]
                ]
                print(ob.name, "Islands:", len(islands))

                facegroups = []
                for i in islands:
                    faces = []
                    for f in bm.faces:
                        is_in = True
                        for v in f.verts:
                            if v not in i:
                                is_in = False
                        if is_in:
                            faces.append(f)
                    if len(faces) > 0:
                        facegroups.append(faces)

                if len(facegroups) < 1:
                    facegroups = [bm.faces]
                for num, facegroup in enumerate(facegroups):
                    fw("{\n")
                    fw('"classname" "func_group"\n')
                    fw('"_phong" "1"\n')
                    fw('"_tb_type" "_tb_group"\n')
                    fw('"_tb_name" "' + ob.name + '_' + str(num) + '"\n')
                    fw('"_tb_id" "' + str(group_id) + '"\n')
                    for face in facegroup[:]:
                        if face.calc_area() < 0.0000001:
                            continue
                        fw('//brush from face from object: ' + obj.name +
                           ' sub: ' + str(num) + '\n')
                        fw('{\n')
                        for vert in reversed(face.verts[0:3]):
                            fw(f'( {self.printvec(vert.co)} ) ')
                        fw(self.texdata(face, bm, obj))
                        pyr = bmesh.ops.poke(bm,
                                             faces=[face],
                                             offset=-self.option_depth)
                        apex = pyr['verts'][0].co
                        pyr['verts'][0].co = self.gridsnap(apex)
                        for pyrface in pyr['faces']:
                            for vert in pyrface.verts[0:]:  # backfacing
                                fw(f'( {self.printvec(vert.co)} ) ')
                            pyrface.material_index = len(
                                obj.data.materials) - 1
                            fw(self.texdata(pyrface, bm, obj, skip=True))
                        fw('}\n')  # end face
                        group_id += 1
                    fw('}\n')  # end group
                    group_id += 1
                ob.to_mesh_clear()
                bm.free()
        elif self.option_geo == 'Brushes':
            fw("{\n")
            fw('"classname" "func_group"\n')
            fw('"_phong" "1"\n')
            fw('"_tb_type" "_tb_group"\n')
            fw('"_tb_name" "' +
               os.path.basename(bpy.data.filepath.split(".")[0]) + '"\n')
            fw('"_tb_id" "' + str(group_id) + '"\n')

            for obj in objects:
                ob = obj.evaluated_get(bpy.context.evaluated_depsgraph_get())
                bm = bmesh.new()
                bm.from_mesh(ob.data)
                #if self.option_tm:
                #bmesh.ops.transform(bm, matrix=obj.matrix_world,
                #                                    verts=bm.verts)
                bm.transform(obj.matrix_world * self.option_scale)
                if len(bm.verts) < 3:
                    continue
                for vert in bm.verts:
                    vert.co = self.gridsnap(vert.co)
                hull = bmesh.ops.convex_hull(bm,
                                             input=bm.verts,
                                             use_existing_faces=True)
                geom = hull['geom'] + hull['geom_holes']
                oldfaces = [face for face in bm.faces if face not in geom]
                bmesh.ops.delete(bm, geom=oldfaces, context='FACES')
                bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
                bmesh.ops.join_triangles(bm,
                                         faces=bm.faces,
                                         angle_face_threshold=0.01,
                                         angle_shape_threshold=0.7)
                bmesh.ops.connect_verts_nonplanar(bm,
                                                  faces=bm.faces,
                                                  angle_limit=0.0)
                fw('{\n')
                for face in bm.faces:
                    for vert in reversed(face.verts[0:3]):
                        fw(f'( {self.printvec(vert.co)} ) ')
                    fw(self.texdata(face, bm, obj))
                fw('}\n')
                bm.free()
            fw('}\n')

        if self.option_dest == 'File':
            self.prevent_overwrite(self.filepath)
            with open(self.filepath, 'w') as file:
                file.write(''.join(geo))
        elif self.option_dest == 'Append':
            self.prevent_overwrite(self.filepath)
            with open(self.filepath, 'a') as file:
                file.write(''.join(geo))
        else:
            bpy.context.window_manager.clipboard = ''.join(geo)

        return {'FINISHED'}
예제 #55
0
def points_to_cells(context,
                    original,
                    original_xyz_minmax,
                    points,
                    source_limit=0,
                    source_noise=0.0,
                    use_smooth_faces=False,
                    use_data_match=False,
                    use_debug_points=False,
                    margin=0.0,
                    material_index=0,
                    use_debug_redraw=False,
                    cell_scale=(1.0, 1.0, 1.0),
                    clean=True):

    from . import cell_calc
    collection = context.collection
    view_layer = context.view_layer

    # apply optional clamp
    if source_limit != 0 and source_limit < len(points):
        points = _limit_source(points, source_limit)

    # saddly we cant be sure there are no doubles
    from mathutils import Vector
    to_tuple = Vector.to_tuple

    # To remove doubles, round the values.
    points = [(Vector(to_tuple(p[0], 4)), p[1]) for p in points]
    del to_tuple
    del Vector

    if source_noise > 0.0:
        from random import random
        # boundbox approx of overall scale
        from mathutils import Vector
        matrix = original.matrix_world.copy()
        bb_world = [matrix @ Vector(v) for v in original.bound_box]
        scalar = source_noise * ((bb_world[0] - bb_world[6]).length / 2.0)

        from mathutils.noise import random_unit_vector
        points[:] = [(p[0] + (random_unit_vector() * (scalar * random())),
                      p[1]) for p in points]

    if use_debug_points:
        bm = bmesh.new()
        for p in points:
            bm.verts.new(p[0])
        mesh_tmp = bpy.data.meshes.new(name="DebugPoints")
        bm.to_mesh(mesh_tmp)
        bm.free()
        obj_tmp = bpy.data.objects.new(name=mesh_tmp.name,
                                       object_data=mesh_tmp)
        collection.objects.link(obj_tmp)
        del obj_tmp, mesh_tmp

    cells_verts = cell_calc.points_to_verts(original_xyz_minmax,
                                            points,
                                            cell_scale,
                                            margin_cell=margin)
    # some hacks here :S
    cell_name = original.name + "_cell"
    cells = []
    for center_point, cell_verts in cells_verts:
        # ---------------------------------------------------------------------
        # BMESH
        # create the convex hulls
        bm = bmesh.new()

        # WORKAROUND FOR CONVEX HULL BUG/LIMIT
        # XXX small noise
        import random

        def R():
            return (random.random() - 0.5) * 0.001

        for i, co in enumerate(cell_verts):
            co.x += R()
            co.y += R()
            co.z += R()
            bm_vert = bm.verts.new(co)

        import mathutils
        bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005)
        try:
            # Making cell meshes as convex full here!
            bmesh.ops.convex_hull(bm, input=bm.verts)
        except RuntimeError:
            import traceback
            traceback.print_exc()

        if clean:
            bm.normal_update()
            try:
                bmesh.ops.dissolve_limit(bm, verts=bm.verts, angle_limit=0.001)
            except RuntimeError:
                import traceback
                traceback.print_exc()
        # smooth faces will remain only inner faces, after appling boolean modifier.
        if use_smooth_faces:
            for bm_face in bm.faces:
                bm_face.smooth = True

        if material_index != 0:
            for bm_face in bm.faces:
                bm_face.material_index = material_index

        # ---------------------------------------------------------------------
        # MESH
        mesh_dst = bpy.data.meshes.new(name=cell_name)

        bm.to_mesh(mesh_dst)
        bm.free()
        del bm

        if use_data_match:
            # match materials and data layers so boolean displays them
            # currently only materials + data layers, could do others...
            mesh_src = original.data
            for mat in mesh_src.materials:
                mesh_dst.materials.append(mat)
            for lay_attr in ("vertex_colors", "uv_layers"):
                lay_src = getattr(mesh_src, lay_attr)
                lay_dst = getattr(mesh_dst, lay_attr)
                for key in lay_src.keys():
                    lay_dst.new(name=key)

        # ---------------------------------------------------------------------
        # OBJECT
        cell = bpy.data.objects.new(name=cell_name, object_data=mesh_dst)
        collection.objects.link(cell)
        cell.location = center_point
        cells.append(cell)

        # support for object materials
        if use_data_match:
            for i in range(len(mesh_dst.materials)):
                slot_src = original.material_slots[i]
                slot_dst = cell.material_slots[i]

                slot_dst.link = slot_src.link
                slot_dst.material = slot_src.material

        if use_debug_redraw:
            view_layer.update()
            _redraw_yasiamevil()

    view_layer.update()
    # move this elsewhere...
    # Blender 2.8: BGE integration was disabled, --
    # -- because BGE was deleted in Blender 2.8.
    '''
    for cell in cells:
        game = cell.game
        game.physics_type = 'RIGID_BODY'
        game.use_collision_bounds = True
        game.collision_bounds_type = 'CONVEX_HULL'
    '''
    return cells
예제 #56
0
    def execute(self, context):
        bool_flip = True
        min_iso, max_iso = 0.25, 0.75
        start_time = timeit.default_timer()
        try:
            check = bpy.context.object.vertex_groups[0]
        except:
            self.report({'ERROR'}, "The object doesn't have Vertex Groups")
            return {'CANCELLED'}

        ob0 = bpy.context.object

        group_id = ob0.vertex_groups.active_index
        vertex_group_name = ob0.vertex_groups[group_id].name

        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.select_all(action='SELECT')
        bpy.ops.object.mode_set(mode='OBJECT')

        me0 = ob0.data

        # generate new bmesh
        bm = bmesh.new()
        bm.from_mesh(me0)
        bm.verts.ensure_lookup_table()
        bm.edges.ensure_lookup_table()
        bm.faces.ensure_lookup_table()

        # store weight values
        weight = []
        ob = bpy.data.objects.new("temp", me0)
        for g in ob0.vertex_groups:
            ob.vertex_groups.new(name=g.name)
        for v in me0.vertices:
            try:
                weight.append(ob.vertex_groups[vertex_group_name].weight(
                    v.index))
            except:
                weight.append(0)

        # define iso values
        iso_values = []
        n_cuts = 24
        for i_cut in range(n_cuts):
            delta_iso = abs(max_iso - min_iso)
            min_iso = min(min_iso, max_iso)
            if delta_iso == 0: iso_val = min_iso
            else: iso_val = i_cut * delta_iso / (n_cuts - 1) + min_iso
            iso_values.append(iso_val)

        # Start Cuts Iterations
        filtered_edges = bm.edges
        for iso_val in iso_values:
            delete_edges = []

            faces_mask = []
            for f in bm.faces:
                w_min = 2
                w_max = 2
                for v in f.verts:
                    w = weight[v.index]
                    if w_min == 2:
                        w_max = w_min = w
                    if w > w_max: w_max = w
                    if w < w_min: w_min = w
                    if w_min < iso_val and w_max > iso_val:
                        faces_mask.append(f)
                        break
            #print("selected faces:" + str(len(faces_mask)))

            #link_faces = [[f for f in e.link_faces] for e in bm.edges]

            #faces_todo = [f.select for f in bm.faces]
            #faces_todo = [True for f in bm.faces]
            verts = []
            edges = []
            edges_id = {}
            _filtered_edges = []
            n_verts = len(bm.verts)
            count = n_verts
            for e in filtered_edges:
                #id0 = e.vertices[0]
                #id1 = e.vertices[1]
                id0 = e.verts[0].index
                id1 = e.verts[1].index
                w0 = weight[id0]
                w1 = weight[id1]

                if w0 == w1: continue
                elif w0 > iso_val and w1 > iso_val:
                    _filtered_edges.append(e)
                    continue
                elif w0 < iso_val and w1 < iso_val:
                    continue
                elif w0 == iso_val or w1 == iso_val:
                    continue
                else:
                    v0 = bm.verts[id0].co
                    v1 = bm.verts[id1].co
                    v = v0.lerp(v1, (iso_val - w0) / (w1 - w0))
                    if e not in delete_edges:
                        delete_edges.append(e)
                    verts.append(v)
                    edges_id[str(id0) + "_" + str(id1)] = count
                    edges_id[str(id1) + "_" + str(id0)] = count
                    count += 1
                    _filtered_edges.append(e)
            filtered_edges = _filtered_edges
            #print("creating faces")
            splitted_faces = []

            switch = False
            # splitting faces
            for f in faces_mask:
                # create sub-faces slots. Once a new vertex is reached it will
                # change slot, storing the next vertices for a new face.
                build_faces = [[], []]
                #switch = False
                verts0 = [v.index for v in f.verts]
                verts1 = list(verts0)
                verts1.append(verts1.pop(0))  # shift list
                for id0, id1 in zip(verts0, verts1):

                    # add first vertex to active slot
                    build_faces[switch].append(id0)

                    # try to split edge
                    try:
                        # check if the edge must be splitted
                        new_vert = edges_id[str(id0) + "_" + str(id1)]
                        # add new vertex
                        build_faces[switch].append(new_vert)
                        # if there is an open face on the other slot
                        if len(build_faces[not switch]) > 0:
                            # store actual face
                            splitted_faces.append(build_faces[switch])
                            # reset actual faces and switch
                            build_faces[switch] = []
                            # change face slot
                        switch = not switch
                        # continue previous face
                        build_faces[switch].append(new_vert)
                    except:
                        pass
                if len(build_faces[not switch]) == 2:
                    build_faces[not switch].append(id0)
                if len(build_faces[not switch]) > 2:
                    splitted_faces.append(build_faces[not switch])
                # add last face
                splitted_faces.append(build_faces[switch])
                #del_faces.append(f.index)

            #print("generate new bmesh")
            # adding new vertices
            new_verts = []
            for v in verts:
                new_verts.append(bm.verts.new(v))
            #verts = [0]*len(verts) + verts
            bm.verts.index_update()
            bm.verts.ensure_lookup_table()
            # adding new faces
            missed_faces = []
            added_faces = []
            for f in splitted_faces:
                try:
                    face_verts = [bm.verts[i] for i in f]
                    new_face = bm.faces.new(face_verts)
                    for e in new_face.edges:
                        filtered_edges.append(e)
                except:
                    missed_faces.append(f)

            #print("missed " + str(len(missed_faces)) + " faces")
            bm.faces.ensure_lookup_table()
            # updating weight values
            weight = weight + [iso_val] * len(verts)

            # deleting old edges/faces
            bm.edges.ensure_lookup_table()
            for e in delete_edges:
                bm.edges.remove(e)
            _filtered_edges = []
            for e in filtered_edges:
                if e not in delete_edges: _filtered_edges.append(e)
            filtered_edges = _filtered_edges

        #print("creating curve")
        name = ob0.name + '_Contour'
        me = bpy.data.meshes.new(name)
        bm.to_mesh(me)
        ob = bpy.data.objects.new(name, me)

        # Link object to scene and make active
        bpy.context.collection.objects.link(ob)
        bpy.context.view_layer.objects.active = ob
        ob.select_set(True)
        ob0.select_set(False)

        # generate new vertex group
        for g in ob0.vertex_groups:
            ob.vertex_groups.new(name=g.name)
            ob.vertex_groups.new(name="Smooth")
        #ob.vertex_groups.new(name=vertex_group_name)

        #print("doing weight")
        all_weight = weight + [iso_val] * len(verts)
        #mult = 1/(1-iso_val)
        for id in range(len(all_weight)):
            #if False: w = (all_weight[id]-iso_val)*mult
            w = all_weight[id]
            direction = bool_flip
            for i in range(len(iso_values) - 1):
                val0, val1 = iso_values[0], iso_values[-1]
                #val0, val1 = iso_values[i], iso_values[i+1]
                if val0 < w <= val1:
                    if direction: w1 = (w - val0) / (val1 - val0)
                    else: w1 = (val1 - w) / (val1 - val0)
                direction = not direction
            if w < iso_values[0]: w1 = not bool_flip
            if w > iso_values[-1]: w1 = not direction
            w2 = w1
            if w == iso_values[0]: w2 = 1
            ob.vertex_groups[vertex_group_name].add([id], w1, 'REPLACE')
            #ob.vertex_groups["Smooth"].add([id], w2, 'REPLACE')
            #ob.vertex_groups["Smooth"].add([id], w>min_iso, 'REPLACE')
        #print("weight done")
        #for id in range(len(weight), len(ob.data.vertices)):
        #    ob.vertex_groups[vertex_group_name].add([id], iso_val*0, 'ADD')

        ob.vertex_groups.active_index = group_id

        # materials
        bpy.ops.object.material_slot_add()
        bpy.ops.object.material_slot_add()
        bpy.ops.object.material_slot_add()
        try:
            body_mat = bpy.data.materials["Body"]
        except:
            body_mat = bpy.data.materials.new("Body")
        try:
            border_mat = bpy.data.materials["Border"]
        except:
            border_mat = bpy.data.materials.new("Border")
        try:
            corset_mat = bpy.data.materials["Corset"]
        except:
            corset_mat = bpy.data.materials.new("Corset")
        corset_mat.diffuse_color = (0.31, 0.737, 0.792, 1)
        border_mat.diffuse_color = (0.31 * 0.6, 0.737 * 0.6, 0.792 * 0.6, 1)
        ob.material_slots[0].material = body_mat
        ob.material_slots[1].material = border_mat
        ob.material_slots[2].material = corset_mat
        for p in ob.data.polygons:
            bool_corset = True
            bool_body = True
            for v in p.vertices:
                #w = ob.vertex_groups["Group"].weight(v)
                w = ob.vertex_groups.active.weight(v)
                if w < 1: bool_corset = False
                if w > 0: bool_body = False
            if bool_corset: p.material_index = 2
            elif not bool_body: p.material_index = 1
            if not bool_body:
                for id in p.vertices:
                    ob.vertex_groups["Smooth"].add([id], 1, 'REPLACE')

        # align new object
        ob.matrix_world = ob0.matrix_world

        # Displace Modifier
        ob.modifiers.new(type='VERTEX_WEIGHT_EDIT', name='Profile')
        group_name = ob.vertex_groups.active.name
        bpy.context.object.modifiers["Profile"].vertex_group = group_name
        ob.modifiers.new(type='SOLIDIFY', name='Solidify')
        mod = ob.modifiers["Solidify"]
        mod.thickness = self.max_thickness
        mod.vertex_group = vertex_group_name
        mod.thickness_vertex_group = self.min_thickness / self.max_thickness
        mod.offset = 1

        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.select_linked(delimit=set())
        bpy.ops.mesh.select_all(action='INVERT')
        bpy.ops.mesh.delete(type='VERT')
        bpy.ops.object.mode_set(mode='OBJECT')

        #bpy.ops.paint.weight_paint_toggle()
        #bpy.context.space_data.viewport_shade = 'WIREFRAME'
        ob.data.update()
        print("Contour Displace time: " +
              str(timeit.default_timer() - start_time) + " sec")

        return {'FINISHED'}
    def execute(self, context):
        CurFile = open(self.filepath, "rb")
        CurCollection = bpy.data.collections.new("New Mesh")
        bpy.context.scene.collection.children.link(CurCollection)

        tmpRead = CurFile.read()
        mshBytes = re.compile(b"\x33\xEA\x00\x00....\x2D\x00\x02\x1C",
                              re.DOTALL)
        iter = 0

        for x in mshBytes.finditer(
                tmpRead):  # Files can have multiple mesh containers
            CurFile.seek(x.end() + 4)
            FaceDataOff = int.from_bytes(CurFile.read(4), byteorder='little')
            MeshDataSize = int.from_bytes(CurFile.read(4), byteorder='little')
            MeshChunkStart = CurFile.tell()
            CurFile.seek(0x14, 1)
            mDataTableCount = int.from_bytes(CurFile.read(4), byteorder='big')
            mDataSubCount = int.from_bytes(CurFile.read(4), byteorder='big')
            mDataOffsets = []

            # This section isn't used right now... probably not needed
            for i in range(mDataTableCount):
                CurFile.seek(4, 1)
                mDataOffsets.append(
                    int.from_bytes(CurFile.read(4), byteorder='big'))
            mDataSubStart = CurFile.tell()

            for i in range(
                    mDataSubCount):  # Containers can have multiple sub-meshes
                CurFile.seek(mDataSubStart + i * 0xc + 8)
                offset = int.from_bytes(CurFile.read(4), byteorder='big')
                chunkHead = CurFile.seek(offset + MeshChunkStart + 0xC)
                VertCountDataOff = int.from_bytes(
                    CurFile.read(4), byteorder='big') + MeshChunkStart
                CurFile.seek(VertCountDataOff)
                VertChunkTotalSize = int.from_bytes(CurFile.read(4),
                                                    byteorder='big')
                VertChunkSize = int.from_bytes(CurFile.read(4),
                                               byteorder='big')
                VertCount = int(VertChunkTotalSize / VertChunkSize)
                CurFile.seek(8, 1)
                VertexStart = int.from_bytes(
                    CurFile.read(4),
                    byteorder='big') + FaceDataOff + MeshChunkStart
                CurFile.seek(0x14, 1)
                FaceCount = int(
                    int.from_bytes(CurFile.read(4), byteorder='big') / 2)
                CurFile.seek(4, 1)
                FaceStart = int.from_bytes(
                    CurFile.read(4),
                    byteorder='big') + FaceDataOff + MeshChunkStart

                CurFile.seek(FaceStart)
                StripList = []
                tmpList = []
                for f in range(FaceCount):
                    Indice = int.from_bytes(CurFile.read(2), byteorder='big')
                    if Indice == 65535:
                        StripList.append(tmpList.copy())
                        tmpList.clear()
                    else:
                        tmpList.append(Indice)
                FaceTable = []
                for f in StripList:
                    for f2 in strip2face(f):
                        FaceTable.append(f2)

                VertTable = []
                UVTable = []
                CMTable = []
                for v in range(VertCount):
                    CurFile.seek(VertexStart + v * VertChunkSize)
                    TempVert = struct.unpack('>fff', CurFile.read(4 * 3))
                    VertTable.append(TempVert)

                    # UV data for the textures
                    CurFile.seek(VertexStart + v * VertChunkSize +
                                 VertChunkSize - 16)
                    TempUV = struct.unpack('>ff', CurFile.read(4 * 2))
                    UVTable.append((TempUV[0], 1 - TempUV[1]))

                    # Color map data for the palette
                    CurFile.seek(VertexStart + v * VertChunkSize +
                                 VertChunkSize - 8)
                    TempCM = struct.unpack('>ff', CurFile.read(4 * 2))
                    CMTable.append((TempCM[0], 1 - TempCM[1]))

                #build mesh
                mesh1 = bpy.data.meshes.new("Mesh")
                mesh1.use_auto_smooth = True
                obj = bpy.data.objects.new("Mesh_" + str(iter) + "_" + str(i),
                                           mesh1)
                CurCollection.objects.link(obj)
                bpy.context.view_layer.objects.active = obj
                obj.select_set(True)
                mesh = bpy.context.object.data
                bm = bmesh.new()

                for v in VertTable:
                    bm.verts.new((v[0], v[1], v[2]))
                list = [v for v in bm.verts]
                for f in FaceTable:
                    try:
                        bm.faces.new((list[f[0]], list[f[1]], list[f[2]]))
                    except:
                        continue
                bm.to_mesh(mesh)

                uv_layer = bm.loops.layers.uv.verify()
                cm_layer = bm.loops.layers.uv.new()
                for f in bm.faces:
                    f.smooth = True
                    for l in f.loops:
                        luv = l[uv_layer]
                        lcm = l[cm_layer]
                        try:
                            luv.uv = UVTable[l.vert.index]
                            lcm.uv = CMTable[l.vert.index]
                        except:
                            continue
                bm.to_mesh(mesh)

                bm.free()
                obj.rotation_euler = (1.5707963705062866, 0, 0)
            iter += 1
        CurFile.close()
        del CurFile
        return {'FINISHED'}
예제 #58
0
def load(properties, data, *args, **kwargs):
    """ Imports photogrammetry data into the current scene.
    """
    scene = kwargs.get('scene', None)
    if not scene:
        raise Exception('Scene required to load data in blender.load')
    collection = set_active_collection(**kwargs)
    camera_collection = set_active_collection(name='Cameras',
                                              parent=collection,
                                              **kwargs)

    if properties.update_render_size:
        resolution = data.get('resolution', None)
        if not resolution and len(data['cameras']):
            resolution = get_image_size(
                next(c for c in data['cameras'].values())['filename'])
        scene.render.resolution_x, scene.render.resolution_y = resolution

    for cid, camera in data['cameras'].items():
        # rotation in file needs to be transposed to work properly
        mrot = Matrix(camera['R'])
        mrot.transpose()
        rotation = mrot.to_euler('XYZ')

        # https://github.com/simonfuhrmann/mve/wiki/Math-Cookbook
        # t = -R * c
        # where c is the real world position as I've calculated, and t is the camera location stored in bundle.out
        translation = -1 * mrot @ Vector(camera['t'])

        # create and link camera
        name = os.path.splitext(os.path.basename(camera['filename']))[0]
        cdata = bpy.data.cameras.new(name)
        cam = bpy.data.objects.new(name, cdata)
        camera_collection.objects.link(cam)

        # add background images per camera!
        cdata.show_background_images = True
        bg = cdata.background_images.new()
        image_path = camera['filename']
        if properties.relative_paths:
            image_path = bpy.path.relpath(image_path)
        img = bpy.data.images.load(image_path, check_existing=True)
        bg.image = img
        bg.alpha = properties.camera_alpha
        bg.display_depth = properties.camera_display_depth

        # set parameters
        cam.location = translation
        cam.rotation_euler = rotation
        cdata.sensor_width = 35
        cdata.lens = (camera['f'] * 35) / scene.render.resolution_x

    coords = []
    for tracker in data['trackers'].values():
        coords.append(Vector(tracker['co']))

    mesh = bpy.data.meshes.new("PhotogrammetryPoints")
    obj = bpy.data.objects.new("PhotogrammetryPoints", mesh)

    collection.objects.link(obj)
    scene.view_layers[0].objects.active = obj
    obj.select_set(True)

    # add all coords from bundler points as vertices
    bm = bmesh.new()
    for v in coords:
        bm.verts.new(v)

    # make the bmesh the object's mesh
    bm.to_mesh(mesh)
    bm.free()
def export(filepath):
    file = open(filepath, 'w')
    fscanf = file.write

    objList = [object for object in bpy.data.objects if object.type == 'MESH']
    for obj in objList:
        mesh = obj.data

        bm = bmesh.new()
        bm.from_mesh(mesh)
        bmesh.ops.triangulate(bm, faces=bm.faces)
        bm.to_mesh(mesh)
        mesh.calc_loop_triangles()
        bm.free()

        fscanf('blendWeightsX blendWeightsY blendWeightsZ blendWeightsW ')
        fscanf('blendIndicesX blendIndicesY blendIndicesZ blendIndicesW ')
        fscanf('\n')

        fscanf(' \n')

        vert = mesh.vertices

        for face in mesh.polygons:
            t = obj.data.loop_triangles

            t_1 = vert[face.vertices[0]]
            count_1 = 0
            for g in t_1.groups:
                fscanf('%.3f ' % g.weight)
                count_1 = count_1 + 1
            while count_1 < 4:
                fscanf('%.3f ' % 0.0)
                count_1 = count_1 + 1

            count_1 = 0
            for g in t_1.groups:
                fscanf('%d ' % g.group)
                count_1 = count_1 + 1
            while count_1 < 4:
                fscanf('%d ' % -1)
                count_1 = count_1 + 1

            fscanf('\n')

            #==========================================================

            t_2 = vert[face.vertices[2]]
            count_2 = 0
            for g in t_2.groups:
                fscanf('%.3f ' % g.weight)
                count_2 = count_2 + 1
            while count_2 < 4:
                fscanf('%.3f ' % 0.0)
                count_2 = count_2 + 1

            count_2 = 0
            for g in t_2.groups:
                fscanf('%d ' % g.group)
                count_2 = count_2 + 1
            while count_2 < 4:
                fscanf('%d ' % -1)
                count_2 = count_2 + 1

            fscanf('\n')

            #==========================================================

            t_3 = vert[face.vertices[1]]
            count_3 = 0
            for g in t_3.groups:
                fscanf('%.3f ' % g.weight)
                count_3 = count_3 + 1
            while count_3 < 4:
                fscanf('%.3f ' % 0.0)
                count_3 = count_3 + 1

            count_3 = 0
            for g in t_3.groups:
                fscanf('%d ' % g.group)
                count_3 = count_3 + 1
            while count_3 < 4:
                fscanf('%d ' % -1)
                count_3 = count_3 + 1

            fscanf('\n')

    file.close()

    return {'FINISHED'}
예제 #60
0
파일: imports.py 프로젝트: Guild-Hall/MCAnm
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)