def focus_view_on(region_3d, location):
    r3d = region_3d

    a = r3d.view_location.copy()
    b = location
    mm = r3d.view_matrix.inverted()

    vr = mm.to_3x3()
    loc = mm.translation

    n = (a-loc).cross(b-loc).normalized()
    alp = math.acos( max(-1.0,min(1.0,  (a-loc).normalized().dot( (b-loc).normalized() )  )))

    zero = Vector()
    u0,v0,w0 = vr.transposed()
    u = rot_on( zero, n, alp, u0 )
    v = rot_on( zero, n, alp, v0 )
    w = rot_on( zero, n, alp, w0 )

    if bpy.context.user_preferences.inputs.view_rotate_method == 'TURNTABLE':
        ez = Vector((0,0,1))
        u2 = ez.cross(w)
        v2 = w.cross(u2)
        u,v = u2,v2

    vr2 = Matrix((u,v,w)).transposed()

    mm2 = vr2.to_4x4()
    mm2[0][3] = loc[0]
    mm2[1][3] = loc[1]
    mm2[2][3] = loc[2]

    dist0 = (loc-location).length
    r3d.view_distance = dist0
    r3d.view_matrix = mm2.inverted()
 def make_tube(self, mats, verts):
     edges_out = []
     verts_out = []
     faces_out = []
     vID = 0
     nring = len(verts[0])
     # end face
     faces_out.append(list(range(nring)))
     for i,m in enumerate(mats):
         for j,v in enumerate(verts[0]):
             vout = Matrix(m) * Vector(v)
             verts_out.append(vout.to_tuple())
             vID = j + i*nring
             # rings
             if j != 0:
                 edges_out.append([vID, vID - 1])
             else:
                 edges_out.append([vID, vID + nring-1])
             # lines
             if i != 0:
                 edges_out.append([vID, vID - nring])
                 # faces
                 if j != 0:
                     faces_out.append([vID, vID - nring, vID - nring - 1, vID-1,])
                 else:
                     faces_out.append([vID, vID - nring,  vID-1, vID + nring-1])
     # end face
     # reversing list fixes face normal direction keeps mesh manifold
     f = list(range(vID, vID-nring, -1))
     faces_out.append(f)
     return verts_out, edges_out, faces_out
Beispiel #3
0
def print_mat(label, matrix, column=4):
    if isinstance(matrix[0], (float, int)):
        # buffer用
        if len(matrix) == 16:
            mat = [matrix[:4], matrix[4:8], matrix[8:12], matrix[12:16]]
            matrix = Matrix(mat)
        elif len(matrix) == 9:
            matrix = Matrix([matrix[:3], matrix[3:6], matrix[6:9]])
        elif len(matrix) == 4:
            matrix = Matrix([matrix[:2], matrix[2:4]])

    print(label)
    t2 = 'row{0} [{1:>{5}.{6}f}, {2:>{5}.{6}f}]'
    t3 = 'row{0} [{1:>{5}.{6}f}, {2:>{5}.{6}f}, {3:>{5}.{6}f}]'
    t4 = 'row{0} [{1:>{5}.{6}f}, {2:>{5}.{6}f}, {3:>{5}.{6}f}, {4:>{5}.{6}f}]'
    m = matrix.transposed()
    for cnt, row in enumerate(m):
        if len(row) == 2:
            print(t2.format(cnt, row[0], row[1], 0, 0, column + 3, column))
        elif len(row) == 3:
            print(t3.format(cnt, row[0], row[1], row[2], 0,
                            column + 3, column))
        else:
            print(t4.format(cnt, row[0], row[1], row[2], row[3],
                            column + 3, column))
Beispiel #4
0
def copyto(scene, source_obj, pos, xdir, zdir, axes, scale=None):  
     """ 
     copy the source_obj to pos, so its primary axis points in zdir and its 
     secondary axis points in xdir       
     """  
     copy_obj = source_obj.copy()
     scene.objects.link(copy_obj)     
       
     xdir = xdir.normalized()  
     zdir = zdir.normalized()  
     #rotation first  
     z_axis = zdir  
     x_axis = xdir      
     y_axis = z_axis.cross(x_axis)  
     #use axes_dict to assign the axis as chosen in panel 
     A, B, C = axes_dict[axes]
     rot_mat = Matrix()  
     rot_mat[A].xyz = x_axis  
     rot_mat[B].xyz = y_axis  
     rot_mat[C].xyz = z_axis  
     rot_mat.transpose()  
     
     #rotate object 
     copy_obj.matrix_world = rot_mat   
            
     #move object into position    
     copy_obj.location = pos  
     
     #scale object
     if  scale != None:
         copy_obj.scale = scale
     
     return copy_obj  
def get_coconuts_mesh(context, prefs):
    me = context.blend_data.meshes.new('temp_mesh')
    bm = bmesh.new()
    bm.from_mesh(me)
    mat = Matrix()

    trunk_length = prefs.palm_stage_length * prefs.palm_stages

    coconutX = (0.29, -0.29, 0,     0)
    coconutY = (0,     0,    0.29, -0.29)
    coconutZ = trunk_length - 0.2

    coconuts = get_random(prefs.lp_Tree_Palm_Top_Coconuts_Min,
                          prefs.lp_Tree_Palm_Top_Coconuts_Max)

    for i in range(0, coconuts):
        mat.translation = (coconutX[i], coconutY[i], coconutZ)
        bmesh.ops.create_icosphere(
            bm,
            subdivisions=1,
            diameter=0.15,
            matrix=mat)

    bm.to_mesh(me)

    return me
Beispiel #6
0
def get_bone_matrix(armature, bone, relative=True):
    pose_bone = armature.pose.bones[bone.name]

    m = Matrix()  ### inverted posebone origin matrix
    m.row[0] = [0, 0, 1, 0]
    m.row[1] = [1, 0, 0, 0]
    m.row[2] = [0, 1, 0, 0]
    m.row[3] = [0, 0, 0, 1]

    if bone.parent == None:
        mat_bone_space = m * pose_bone.matrix.copy()
    else:
        if relative:
            mat_bone_space = pose_bone.parent.matrix.inverted() * pose_bone.matrix
        else:
            mat_bone_space = m * pose_bone.matrix

    #### remap matrix
    loc, rot, scale = mat_bone_space.decompose()

    if not bone.use_inherit_scale:
        scale = (m * pose_bone.matrix).decompose()[2]

    loc_mat = Matrix.Translation(loc)

    rot_mat = rot.inverted().to_matrix().to_4x4()

    scale_mat = Matrix()
    scale_mat[0][0] = scale[1]
    scale_mat[1][1] = scale[0]

    mat_bone_space = loc_mat * rot_mat * scale_mat

    return mat_bone_space
def parseTree(tree, parentName):
    # print("parsetree")
    armName = bpy.context.active_object.name
    armatures.createBone(armName, tree.name, parentName)
    bpy.ops.roboteditor.select_segment(segment_name=tree.name)
    # print(tree.name)
    boneProp = bpy.context.active_bone.RobotEditor

    m = Matrix()
    # print(tree.transformations)
    for i in tree.transformations:
        # We expect a matrix here!
        # Todo accept rotation and translations too!
        if type(i[0]) is list:
            m = m * Matrix(i)
        elif len(i) == 3:
            # TODO
            pass
        elif len(i) == 4:
            # TODO
            pass
        else:
            raise Exception("ParsingError")
            # print(m)

    bpy.context.active_bone.RobotEditor.Euler.x.value = m.translation[0] / 1000
    bpy.context.active_bone.RobotEditor.Euler.y.value = m.translation[1] / 1000
    bpy.context.active_bone.RobotEditor.Euler.z.value = m.translation[2] / 1000

    bpy.context.active_bone.RobotEditor.Euler.gamma.value = degrees(m.to_euler().z)
    bpy.context.active_bone.RobotEditor.Euler.beta.value = degrees(m.to_euler().y)
    bpy.context.active_bone.RobotEditor.Euler.alpha.value = degrees(m.to_euler().x)

    if tree.axis_type == 'revolute':
        bpy.context.active_bone.RobotEditor.jointMode = 'REVOLUTE'
        # boneProp.theta.value = float(tree.initalValue)
        bpy.context.active_bone.RobotEditor.theta.max = float(tree.max)
        bpy.context.active_bone.RobotEditor.theta.min = float(tree.min)
    else:
        bpy.context.active_bone.RobotEditor.jointMode = 'PRISMATIC'
        # boneProp.d.value = float(tree.initialValue)
        bpy.context.active_bone.RobotEditor.d.max = float(tree.max)
        bpy.context.active_bone.RobotEditor.d.min = float(tree.min)

    if tree.axis is not None:
        for i, axis in enumerate(tree.axis):
            if axis == -1.0:
                bpy.context.active_bone.RobotEditor.axis_revert = True
                tree.axis[i] = 1.0

        if tree.axis == [1.0, 0.0, 0.0]:
            bpy.context.active_bone.RobotEditor.axis = 'X'
        elif tree.axis == [0.0, 1.0, 0.0]:
            bpy.context.active_bone.RobotEditor.axis = 'Y'
        elif tree.axis == [0.0, 0.0, 1.0]:
            bpy.context.active_bone.RobotEditor.axis = 'Z'
    # print("parsetree done")

    for child in tree.children:
        parseTree(child, tree.name)
Beispiel #8
0
def fit_cubicbezier(l_v, l_t):
    #########################################################
    # http://nbviewer.ipython.org/gist/anonymous/5688579

    # make the summation functions for A (16 of them)
    A_fns = [
        lambda l_t: sum([2*t**0*(t-1)**6 for t in l_t]),
        lambda l_t: sum([-6*t**1*(t-1)**5 for t in l_t]),
        lambda l_t: sum([6*t**2*(t-1)**4 for t in l_t]),
        lambda l_t: sum([-2*t**3*(t-1)**3 for t in l_t]),

        lambda l_t: sum([-6*t**1*(t-1)**5 for t in l_t]),
        lambda l_t: sum([18*t**2*(t-1)**4 for t in l_t]),
        lambda l_t: sum([-18*t**3*(t-1)**3 for t in l_t]),
        lambda l_t: sum([6*t**4*(t-1)**2 for t in l_t]),

        lambda l_t: sum([6*t**2*(t-1)**4 for t in l_t]),
        lambda l_t: sum([-18*t**3*(t-1)**3 for t in l_t]),
        lambda l_t: sum([18*t**4*(t-1)**2 for t in l_t]),
        lambda l_t: sum([-6*t**5*(t-1)**1 for t in l_t]),

        lambda l_t: sum([-2*t**3*(t-1)**3 for t in l_t]),
        lambda l_t: sum([6*t**4*(t-1)**2 for t in l_t]),
        lambda l_t: sum([-6*t**5*(t-1)**1 for t in l_t]),
        lambda l_t: sum([2*t**6*(t-1)**0 for t in l_t])
    ]

    # make the summation functions for b (4 of them)
    b_fns = [
        lambda l_t, l_v: sum(v * (-2 * (t**0) * ((t-1)**3))
                             for t, v in zip(l_t, l_v)),
        lambda l_t, l_v: sum(v * (6 * (t**1) * ((t-1)**2))
                             for t, v in zip(l_t, l_v)),
        lambda l_t, l_v: sum(v * (-6 * (t**2) * ((t-1)**1))
                             for t, v in zip(l_t, l_v)),
        lambda l_t, l_v: sum(v * (2 * (t**3) * ((t-1)**0))
                             for t, v in zip(l_t, l_v)),
    ]

    # compute the data we will put into matrix A
    A_values = [fn(l_t) for fn in A_fns]
    # fill the A matrix with data
    A_matrix = Matrix(tuple(zip(*[iter(A_values)]*4)))
    try:
        A_inv = A_matrix.inverted()
    except:
        return (float('inf'), l_v[0], l_v[0], l_v[0], l_v[0])

    # compute the data we will put into the b vector
    b_values = [fn(l_t, l_v) for fn in b_fns]
    # fill the b vector with data
    b_vector = Vector(b_values)

    # solve for the unknowns in vector x
    v0, v1, v2, v3 = A_inv * b_vector

    err = compute_cubic_error(v0, v1, v2, v3, l_v, l_t) / len(l_v)

    return (err, v0, v1, v2, v3)
Beispiel #9
0
def matchPoseReverse(pb, src):
    gmat = src.matrix
    tail = gmat.col[3] + src.length * gmat.col[1]
    rmat = Matrix((gmat.col[0], -gmat.col[1], -gmat.col[2], tail))
    rmat.transpose()
    pmat = getPoseMatrix(rmat, pb)
    pb.matrix_basis = pmat
    insertRotation(pb, pmat)
    def _convertMatrixTo4x4(self, value):
        matrix = Matrix()

        matrix[0] = value[0:4]
        matrix[1] = value[4:8]
        matrix[2] = value[8:12]
        matrix[3] = value[12:16]

        return matrix.transposed()
Beispiel #11
0
 def test_matrix_to_3x3(self):
     # mat =
     # [ 1  2  3  4  ]
     # [ 2  4  6  8  ]
     # [ 3  6  9  12 ]
     # [ 4  8  12 16 ]
     mat = Matrix(tuple((i, 2 * i, 3 * i, 4 * i) for i in range(1, 5)))
     mat_correct = Matrix(((1, 2, 3), (2, 4, 6), (3, 6, 9)))
     self.assertEqual(mat.to_3x3(), mat_correct)
Beispiel #12
0
	def _parseVertices( self, mesh ):
		'''
		Extract the vertices from a blender mesh
		'''
		transform = Matrix().to_4x4()
		transform.identity()
		if not self.export_config.export_rot:
			transform = self.export_config.global_matrix.to_4x4() * self.matrix_world
		self.vertices = [transform * v.co for v in mesh.vertices]
    def parse_rotation_channel(gltf, node, obj, bone, channel, animation):
        """Manage rotation animation."""
        blender_path = "pose.bones[" + json.dumps(bone.name) + "].rotation_quaternion"
        group_name = bone.name

        keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
        values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
        bind_rotation = node.blender_bone_matrix.to_quaternion()

        if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
            # TODO manage tangent?
            quat_keyframes = [
                quaternion_gltf_to_blender(values[idx * 3 + 1])
                for idx in range(0, len(keys))
            ]
        else:
            quat_keyframes = [quaternion_gltf_to_blender(vals) for vals in values]


        if node.parent is None:
            final_rots = [
                bind_rotation.inverted() @ quat_keyframe
                for quat_keyframe in quat_keyframes
            ]
        else:
            if not gltf.data.nodes[node.parent].is_joint:
                parent_mat = Matrix()
            else:
                parent_mat = gltf.data.nodes[node.parent].blender_bone_matrix

            if parent_mat != parent_mat.inverted():
                final_rots = [
                    bind_rotation.rotation_difference(
                        (parent_mat @ quat_keyframe.to_matrix().to_4x4()).to_quaternion()
                    )
                    for quat_keyframe in quat_keyframes
                ]
            else:
                final_rots = [
                    bind_rotation.rotation_difference(quat_keyframe)
                    for quat_keyframe in quat_keyframes
                ]

        # Manage antipodal quaternions
        for i in range(1, len(final_rots)):
            if final_rots[i].dot(final_rots[i-1]) < 0:
                final_rots[i] = -final_rots[i]

        BlenderBoneAnim.fill_fcurves(
            obj.animation_data.action,
            keys,
            final_rots,
            group_name,
            blender_path,
            animation.samplers[channel.sampler].interpolation
        )
Beispiel #14
0
def sparse(values):
    """
    constructs a sparse matrix from a list of tuples (col, row, value)
    """
    result = Matrix()
    result.zero()
    result[W][W] = 1
    for cell in values:
        result.col[cell[0]][cell[1]] = cell[2]
    return result
Beispiel #15
0
 def _transform_mesh_coordinate_system(mesh):
     # This transformation swaps Y and Z axes, turning coordinate system from
     # right-handed to left-handed.
     transformation = Matrix()
     transformation.zero()
     transformation[0][0] = 1
     transformation[1][2] = 1
     transformation[2][1] = 1
     transformation[3][3] = 1
     mesh.transform(transformation)
def cubic_bezier_fit_value(l_v, l_t):
    def compute_error(v0,v1,v2,v3,l_v,l_t):
        return math.sqrt(sum((cubic_bezier_blend_t(v0,v1,v2,v3,t)-v)**2 for v,t in zip(l_v,l_t)))
    
    #########################################################
    # http://nbviewer.ipython.org/gist/anonymous/5688579
    
    # make the summation functions for A (16 of them)
    A_fns = [
        lambda l_t: sum([  2*t**0*(t-1)**6 for t in l_t]),
        lambda l_t: sum([ -6*t**1*(t-1)**5 for t in l_t]),
        lambda l_t: sum([  6*t**2*(t-1)**4 for t in l_t]),
        lambda l_t: sum([ -2*t**3*(t-1)**3 for t in l_t]),
        
        lambda l_t: sum([ -6*t**1*(t-1)**5 for t in l_t]),
        lambda l_t: sum([ 18*t**2*(t-1)**4 for t in l_t]),
        lambda l_t: sum([-18*t**3*(t-1)**3 for t in l_t]),
        lambda l_t: sum([  6*t**4*(t-1)**2 for t in l_t]),
        
        lambda l_t: sum([  6*t**2*(t-1)**4 for t in l_t]),
        lambda l_t: sum([-18*t**3*(t-1)**3 for t in l_t]),
        lambda l_t: sum([ 18*t**4*(t-1)**2 for t in l_t]),
        lambda l_t: sum([ -6*t**5*(t-1)**1 for t in l_t]),
        
        lambda l_t: sum([ -2*t**3*(t-1)**3 for t in l_t]),
        lambda l_t: sum([  6*t**4*(t-1)**2 for t in l_t]),
        lambda l_t: sum([ -6*t**5*(t-1)**1 for t in l_t]),
        lambda l_t: sum([  2*t**6*(t-1)**0 for t in l_t])
        ]
    
    # make the summation functions for b (4 of them)
    b_fns = [
        lambda l_t,l_v: sum([-2*v*t**0*(t-1)**3 for t,v in zip(l_t,l_v)]),
        lambda l_t,l_v: sum([ 6*v*t**1*(t-1)**2 for t,v in zip(l_t,l_v)]),
        lambda l_t,l_v: sum([-6*v*t**2*(t-1)**1 for t,v in zip(l_t,l_v)]),
        lambda l_t,l_v: sum([ 2*v*t**3*(t-1)**0 for t,v in zip(l_t,l_v)])
        ]
    
    # compute the data we will put into matrix A
    A_values = [fn(l_t) for fn in A_fns]
    # fill the A matrix with data
    A_matrix = Matrix(tuple(zip(*[iter(A_values)]*4)))
    A_inv    = A_matrix.inverted()
    
    # compute the data we will put into the b vector
    b_values = [fn(l_t, l_v) for fn in b_fns]
    # fill the b vector with data
    b_vector = Vector(b_values)
    
    # solve for the unknowns in vector x
    v0,v1,v2,v3 = A_inv * b_vector
    
    err = compute_error(v0,v1,v2,v3,l_v,l_t) / len(l_v)
    
    return (err,v0,v1,v2,v3)
def calculate_best_plane(locs):
    
    # calculating the center of masss
    com = Vector()
    for loc in locs:
        com += loc
    com /= len(locs)
    x, y, z = com
    
    
    # creating the covariance matrix
    mat = Matrix(((0.0, 0.0, 0.0),
                  (0.0, 0.0, 0.0),
                  (0.0, 0.0, 0.0),
                 ))
    
    for loc in locs:
        mat[0][0] += (loc[0]-x)**2
        mat[1][0] += (loc[0]-x)*(loc[1]-y)
        mat[2][0] += (loc[0]-x)*(loc[2]-z)
        mat[0][1] += (loc[1]-y)*(loc[0]-x)
        mat[1][1] += (loc[1]-y)**2
        mat[2][1] += (loc[1]-y)*(loc[2]-z)
        mat[0][2] += (loc[2]-z)*(loc[0]-x)
        mat[1][2] += (loc[2]-z)*(loc[1]-y)
        mat[2][2] += (loc[2]-z)**2
    
    # calculating the normal to the plane
    normal = False
    try:
        mat.invert()
    except:
        if sum(mat[0]) == 0.0:
            normal = Vector((1.0, 0.0, 0.0))
        elif sum(mat[1]) == 0.0:
            normal = Vector((0.0, 1.0, 0.0))
        elif sum(mat[2]) == 0.0:
            normal = Vector((0.0, 0.0, 1.0))
    if not normal:
        # warning! this is different from .normalize()
        itermax = 500
        iter = 0
        vec = Vector((1.0, 1.0, 1.0))
        vec2 = (mat * vec)/(mat * vec).length
        while vec != vec2 and iter<itermax:
            iter+=1
            vec = vec2
            vec2 = mat * vec
            if vec2.length != 0:
                vec2 /= vec2.length
        if vec2.length == 0:
            vec2 = Vector((1.0, 1.0, 1.0))
        normal = vec2
    
    return(com, normal)
Beispiel #18
0
def pointInTri2D(v, v1, v2, v3):
    global dict_matrix

    key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y

    # Commented because its slower to do teh bounds check, we should realy cache the bounds info for each face.
    '''
    # BOUNDS CHECK
    xmin= 1000000
    ymin= 1000000

    xmax= -1000000
    ymax= -1000000

    for i in (0,2,4):
        x= key[i]
        y= key[i+1]

        if xmax<x:	xmax= x
        if ymax<y:	ymax= y
        if xmin>x:	xmin= x
        if ymin>y:	ymin= y

    x= v.x
    y= v.y

    if x<xmin or x>xmax or y < ymin or y > ymax:
        return False
    # Done with bounds check
    '''
    try:
        mtx = dict_matrix[key]
        if not mtx:
            return False
    except:
        side1 = v2 - v1
        side2 = v3 - v1

        nor = side1.cross(side2)

        mtx = Matrix((side1, side2, nor))

        # Zero area 2d tri, even tho we throw away zerop area faces
        # the projection UV can result in a zero area UV.
        if not mtx.determinant():
            dict_matrix[key] = None
            return False

        mtx.invert()

        dict_matrix[key] = mtx

    uvw = (v - v1) * mtx
    return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1
Beispiel #19
0
def unit_normal(a, b, c):
    mat_x = Matrix(((1, a[1], a[2]), (1, b[1], b[2]), (1, c[1], c[2])))
    mat_y = Matrix(((a[0], 1, a[2]), (b[0], 1, b[2]), (c[0], 1, c[2])))
    mat_z = Matrix(((a[0], a[1], 1), (b[0], b[1], 1), (c[0], c[1], 1)))

    x = Matrix.determinant(mat_x)
    y = Matrix.determinant(mat_y)
    z = Matrix.determinant(mat_z)

    magnitude = (x**2 + y**2 + z**2)**.5
    return (x/magnitude, y/magnitude, z/magnitude)
 def to_Scene(self):
     if self.hasOpened:
         #      Load table
         #
         #Get the tag objects from the scene by filtering objects with 
         # hexadecimal strings as the first 8 chars of their name
         tag_objs = {obj.name[:8]:obj for obj in bpy.data.objects if isHex(obj.name[:8])}
         #
         #      Load placements
         #
         #Create a parent object to contain all placement objects
         for i, p in enumerate(self.placements):
             mesh = None # the mesh for the object
             #The placement's index references a table item that has a tag index
             if p.index >= 0 and p.index < self.n_table_items: # the index must be in the range of the table items
                 palette_tag_idx = self.table_items[p.index].index 
                 try:
                     #apply the data if found
                     mesh = tag_objs[str('%08x' % palette_tag_idx).upper()].data
                 except KeyError:
                     print("Could not find tag '%08x' for placement %d" % (palette_tag_idx, i))
             object = bpy.data.objects.new("Placement.%03d" % i, mesh)
             #link the object to the active scene (ususally scene 0)
             bpy.context.scene.objects.link(object)
             for j in range(3):
                 object.lock_scale[j] = True #objects in forge can be only moved or rotated
             #
             #    Apply a matrix to the object to place it correctly in the scene
             #
             #Recreate col1 using cross product of column vectors: col0 
             # and col2 that are perpendicular to one another
             col2 = p.col2
             col0 = p.col0
             col1 = col0.cross(col2)
             pos = p.pos
             #Construct 3x3 matrix with column vectors for rows
             mat = Matrix((col0, col1, col2))
             mat.transpose() # Matrix is now correct
             #Increase size from 3x3 to 4x4 to move 3D points 
             # as well as to rotate/scale them like a 3x3 could
             mat = mat.to_4x4() 
             for i in range(3):
                 mat[i][3] = pos[i]
             object.matrix_local = mat
             #object.
             #Assign 'Custom Properties' to the object with values from the Placement
             # in order to serialize the placement later
             pd = vars(p)
             for key in pd.keys():
                 object[key] = pd[key]
             #Assign the item table to the scene in order to serialize later
             bpy.data.scenes[0]['item_table'] = [l.to_list() for l in self.table_items]
             #Assign the entire 60k file to the scene
             bpy.data.scenes[0]['usermap_data'] = struct.unpack("B" * len(self.data), self.data)
    def test_matrix_inverse(self):
        mat = Matrix(((1, 4, 0, -1),
                      (2, -1, 2, -2),
                      (0, 3, 8, 3),
                      (-2, 9, 1, 0)))

        inv_mat = (1 / 285) * Matrix(((195, -57, 27, -102),
                                      (50, -19, 4, 6),
                                      (-60, 57, 18, 27),
                                      (110, -133, 43, -78)))

        self.assertEqual(mat.inverted(), inv_mat)
def get_trunk_mesh(context, prefs):
    me = context.blend_data.meshes.new("temp_mesh")
    bm = bmesh.new()
    bm.from_mesh(me)
    mat = Matrix()
    tt = prefs.lp_Tree_Type

    if tt == "lp_Tree_Oak" or tt == "lp_Tree_Pine":
        segments = get_random(prefs.lp_Tree_Trunk_Segments_Min, prefs.lp_Tree_Trunk_Segments_Max)
        trunklen = uniform(prefs.lp_Tree_Trunk_Length_Min, prefs.lp_Tree_Trunk_Length_Max)
        prefs.trunk_depth = 2.0 * trunklen
        mat.translation = (0, 0, prefs.trunk_depth / 2)
        trunk_diameter1 = 0.15 * uniform(prefs.lp_Tree_Trunk_Diameter1_Min, prefs.lp_Tree_Trunk_Diameter1_Max)
        trunk_diameter2 = 0.15 * uniform(prefs.lp_Tree_Trunk_Diameter2_Min, prefs.lp_Tree_Trunk_Diameter2_Max)
        bmesh.ops.create_cone(
            bm,
            cap_ends=False,
            cap_tris=True,
            segments=segments,
            diameter1=trunk_diameter1,
            diameter2=trunk_diameter2,
            depth=prefs.trunk_depth,
            matrix=mat,
        )
    elif tt == "lp_Tree_Palm":
        prefs.palm_stages = get_random(prefs.lp_Tree_Palm_Trunk_Stages_Min, prefs.lp_Tree_Palm_Trunk_Stages_Max)
        segments = get_random(prefs.lp_Tree_Palm_Trunk_Segments_Min, prefs.lp_Tree_Palm_Trunk_Segments_Max)
        prefs.palm_stage_length = uniform(
            prefs.lp_Tree_Palm_Trunk_Stage_Length_Min, prefs.lp_Tree_Palm_Trunk_Stage_Length_Max
        )
        stage_length = prefs.palm_stage_length
        diameter1 = uniform(prefs.lp_Tree_Palm_Trunk_Diameter1_Min, prefs.lp_Tree_Palm_Trunk_Diameter1_Max)
        diameter2 = uniform(prefs.lp_Tree_Palm_Trunk_Diameter2_Min, prefs.lp_Tree_Palm_Trunk_Diameter1_Max)
        for i in range(0, prefs.palm_stages):
            scale = 1
            mat[0][0], mat[1][1], mat[2][2] = (scale, scale, scale)
            # e = Euler((0, uniform(0, 0.2), 0), 'XYZ')
            # mat = mat * e.to_matrix().to_4x4()
            mat.translation = (0, 0, (stage_length / 2 + i * stage_length))
            bmesh.ops.create_cone(
                bm,
                cap_ends=True,
                cap_tris=True,
                segments=segments,
                diameter1=diameter1,
                diameter2=diameter2,
                depth=stage_length,
                matrix=mat,
            )
            # mat = Matrix()

    bm.to_mesh(me)
    return me
Beispiel #23
0
def make_strut(v1, v2, id, od, n, solid, loops):
    v1 = Vector(v1)
    v2 = Vector(v2)
    axis = v2 - v1
    pos = [(0, od / 2)]
    if loops:
        pos += [((od - id) / 2, od / 2),
                (axis.length - (od - id) / 2, od / 2)]
    pos += [(axis.length, od / 2)]
    if solid:
        pos += [(axis.length, id / 2)]
        if loops:
            pos += [(axis.length - (od - id) / 2, id / 2),
                    ((od - id) / 2, id / 2)]
        pos += [(0, id / 2)]
    vps = len(pos)
    fps = vps
    if not solid:
        fps -= 1
    fw = axis.copy()
    fw.normalize()
    if (abs(axis[0] / axis.length) < 1e-5
        and abs(axis[1] / axis.length) < 1e-5):
        up = Vector((-1, 0, 0))
    else:
        up = Vector((0, 0, 1))
    lf = up.cross(fw)
    lf.normalize()
    up = fw.cross(lf)
    mat = Matrix((fw, lf, up))
    mat.transpose()
    verts = [None] * n * vps
    faces = [None] * n * fps
    for i in range(n):
        base = (i - 1) * vps
        x = cossin[i][0]
        y = cossin[i][1]
        for j in range(vps):
            p = Vector((pos[j][0], pos[j][1] * x, pos[j][1] * y))
            p = mat * p
            verts[i * vps + j] = p + v1
        if i:
            for j in range(fps):
                f = (i - 1) * fps + j
                faces[f] = [base + j, base + vps + j,
                            base + vps + (j + 1) % vps, base + (j + 1) % vps]
    base = len(verts) - vps
    i = n
    for j in range(fps):
        f = (i - 1) * fps + j
        faces[f] = [base + j, j, (j + 1) % vps, base + (j + 1) % vps]
    #print(verts,faces)
    return verts, faces
Beispiel #24
0
def mirrorPlane(vertex, matrix):
    vert = []
    a = Matrix(matrix)
    eul = a.to_euler()
    normal = Vector((0.0, 0.0, 1.0))
    normal.rotate(eul)
    tras = Matrix.Translation(2*a.to_translation())
    for i in vertex:
        v = Vector(i)
        r = v.reflect(normal)
        vert.append((tras*r)[:])
    return vert
def rotation_from_matrix(m00, m01, m02, m10, m11, m12, m20, m21, m22):
    mat = Matrix()
    mat[0][0] = m00
    mat[0][1] = m01
    mat[0][2] = m02
    mat[1][0] = m10
    mat[1][1] = m11
    mat[1][2] = m12
    mat[2][0] = m20
    mat[2][1] = m21
    mat[2][2] = m22

    return mat.to_quaternion()
Beispiel #26
0
    def update(self):
        if 'vertices' in self.inputs and self.inputs['vertices'].links \
            and self.inputs['edg_pol'].links \
            and self.inputs['cut_matrix'].links:
                
        
            verts_ob = Vector_generate(SvGetSocketAnyType(self,self.inputs['vertices']))
            edg_pols_ob = SvGetSocketAnyType(self,self.inputs['edg_pol'])
            
            if self.inputs['matrix'].links:
                
                matrixs = SvGetSocketAnyType(self,self.inputs['matrix'])
            else:
                matrixs = []
                for le in verts_ob:
                    matrixs.append(Matrix())
            cut_mats = SvGetSocketAnyType(self,self.inputs['cut_matrix'])
            
            verts_out = []
            edges_out = []
            for cut_mat in cut_mats:
                cut_mat = Matrix(cut_mat)
                pp = Vector((0.0, 0.0, 0.0)) * cut_mat.transposed()
                pno = Vector((0.0, 0.0, 1.0)) * cut_mat.to_3x3().transposed()
                
                verts_pre_out = []
                edges_pre_out = []
                for idx_mob, matrix in enumerate(matrixs):
                    idx_vob = min(idx_mob, len(verts_ob)-1)
                    idx_epob = min(idx_mob, len(edg_pols_ob)-1)
                    matrix = Matrix(matrix)
                    
                    x_me = section(verts_ob[idx_vob], edg_pols_ob[idx_epob], matrix, pp, pno, self.fill_check, self.tri)
                    if x_me:
                        verts_pre_out.append(x_me['Verts'])
                        edges_pre_out.append(x_me['Edges'])
                
                if verts_pre_out:
                    verts_out.extend(verts_pre_out)
                    edges_out.extend(edges_pre_out)
            
            if 'vertices' in self.outputs and self.outputs['vertices'].links:
                output = Vector_degenerate(verts_out)
                SvSetSocketAnyType(self,'vertices',output)
            
            if 'edges' in self.outputs and self.outputs['edges'].links:

                SvSetSocketAnyType(self,'edges',edges_out) 
            
        else:
            pass
def matrix_inverted_safe(m):
    try:
        return m.inverted()
    except ValueError:
        pass
    m = Matrix()
    m.col[0][0] += 1e-6
    m.col[1][1] += 1e-6
    m.col[2][2] += 1e-6
    m.col[3][3] += 1e-6
    try:
        return m.inverted()
    except ValueError:
        return Matrix()
Beispiel #28
0
    def getWorld(self):
        t = Vector(self.translation).to_4d()
        mr = Matrix()
        for row in range(3):
            mr[row][0:3] = self.rotation[row]

        mr.transpose() # = Inverse rotation
        
        p = -(mr * t) # Camera position in world coordinates
        p[3] = 1.0

        m = mr.copy()
        m.col[3] = p # Set translation to camera position
        return m
def draw_cloud(bm, prefs, translation=(0, 0, 0)):
    mat = Matrix()
    mat.translation = translation
    smin = prefs.lp_Cloud_Scale_Min
    smax = prefs.lp_Cloud_Scale_Max
    sx = uniform(smin[0], smax[0])
    sy = uniform(smin[1], smax[1])
    sz = uniform(smin[2], smax[2])
    scale = (sx, sy, sz)
    mat[0][0], mat[1][1], mat[2][2] = scale[0], scale[1], scale[2]
    e = Euler((uniform(0, 3.14), uniform(0, 3.14), uniform(0, 3.14)), 'XYZ')
    mat = mat * e.to_matrix().to_4x4()
    bmesh.ops.create_icosphere(bm, subdivisions=prefs.lp_Cloud_Subdivisions,
                               diameter=1.0, matrix=mat)
    return scale
Beispiel #30
0
    def __getAxisAngleBasedRotation(self, rotate, translate):

        euler = Euler(rotate)

        self.logger.debug("Injecting rotation: '%s'", str(euler))

        vector_translate = Vector((translate[0], translate[1], translate[2]))

        # actually the translation is also needed to be passed here
        rotate_mtx = Matrix.to_4x4(euler.to_matrix())
        translate_mtx = Matrix.Translation(vector_translate)

        cameraMatrix = translate_mtx * rotate_mtx

        # global matrix rotate (guess it is for world coordinate system rotating)

        mtx = Matrix.Rotation(-(math.pi / 2.0), 4, 'X')
        mtx = mtx * cameraMatrix

        (loc, quat, _) = mtx.decompose()

        # get the values the way that in x3d exporter does
        quat = quat.normalized()

        # some weird stuff
        axises = list(quat.axis.to_tuple())
        angle = quat.angle

        orientation = self.__getStringRepresentation(axises) + " " + str(angle)
        translation = self.__getStringRepresentation(loc)

        return translation, orientation
Beispiel #31
0
    def execute(self, context):

        from .model import SelectModel
        from .rigid_bodies import SelectGeometry, AssignGeometry
        from .segments import SelectSegment

        C = bpy.context
        D = bpy.data

        model = C.active_object

        bone_name = C.active_bone.name
        pose_bone = C.active_object.pose.bones[bone_name]

        if not C.active_bone.parent:
            self.report({"ERROR"}, "Does not work for root segments")
            return {'CANCELLED'}

        parent_bone = C.active_object.pose.bones[C.active_bone.parent.name]
        parent_name = parent_bone.name

        parent_frame = model.matrix_world * parent_bone.matrix

        bone_world = model.matrix_world * pose_bone.matrix
        bone_to_parent = bone_world.inverted() * parent_frame
        parent_to_bone = parent_frame.inverted() * bone_world
        l = bone_to_parent.translation.length

        v1 = bone_to_parent.translation
        max_v1 = max(abs(i) for i in v1)
        v2 = parent_to_bone.translation
        max_v2 = max(abs(i) for i in v2)

        if max_v1 != 0:
            bpy.ops.curve.primitive_bezier_circle_add(radius=l / 20)
            print(l)

            bevel = C.active_object

            bezier = bpy.ops.curve.primitive_bezier_curve_add()

            bezier = C.active_object
            bezier.data.bevel_object = bevel

            bezier.matrix_world = bone_world

            print(bezier.matrix_world)
            # e= C.active_bone.RobotEditor.Euler

            bpy.ops.object.mode_set(mode="EDIT", toggle=False)

            a = bezier.data.splines[0].bezier_points[0]
            b = bezier.data.splines[0].bezier_points[1]

            a.co = (0, 0, 0)
            b.co = bone_to_parent.translation

            print(v1, max_v1)
            v1 = Vector(
                [0.1 * i / max_v1 if abs(i) == max_v1 else 0.0 for i in v1])

            v2 = Vector(
                [0.1 * i / max_v2 if abs(i) == max_v2 else 0.0 for i in v2])
            # v2 = Vector(v2)#.to_4d()
            # v2[3]=0.0

            a.handle_right = v1
            a.handle_left = -1 * v1
            print(v1, a.handle_right, a.handle_left)

            m = Matrix()
            m.translation = v2

            # m[3][3] = 0
            # b.co = (bone_to_parent *m).translation
            print(m, bone_to_parent.inverted() * parent_frame * m)
            b.handle_left = (bone_to_parent * m).translation
            m.translation = -1 * v2

            b.handle_right = (bone_to_parent * m).translation
            print(v2, b.handle_right, b.handle_left)

            # print(a.co,b.co)

            bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
            bpy.ops.object.convert(target='MESH')
            bpy.ops.object.select_all(action='DESELECT')
            bevel.select = True
            bpy.ops.object.delete()

            SelectModel.run(model_name=model.name)
            SelectGeometry.run(mesh_name=bezier.name)  #
            SelectSegment.run(segment_name=parent_name)
            AssignGeometry.run()
            SelectSegment.run(segment_name=bone_name)

        GenerateMeshFromJoint.run()

        return {'FINISHED'}
Beispiel #32
0
    def execute(self, model):

        # Set the first node as removable
        model.nodes[0].is_removable = True

        # First node seems to be off...
        model.nodes[0].bind_matrix = Matrix()

        model.nodes[0].bind_matrix[0][0] = -1.0
        model.nodes[0].bind_matrix[0][1] = 0.0
        model.nodes[0].bind_matrix[0][2] = 0.0
        model.nodes[0].bind_matrix[0][3] = 0.0

        model.nodes[0].bind_matrix[1][0] = 0.0
        model.nodes[0].bind_matrix[1][1] = -1.0
        model.nodes[0].bind_matrix[1][2] = 0.0
        model.nodes[0].bind_matrix[1][3] = -1.543487

        model.nodes[0].bind_matrix[2][0] = 0.0
        model.nodes[0].bind_matrix[2][1] = 0.0
        model.nodes[0].bind_matrix[2][2] = 1.0
        model.nodes[0].bind_matrix[2][3] = 0.0

        model.nodes[0].bind_matrix[3][0] = 0.0
        model.nodes[0].bind_matrix[3][1] = 0.0
        model.nodes[0].bind_matrix[3][2] = 0.0
        model.nodes[0].bind_matrix[3][3] = 1.0

        # Fix specular power, scale, and lod weight
        for i in range(len(model.pieces)):
            model.pieces[i].specular_power = 5.0
            model.pieces[i].specular_scale = 1.0
            model.pieces[i].lod_weight = 1.0
        '''
        This function will just create fake parts of the model
        Because LithTech needs at least something in every section!
        '''
        animation = Animation()
        animation.name = 'ConvertedFromPS2'
        animation.extents = Vector((0, 0, 0))
        animation.keyframes.append(Animation.Keyframe())
        for node_index, (node) in enumerate(model.nodes):
            transforms = list()
            for _ in animation.keyframes:
                transform = Animation.Keyframe.Transform()
                transform.matrix = node.bind_matrix
                transforms.append(transform)
            animation.node_keyframe_transforms.append(transforms)
        model.animations.append(animation)
        ''' ChildModels '''
        child_model = ChildModel()

        for _ in model.nodes:
            # This number seems to have no basis on reality, so therefore it's now a teapot.
            child_model.build_number = 418
            child_model.transforms.append(Animation.Keyframe.Transform())
        model.child_models.append(child_model)
        ''' AnimBindings '''
        anim_binding = AnimBinding()
        anim_binding.name = 'ConvertedFromPS2'
        anim_binding.origin = Vector((0, 0, 0))
        model.anim_bindings.append(anim_binding)

        # Save me some time renaming stuff..
        # PS2 doesn't have names for sockets
        human_socket_list = [
            "RightHand", "Head", "Eyes", "Back", "Nose", "Chin", "LeftHand",
            "LeftFoot", "RightFoot", "Snowmobile", "Motorcycle"
        ]

        print(len(model.sockets), len(human_socket_list))

        if len(model.sockets) == len(human_socket_list):
            for i in range(len(model.sockets)):
                model.sockets[i].name = human_socket_list[i]

        print(model.sockets[0])

        return model
 def get_matrix_local(self):
     if self._tag == 'OB':
         return self.bdata.matrix_local.copy()
     elif self._tag == 'DP':
         return self._ref.matrix_world.inverted_safe() * self._dupli_matrix
     else:  # 'BO', current pose
         # PoseBone.matrix is in armature space, bring in back in real local one!
         par = self.bdata.parent
         par_mat_inv = self._ref.pose.bones[par.name].matrix.inverted_safe() if par else Matrix()
         return par_mat_inv * self._ref.pose.bones[self.bdata.name].matrix
Beispiel #34
0
def import_motion(reader,
                  context,
                  bonesmap,
                  reported,
                  motions_filter=MOTIONS_FILTER_ALL):
    bpy_armature = context.armature
    name = reader.gets()

    if not motions_filter(name):
        skip = _skip_motion_rest(reader.getv(), 0)
        reader.skip(skip)
        return
    act = bpy.data.actions.new(name=name)
    act.use_fake_user = True
    xray = act.xray
    reader.getf('II')  # range
    fps, ver = reader.getf('fH')
    xray.fps = fps
    if ver < 6:
        raise AppError('unsupported motions version', log_props(version=ver))

    motion = bpy_armature.xray.motions_collection.add()
    motion.name = act.name
    if context.use_motion_prefix_name:
        bpy_armature.xray.use_custom_motion_names = True
        motion.export_name = name
        # cut extension
        filename = context.filename[0:-len(context.filename.split('.')[-1]) -
                                    1]
        name = '{0}_{1}'.format(filename, name)
        act.name = name
        motion.name = name

    if name != act.name and not context.use_motion_prefix_name:
        bpy_armature.xray.use_custom_motion_names = True
        motion.export_name = name

    xray.flags, xray.bonepart = reader.getf('<BH')
    xray.speed, xray.accrue, xray.falloff, xray.power = reader.getf('<ffff')
    for _bone_idx in range(reader.getf('H')[0]):
        tmpfc = [act.fcurves.new('temp', index=i) for i in range(6)]
        try:
            times = {}
            bname = reader.gets()
            flags = reader.getf('B')[0]
            if flags != 0:
                warn('bone has non-zero flags', bone=bname, flags=flags)
            for fcurve in tmpfc:
                behaviors = reader.getf('BB')
                if (behaviors[0] != 1) or (behaviors[1] != 1):
                    warn('bone has different behaviors',
                         bode=bname,
                         behaviors=behaviors)
                for _keyframe_idx in range(reader.getf('H')[0]):
                    val = reader.getf('f')[0]
                    time = reader.getf('f')[0] * fps
                    times[time] = True
                    key_frame = fcurve.keyframe_points.insert(time, val)
                    shape = Shape(reader.getf('B')[0])
                    if shape != Shape.STEPPED:
                        reader.getf('HHH')
                        reader.getf('HHHH')
                    else:
                        key_frame.interpolation = 'CONSTANT'
            bpy_bone = bpy_armature.data.bones.get(bname, None)
            if bpy_bone is None:
                bpy_bone = bonesmap.get(bname.lower(), None)
                if bpy_bone is None:
                    if bname not in reported:
                        warn('bone is not found', bone=bname)
                        reported.add(bname)
                    continue
                if bname not in reported:
                    warn('bone\'s reference will be replaced',
                         bone=bname,
                         replacement=bpy_bone.name)
                    reported.add(bname)
                bname = bpy_bone.name
            data_path = 'pose.bones["' + bname + '"]'
            fcs = [
                act.fcurves.new(data_path + '.location',
                                index=0,
                                action_group=bname),
                act.fcurves.new(data_path + '.location',
                                index=1,
                                action_group=bname),
                act.fcurves.new(data_path + '.location',
                                index=2,
                                action_group=bname),
                act.fcurves.new(data_path + '.rotation_euler',
                                index=0,
                                action_group=bname),
                act.fcurves.new(data_path + '.rotation_euler',
                                index=1,
                                action_group=bname),
                act.fcurves.new(data_path + '.rotation_euler',
                                index=2,
                                action_group=bname)
            ]
            xmat = bpy_bone.matrix_local.inverted()
            real_parent = find_bone_exportable_parent(bpy_bone)
            if real_parent:
                xmat = multiply(xmat, real_parent.matrix_local)
            else:
                xmat = multiply(xmat, MATRIX_BONE)
            for time in times:
                mat = multiply(
                    xmat,
                    Matrix.Translation((
                        +tmpfc[0].evaluate(time),
                        +tmpfc[1].evaluate(time),
                        -tmpfc[2].evaluate(time),
                    )),
                    Euler((
                        -tmpfc[4].evaluate(time),
                        -tmpfc[3].evaluate(time),
                        +tmpfc[5].evaluate(time),
                    ), 'ZXY').to_matrix().to_4x4())
                trn = mat.to_translation()
                rot = mat.to_euler('ZXY')
                for i in range(3):
                    fcs[i + 0].keyframe_points.insert(time, trn[i])
                for i in range(3):
                    fcs[i + 3].keyframe_points.insert(time, rot[i])
        finally:
            for fcurve in tmpfc:
                act.fcurves.remove(fcurve)
    if ver >= 7:
        for _bone_idx in range(reader.getf('I')[0]):
            name = reader.gets_a()
            reader.skip((4 + 4) * reader.getf('I')[0])
            warn('markers are not supported yet', name=name)
    return act
 def __matrix_compose(loc, rot, scale):
     return (Matrix.Translation(loc) * rot.to_matrix().to_4x4() *
             Matrix.Scale(scale[0], 4, (1, 0, 0)) *
             Matrix.Scale(scale[1], 4,
                          (0, 1, 0)) * Matrix.Scale(scale[2], 4, (0, 0, 1)))
FBX_DEFORMER_SHAPE_VERSION = 100
FBX_DEFORMER_SHAPECHANNEL_VERSION = 100
FBX_POSE_BIND_VERSION = 100
FBX_DEFORMER_SKIN_VERSION = 101
FBX_DEFORMER_CLUSTER_VERSION = 100
FBX_MATERIAL_VERSION = 102
FBX_TEXTURE_VERSION = 202
FBX_ANIM_KEY_VERSION = 4008

FBX_NAME_CLASS_SEP = b"\x00\x01"
FBX_ANIM_PROPSGROUP_NAME = "d"

FBX_KTIME = 46186158000  # This is the number of "ktimes" in one second (yep, precision over the nanosecond...)


MAT_CONVERT_LAMP = Matrix.Rotation(math.pi / 2.0, 4, 'X')  # Blender is -Z, FBX is -Y.
MAT_CONVERT_CAMERA = Matrix.Rotation(math.pi / 2.0, 4, 'Y')  # Blender is -Z, FBX is +X.
# XXX I can't get this working :(
# MAT_CONVERT_BONE = Matrix.Rotation(math.pi / 2.0, 4, 'Z')  # Blender is +Y, FBX is -X.
MAT_CONVERT_BONE = Matrix()


BLENDER_OTHER_OBJECT_TYPES = {'CURVE', 'SURFACE', 'FONT', 'META'}
BLENDER_OBJECT_TYPES_MESHLIKE = {'MESH'} | BLENDER_OTHER_OBJECT_TYPES


# Lamps.
FBX_LIGHT_TYPES = {
    'POINT': 0,  # Point.
    'SUN': 1,    # Directional.
    'SPOT': 2,   # Spot.
    ("Y", -45.0),
    ("Y", -22.5),
#    ("Y",   0.0), 0 rotation, default to x
    ("Y",  22.5),
    ("Y",  45.0),
    ("Z", -45.0),
    ("Z", -22.5),
#    ("Z",   0.0), 0 rotation, default to x
    ("Z",  22.5),
    ("Z",  45.0),
]

# generate all rotation matrices (15x3x3)
MAT_ROTATIONS = np.zeros((len(ROTATIONS), 3, 3))
for i, r in enumerate(ROTATIONS):
    MAT_ROTATIONS[i,:,:] = np.array(Matrix.Rotation(math.radians(r[1]), 3, r[0]))

# direction names for minecraft cube face UVs
DIRECTIONS = np.array([
    "north",
    "east",
    "west",
    "south",
    "up",
    "down",
])

# normals for minecraft directions in BLENDER world space
# e.g. blender (-1, 0, 0) is minecraft north (0, 0, -1)
# shape (f,n) = (6,3)
#   f = 6: number of cuboid faces to test
Beispiel #38
0
import bpy
from mathutils import Matrix, Euler, Quaternion

from .utils import is_exportable_bone, find_bone_exportable_parent, AppError
from .xray_envelope import Behavior, Shape, KF, EPSILON, refine_keys, export_keyframes
from .xray_io import PackedWriter, FastBytes as fb
from .log import warn, with_context, props as log_props
from .version_utils import multiply

MATRIX_BONE = Matrix(((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, -1.0, 0.0),
                      (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0))).freeze()
MATRIX_BONE_INVERTED = MATRIX_BONE.inverted().freeze()

MOTIONS_FILTER_ALL = lambda name: True


@with_context('import-motion')
def import_motion(reader,
                  context,
                  bonesmap,
                  reported,
                  motions_filter=MOTIONS_FILTER_ALL):
    bpy_armature = context.armature
    name = reader.gets()

    if not motions_filter(name):
        skip = _skip_motion_rest(reader.getv(), 0)
        reader.skip(skip)
        return
    act = bpy.data.actions.new(name=name)
    act.use_fake_user = True
Beispiel #39
0
 def setOrigin(self, origin):
     terrain = self.terrain
     # see http://blender.stackexchange.com/questions/35825/changing-object-origin-to-arbitrary-point-without-origin-set
     offset = origin - terrain.matrix_world.translation
     terrain.data.transform(Matrix.Translation(-offset))
     terrain.matrix_world.translation += offset
    def load(self, context, **options):
        """load a sketchup file"""

        self.context = context
        self.reuse_material = options['reuse_material']
        self.reuse_group = options['reuse_existing_groups']
        self.max_instance = options['max_instance']
        self.render_engine = options['render_engine']
        self.component_stats = defaultdict(list)
        self.component_skip = proxy_dict()
        self.component_depth = proxy_dict()
        self.group_written = {}
        ren_res_x = context.scene.render.resolution_x
        ren_res_y = context.scene.render.resolution_y
        self.aspect_ratio = ren_res_x / ren_res_y

        skp_log(f'Importing: {self.filepath}')

        addon_name = __name__.split('.')[0]
        self.prefs = context.preferences.addons[addon_name].preferences

        _time_main = time.time()

        try:
            self.skp_model = sketchup.Model.from_file(self.filepath)
        except Exception as e:
            skp_log(f'Error reading input file: {self.filepath}')
            skp_log(e)
            return {'FINISHED'}

        if options['import_scene']:
            for s in self.skp_model.scenes:
                if s.name == options['import_scene']:
                    skp_log(f"Importing Scene '{s.name}'")
                    self.scene = s
                    self.layers_skip = [l for l in s.layers]
                    for l in s.layers:
                        skp_log(f"SKIP: {l.name}")
            if not self.layers_skip:
                skp_log('Could not find scene: {}, importing default.'.format(
                    options['import_scene']))

        if not self.layers_skip:
            self.layers_skip = [
                l for l in self.skp_model.layers if not l.visible
            ]

        skp_log('Skipping Layers ... ')

        for l in sorted([l.name for l in self.layers_skip]):
            skp_log(l)

        self.skp_components = proxy_dict(
            self.skp_model.component_definition_as_dict)

        skp_log(f'Parsed in {(time.time() - _time_main):.4f} sec.')

        if options['scenes_as_camera']:
            for s in self.skp_model.scenes:
                self.write_camera(s.camera, s.name)

        if options['import_camera']:
            if self.scene:
                active_cam = self.write_camera(self.scene.camera,
                                               name=self.scene.name)
                context.scene.camera = active_cam
            else:
                active_cam = self.write_camera(self.skp_model.camera)
                context.scene.camera = active_cam

        _t1 = time.time()
        self.write_materials(self.skp_model.materials)

        skp_log(f'Materials imported in {(time.time() - _t1):.4f} sec.')

        _t1 = time.time()
        D = SKP_util()
        SKP_util.layers_skip = self.layers_skip

        for c in self.skp_model.component_definitions:
            self.component_depth[c.name] = D.component_deps(c.entities)

        skp_log(f'Component depths analyzed in {(time.time() - _t1):.4f} sec.')

        self.write_duplicateable_groups()

        if options["dedub_only"]:
            return {'FINISHED'}

        self.component_stats = defaultdict(list)
        self.write_entities(self.skp_model.entities, "Sketchup",
                            Matrix.Identity(4))

        for k, _v in self.component_stats.items():
            name, mat = k
            if options['dedub_type'] == "VERTEX":
                self.instance_group_dupli_vert(name, mat, self.component_stats)
            else:
                self.instance_group_dupli_face(name, mat, self.component_stats)

        skp_log(f'Entities imported in {(time.time() - _t1):.4f} sec.')
        skp_log('Finished importing in %.4f sec.\n' %
                (time.time() - _time_main))

        return {'FINISHED'}
    def instance_group_dupli_face(self, name, default_material,
                                  component_stats):
        def get_orientations(v):

            orientations = defaultdict(list)

            for transform in v:
                _loc, _rot, scale = Matrix(transform).decompose()
                scale = (scale[0], scale[1], scale[2])
                orientations[scale].append(transform)

            for scale, transforms in orientations.items():
                yield scale, transforms

        for _scale, transforms in get_orientations(
                component_stats[(name, default_material)]):
            main_loc, _, real_scale = Matrix(transforms[0]).decompose()
            verts = []
            faces = []
            f_count = 0

            for c in transforms:
                l_loc, l_rot, _l_scale = Matrix(c).decompose()
                mat = Matrix.Translation(l_loc) * l_rot.to_matrix().to_4x4()

                verts.append(
                    Vector((mat * Vector((-0.05, -0.05, 0, 1.0)))[0:3]) -
                    main_loc)
                verts.append(
                    Vector((mat * Vector((0.05, -0.05, 0, 1.0)))[0:3]) -
                    main_loc)
                verts.append(
                    Vector((mat * Vector((0.05, 0.05, 0, 1.0)))[0:3]) -
                    main_loc)
                verts.append(
                    Vector((mat * Vector((-0.05, 0.05, 0, 1.0)))[0:3]) -
                    main_loc)

                faces.append(
                    (f_count + 0, f_count + 1, f_count + 2, f_count + 3))

                f_count += 4

            dme = bpy.data.meshes.new('DUPLI_' + name)
            dme.vertices.add(len(verts))
            dme.vertices.foreach_set("co", unpack_list(verts))

            dme.tessfaces.add(f_count / 4)
            dme.tessfaces.foreach_set("vertices_raw", unpack_face_list(faces))
            dme.update(calc_edges=True)  # Update mesh with new data
            dme.validate()
            dob = bpy.data.objects.new("DUPLI_" + name, dme)
            dob.dupli_type = 'FACES'
            dob.location = main_loc
            #dob.use_dupli_faces_scale = True
            #dob.dupli_faces_scale = 10

            ob = self.instance_object_or_group(name, default_material)
            ob.scale = real_scale
            ob.parent = dob
            self.context.scene.objects.link(ob)
            self.context.scene.objects.link(dob)
            skp_log("Complex group {} {} instanced {} times".format(
                name, default_material, f_count / 4))

        return
 def deserializePoseVector(vec4):
     m = Matrix.Identity(4)
     for i in range(4):
         m[i][3] = vec4[i]
     return m
Beispiel #43
0
def _get_bone_channels(scs_root_obj, armature, scs_animation, action,
                       export_scale):
    """Takes armature and action and returns bone channels.
    bone_channels structure example:
    [("Bone", [("_TIME", [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]), ("_MATRIX", [])])]"""
    bone_channels = []
    frame_start = scs_animation.anim_start
    frame_end = scs_animation.anim_end
    anim_export_step = action.scs_props.anim_export_step
    total_frames = (frame_end - frame_start) / anim_export_step

    # armature matrix stores transformation of armature object against scs root
    # and has to be added to all bones as they only armature space transformations
    armature_mat = scs_root_obj.matrix_world.inverted() @ armature.matrix_world

    invalid_data = False  # flag to indicate invalid data state
    curves_per_bone = OrderedDict(
    )  # store all the curves we are interested in per bone names

    for bone in armature.data.bones:
        for fcurve in action.fcurves:

            # check if curve belongs to bone
            if '["' + bone.name + '"]' in fcurve.data_path:

                data_path = fcurve.data_path
                array_index = fcurve.array_index

                if data_path.endswith("location"):
                    curve_type = "location"
                elif data_path.endswith("rotation_euler"):
                    curve_type = "euler_rotation"
                elif data_path.endswith("rotation_quaternion"):
                    curve_type = "quat_rotation"
                elif data_path.endswith("scale"):
                    curve_type = "scale"
                else:
                    curve_type = None

                # write only recognized curves
                if curve_type is not None:
                    if bone.name not in curves_per_bone:
                        curves_per_bone[bone.name] = {
                            "location": {},
                            "euler_rotation": {},
                            "quat_rotation": {},
                            "scale": {}
                        }

                    curves_per_bone[
                        bone.name][curve_type][array_index] = fcurve

    for bone_name, bone_curves in curves_per_bone.items():

        bone = armature.data.bones[bone_name]
        pose_bone = armature.pose.bones[bone_name]
        loc_curves = bone_curves["location"]
        euler_rot_curves = bone_curves["euler_rotation"]
        quat_rot_curves = bone_curves["quat_rotation"]
        sca_curves = bone_curves["scale"]

        bone_rest_mat = armature_mat @ bone.matrix_local
        if bone.parent:
            parent_bone_rest_mat = (
                Matrix.Scale(export_scale, 4)
                @ _convert_utils.scs_to_blend_matrix().inverted()
                @ armature_mat @ bone.parent.matrix_local)
        else:
            parent_bone_rest_mat = Matrix()

        # GO THOUGH FRAMES
        actual_frame = frame_start
        timings_stream = []
        matrices_stream = []
        while actual_frame <= frame_end:
            mat_loc = Matrix()
            mat_rot = Matrix()
            mat_sca = Matrix()

            # LOCATION MATRIX
            if len(loc_curves) > 0:
                location = Vector()
                for index in range(3):
                    if index in loc_curves:
                        location[index] = loc_curves[index].evaluate(
                            actual_frame)
                mat_loc = Matrix.Translation(location)

            # ROTATION MATRIX
            if len(euler_rot_curves) > 0:
                rotation = Euler()
                for index in range(3):
                    if index in euler_rot_curves:
                        rotation[index] = euler_rot_curves[index].evaluate(
                            actual_frame)
                mat_rot = Euler(rotation, pose_bone.rotation_mode).to_matrix(
                ).to_4x4()  # calc rotation by pose rotation mode

            elif len(quat_rot_curves) > 0:
                rotation = Quaternion()
                for index in range(4):
                    if index in quat_rot_curves:
                        rotation[index] = quat_rot_curves[index].evaluate(
                            actual_frame)
                mat_rot = rotation.to_matrix().to_4x4()

            # SCALE MATRIX
            if len(sca_curves) > 0:
                scale = Vector((1.0, 1.0, 1.0))
                for index in range(3):
                    if index in sca_curves:
                        scale[index] = sca_curves[index].evaluate(actual_frame)

                        if scale[index] < 0:
                            lprint(
                                str("E Negative scale detected on bone %r:\n\t   "
                                    "(Action: %r, keyframe no.: %s, SCS Animation: %r)."
                                    ), (bone_name, action.name, actual_frame,
                                        scs_animation.name))
                            invalid_data = True

                mat_sca = Matrix()
                mat_sca[0] = (scale[0], 0, 0, 0)
                mat_sca[1] = (0, scale[1], 0, 0)
                mat_sca[2] = (0, 0, scale[2], 0)
                mat_sca[3] = (0, 0, 0, 1)

            # BLENDER FRAME MATRIX
            mat = mat_loc @ mat_rot @ mat_sca

            # SCALE REMOVAL MATRIX
            rest_location, rest_rotation, rest_scale = bone_rest_mat.decompose(
            )
            # print(' BONES rest_scale: %s' % str(rest_scale))
            rest_scale = rest_scale * export_scale
            scale_removal_matrix = Matrix()
            scale_removal_matrix[0] = (1.0 / rest_scale[0], 0, 0, 0)
            scale_removal_matrix[1] = (0, 1.0 / rest_scale[1], 0, 0)
            scale_removal_matrix[2] = (0, 0, 1.0 / rest_scale[2], 0)
            scale_removal_matrix[3] = (0, 0, 0, 1)

            # SCALE MATRIX
            scale_matrix = Matrix.Scale(export_scale, 4)

            # COMPUTE SCS FRAME MATRIX
            frame_matrix = (parent_bone_rest_mat.inverted()
                            @ _convert_utils.scs_to_blend_matrix().inverted()
                            @ scale_matrix.inverted() @ bone_rest_mat @ mat
                            @ scale_removal_matrix.inverted())

            # print('          actual_frame: %s - value: %s' % (actual_frame, frame_matrix))
            timings_stream.append(
                ("__time__", scs_animation.length / total_frames), )
            matrices_stream.append(("__matrix__", frame_matrix.transposed()), )
            actual_frame += anim_export_step

        anim_timing = ("_TIME", timings_stream)
        anim_matrices = ("_MATRIX", matrices_stream)
        bone_anim = (anim_timing, anim_matrices)
        bone_data = (bone_name, bone_anim)
        bone_channels.append(bone_data)

    # return empty bone channels if data are invalid
    if invalid_data:
        return []

    return bone_channels
def __gather_children(blender_object, blender_scene, export_settings):
    children = []
    # standard children
    for child_object in blender_object.children:
        if child_object.parent_bone:
            # this is handled further down,
            # as the object should be a child of the specific bone,
            # not the Armature object
            continue
        node = gather_node(child_object, blender_scene, export_settings)
        if node is not None:
            children.append(node)
    # blender dupli objects
    if bpy.app.version < (2, 80, 0):
        if blender_object.dupli_type == 'GROUP' and blender_object.dupli_group:
            for dupli_object in blender_object.dupli_group.objects:
                node = gather_node(dupli_object, blender_scene, export_settings)
                if node is not None:
                    children.append(node)
    else:
        if blender_object.instance_type == 'COLLECTION' and blender_object.instance_collection:
            for dupli_object in blender_object.instance_collection.objects:
                node = gather_node(dupli_object, blender_scene, export_settings)
                if node is not None:
                    children.append(node)

    # blender bones
    if blender_object.type == "ARMATURE":
        root_joints = []
        for blender_bone in blender_object.pose.bones:
            if not blender_bone.parent:
                joint = gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)
                children.append(joint)
                root_joints.append(joint)
        # handle objects directly parented to bones
        direct_bone_children = [child for child in blender_object.children if child.parent_bone]
        def find_parent_joint(joints, name):
            for joint in joints:
                if joint.name == name:
                    return joint
                parent_joint = find_parent_joint(joint.children, name)
                if parent_joint:
                    return parent_joint
            return None
        for child in direct_bone_children:
            # find parent joint
            parent_joint = find_parent_joint(root_joints, child.parent_bone)
            if not parent_joint:
                continue
            child_node = gather_node(child, None, export_settings)
            if child_node is None:
                continue
            blender_bone = blender_object.pose.bones[parent_joint.name]
            # fix rotation
            if export_settings[gltf2_blender_export_keys.YUP]:
                rot = child_node.rotation
                if rot is None:
                    rot = [0, 0, 0, 1]

                rot_quat = Quaternion(rot)
                axis_basis_change = Matrix(
                    ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, -1.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0)))
                mat = gltf2_blender_math.multiply(axis_basis_change, child.matrix_basis)
                mat = gltf2_blender_math.multiply(child.matrix_parent_inverse, mat)

                _, rot_quat, _ = mat.decompose()
                child_node.rotation = [rot_quat[1], rot_quat[2], rot_quat[3], rot_quat[0]]

            # fix translation (in blender bone's tail is the origin for children)
            trans, _, _ = child.matrix_local.decompose()
            if trans is None:
                trans = [0, 0, 0]
            # bones go down their local y axis
            bone_tail = [0, blender_bone.length, 0]
            child_node.translation = [trans[idx] + bone_tail[idx] for idx in range(3)]

            parent_joint.children.append(child_node)

    return children
def array_to_matrix4(arr):
    """Convert a single 16-len tuple into a valid 4D Blender matrix"""
    # Blender matrix is row major, fbx is col major so transpose on read
    return Matrix(tuple(zip(*[iter(arr)]*4))).transposed()
Beispiel #46
0
 def __matrix_compose(loc, rot, scale):
     return matmul(
         matmul(Matrix.Translation(loc),
                rot.to_matrix().to_4x4()),
         Matrix([(scale[0], 0, 0, 0), (0, scale[1], 0, 0),
                 (0, 0, scale[2], 0), (0, 0, 0, 1)]))
    def fbx_object_matrix(self, scene_data, rest=False, local_space=False, global_space=False):
        """
        Generate object transform matrix (*always* in matching *FBX* space!).
        If local_space is True, returned matrix is *always* in local space.
        Else if global_space is True, returned matrix is always in world space.
        If both local_space and global_space are False, returned matrix is in parent space if parent is valid,
        else in world space.
        Note local_space has precedence over global_space.
        If rest is True and object is a Bone, returns matching rest pose transform instead of current pose one.
        Applies specific rotation to bones, lamps and cameras (conversion Blender -> FBX).
        """
        # Objects which are not bones and do not have any parent are *always* in global space
        # (unless local_space is True!).
        is_global = (not local_space and
                     (global_space or not (self._tag in {'DP', 'BO'} or self.has_valid_parent(scene_data.objects))))

        # Objects (meshes!) parented to armature are not parented to anything in FBX, hence we need them
        # in global space, which is their 'virtual' local space...
        is_global = is_global or self.parented_to_armature

        # Since we have to apply corrections to some types of object, we always need local Blender space here...
        matrix = self.matrix_rest_local if rest else self.matrix_local
        parent = self.parent

        # Bones, lamps and cameras need to be rotated (in local space!).
        if self._tag == 'BO':
            # If we have a bone parent we need to undo the parent correction.
            if not is_global and scene_data.settings.bone_correction_matrix_inv and parent and parent.is_bone:
                matrix = scene_data.settings.bone_correction_matrix_inv * matrix
            # Apply the bone correction.
            if scene_data.settings.bone_correction_matrix:
                matrix = matrix * scene_data.settings.bone_correction_matrix
        elif self.bdata.type == 'LAMP':
            matrix = matrix * MAT_CONVERT_LAMP
        elif self.bdata.type == 'CAMERA':
            matrix = matrix * MAT_CONVERT_CAMERA

        if self._tag in {'DP', 'OB'} and parent:
            if parent._tag == 'BO':
                # In bone parent case, we get transformation in **bone tip** space (sigh).
                # Have to bring it back into bone root, which is FBX expected value.
                matrix = Matrix.Translation((0, (parent.bdata.tail - parent.bdata.head).length, 0)) * matrix

        # Our matrix is in local space, time to bring it in its final desired space.
        if parent:
            if is_global:
                # Move matrix to global Blender space.
                matrix = (parent.matrix_rest_global if rest else parent.matrix_global) * matrix
            elif parent.use_bake_space_transform(scene_data):
                # Blender's and FBX's local space of parent may differ if we use bake_space_transform...
                # Apply parent's *Blender* local space...
                matrix = (parent.matrix_rest_local if rest else parent.matrix_local) * matrix
                # ...and move it back into parent's *FBX* local space.
                par_mat = parent.fbx_object_matrix(scene_data, rest=rest, local_space=True)
                matrix = par_mat.inverted_safe() * matrix

        if self.use_bake_space_transform(scene_data):
            # If we bake the transforms we need to post-multiply inverse global transform.
            # This means that the global transform will not apply to children of this transform.
            matrix = matrix * scene_data.settings.global_matrix_inv
        if is_global:
            # In any case, pre-multiply the global matrix to get it in FBX global space!
            matrix = scene_data.settings.global_matrix * matrix

        return matrix
Beispiel #48
0
    def execute(self, context):

        from .model import SelectModel
        from .rigid_bodies import SelectGeometry, AssignGeometry
        from .segments import SelectSegment

        C = bpy.context
        D = bpy.data

        model = C.active_object

        bone_name = C.active_bone.name
        axis = C.active_bone.RobotEditor.axis
        pose_bone = C.active_object.pose.bones[bone_name]
        parent_bone = pose_bone.parent
        bone_to_parent = pose_bone.matrix.inverted() * parent_bone.matrix
        bone_world = model.matrix_world * pose_bone.matrix

        segment_length = bone_to_parent.translation.length
        distance_to_children = [
            (child.matrix.inverted() * pose_bone.matrix).translation.length
            for child in pose_bone.children
        ]

        self.logger.debug("%s, %s", segment_length, distance_to_children)

        # if there is no translation to parent, the parent (or its parent) draws the joint
        if bone_to_parent.translation.length > 0.001:

            max_length = max(distance_to_children + [segment_length])
            # If there is only one children, and its a distance 0, we have a ball joint
            if len(pose_bone.children
                   ) == 1 and distance_to_children[0] < 0.001:

                bpy.ops.mesh.primitive_uv_sphere_add(size=segment_length /
                                                     15.0)
                C.active_object.matrix_world = bone_world
            # if there IS a child, at distance >0 (or more than one child), draw a hinge joint
            elif len(pose_bone.children):
                bpy.ops.mesh.primitive_cylinder_add(radius=max_length / 15,
                                                    depth=max_length / 5)
                if axis == 'X':
                    m = Euler((0, 0, pi / 4)).to_matrix().to_4x4()
                elif axis == 'Y':
                    m = Euler((0, 0, pi / 4)).to_matrix().to_4x4()
                else:
                    m = Matrix()

                C.active_object.matrix_world = bone_world * m
            else:
                bpy.ops.mesh.primitive_cone_add(radius1=segment_length / 10,
                                                radius2=segment_length / 10)

            C.active_object.name = bone_name + '_axis'
            new_name = C.active_object.name
            SelectModel.run(model_name=model.name)
            SelectSegment.run(bone_name)
            SelectGeometry.run(new_name)
            AssignGeometry.run()

        return {'FINISHED'}
    def conponent_def_as_group(self,
                               entities,
                               name,
                               parent_tranform,
                               default_material="Material",
                               etype=None,
                               group=None):

        if etype == EntityType.outer:
            if (name, default_material) in self.component_skip:
                return
            else:
                skp_log("Write instance definition as group {} {}".format(
                    group.name, default_material))
                self.component_skip[(name, default_material)] = True

        if etype == EntityType.component and (
                name, default_material) in self.component_skip:
            ob = self.instance_object_or_group(name, default_material)
            ob.matrix_world = parent_tranform
            self.context.scene.objects.link(ob)
            ob.layers = 18 * [False] + [True] + [False]
            group.objects.link(ob)

            return

        else:
            me, alpha = self.write_mesh_data(entities=entities,
                                             name=name,
                                             default_material=default_material)

        if me:
            ob = bpy.data.objects.new(name, me)
            ob.matrix_world = parent_tranform
            if alpha:
                ob.show_transparent = True
            me.update(calc_edges=True)
            self.context.scene.objects.link(ob)
            ob.layers = 18 * [False] + [True] + [False]
            group.objects.link(ob)

        for g in entities.groups:
            if self.layers_skip and g.layer in self.layers_skip:
                continue
            self.conponent_def_as_group(g.entities,
                                        "G-" + g.name,
                                        parent_tranform @ Matrix(g.transform),
                                        default_material=inherent_default_mat(
                                            g.material, default_material),
                                        etype=EntityType.group,
                                        group=group)

        for instance in entities.instances:
            if self.layers_skip and instance.layer in self.layers_skip:
                continue
            cdef = self.skp_components[instance.definition.name]
            self.conponent_def_as_group(
                cdef.entities,
                cdef.name,
                parent_tranform @ Matrix(instance.transform),
                default_material=inherent_default_mat(instance.material,
                                                      default_material),
                etype=EntityType.component,
                group=group)
    def render(self, context):
        # needed???
        if context.region.id == self.region_id:
            # just hide the cursor...
            context.space_data.cursor_location = [0.0, 0.0, 10.0]
            context.space_data.region_3d.view_matrix = Matrix.Identity(4)

            w = context.region.width
            h = context.region.height

            x1, x2, x3, x4, y1, y2, y3, y4 = self.grid(w, h)

            bgl.glMatrixMode(bgl.GL_PROJECTION)
            bgl.glLoadIdentity()
            bgl.gluOrtho2D(0, w, 0, h)
            bgl.glMatrixMode(bgl.GL_MODELVIEW)
            bgl.glLoadIdentity()

            bgl.glColor3f(*self.COLOR_BOARD)
            bgl.glLineWidth(2.0)
            bgl.glBegin(bgl.GL_LINES)
            for x in (x1, x2, x3, x4):
                bgl.glVertex3f(x, y1, 0.0)
                bgl.glVertex3f(x, y4, 0.0)
            for y in (y1, y2, y3, y4):
                bgl.glVertex3f(x1, y, 0.0)
                bgl.glVertex3f(x4, y, 0.0)
            bgl.glEnd()

            xs = (x1, x2, x3, x4)
            ys = (y1, y2, y3, y4)

            bgl.glLineWidth(8.0)
            bgl.glBegin(bgl.GL_LINES)
            for i in range(3):
                for j in range(3):
                    c = self.board[i][j]
                    xa = xs[i]
                    xb = xs[i + 1]
                    ya = ys[j]
                    yb = ys[j + 1]

                    if c == self.PLAYER:
                        if self.computer_has_x:
                            self.drawO(xa, xb, ya, yb)
                        else:
                            self.drawX(xa, xb, ya, yb)
                    elif c == self.COMPUTER:
                        if self.computer_has_x:
                            self.drawX(xa, xb, ya, yb)
                        else:
                            self.drawO(xa, xb, ya, yb)
            bgl.glEnd()

            bgl.glLineWidth(1.0)
            bgl.glColor3f(*self.COLOR_FONT)

            xp, yp = self.fontPosition(w, h)
            blf.position(0, xp, yp, 0)
            blf.size(0, 50, 72)

            if self.winner == self.COMPUTER:
                blf.draw(0, "You loose!")

            elif self.winner == self.PLAYER:
                blf.draw(0, "You win!")

            elif self.round == self.NONE:
                blf.draw(0, "Draw.")
Beispiel #51
0
def rotate(co):
    """
    Set the human orientation in reference to the camera orientation.
    """

    ow = co.owner

    # get the suffix of the human to reference the right objects
    suffix = ow.name[-4:] if ow.name[-4] == "." else ""

    keyboard = co.sensors['All_Keys']
    scene = blenderapi.scene()
    human_pos = co.owner
    pos = scene.objects['POS_EMPTY' + suffix]
    active_camera = scene.active_camera

    # if the human is external, do nothing
    if human_pos.get(
            'External_Robot_Tag') or human_pos['disable_keyboard_control']:
        return

    if human_pos['move_cameraFP'] and active_camera.name != ('Human_Camera' +
                                                             suffix):
        return

    keylist = keyboard.events

    k = []  #initiate a list with all currently pressed keys
    for key in keylist:
        if key[1] == blenderapi.input_active():
            k.append(key[0])  # add all pressed keys to a list - as ASCII CODES

    pos.worldPosition = ow.worldPosition

    # Get active camera
    scene = blenderapi.scene()
    active_camera = scene.active_camera

    if ow['Manipulate']:
        ow.worldOrientation = pos.worldOrientation
        # lock camera to head in Manipulation Mode
    else:
        if FORWARDS in k and not (LEFT in k or RIGHT in k):
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(pos.worldOrientation, ow)
            else:
                applyrotate(human_pos.worldOrientation, ow)
        elif LEFT in k and not (FORWARDS in k or BACKWARDS in k):
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(
                    pos.worldOrientation *
                    Matrix.Rotation(math.pi / 2, 3, 'Z'), ow)
            else:
                applyrotate(
                    human_pos.worldOrientation *
                    Matrix.Rotation(math.pi / 2, 3, 'Z'), ow)
            # turn around 90 deg
        elif RIGHT in k and not (FORWARDS in k or BACKWARDS in k):
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(
                    pos.worldOrientation *
                    Matrix.Rotation(math.pi * 3 / 2, 3, 'Z'), ow)
            else:
                applyrotate(
                    human_pos.worldOrientation *
                    Matrix.Rotation(math.pi * 3 / 2, 3, 'Z'), ow)
            # turn around 270 deg
        elif LEFT in k and FORWARDS in k:
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(
                    pos.worldOrientation *
                    Matrix.Rotation(math.pi / 4, 3, 'Z'), ow)
            else:
                applyrotate(
                    human_pos.worldOrientation *
                    Matrix.Rotation(math.pi / 4, 3, 'Z'), ow)
            # turn around 45 deg
        elif RIGHT in k and FORWARDS in k:
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(
                    pos.worldOrientation *
                    Matrix.Rotation(math.pi * 7 / 4, 3, 'Z'), ow)
            else:
                applyrotate(
                    human_pos.worldOrientation *
                    Matrix.Rotation(math.pi * 7 / 4, 3, 'Z'), ow)
            # turn around 315 deg
        elif BACKWARDS in k and not (LEFT in k or RIGHT in k):
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(
                    pos.worldOrientation * Matrix.Rotation(math.pi, 3, 'Z'),
                    ow)
            # turn around 180 deg if in game-mode
        elif LEFT in k and BACKWARDS in k:
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(
                    pos.worldOrientation *
                    Matrix.Rotation(math.pi * 3 / 4, 3, 'Z'), ow)
            else:
                applyrotate(
                    human_pos.worldOrientation *
                    Matrix.Rotation(math.pi / 4, 3, 'Z'), ow)
            # turn around 135 deg if in game-mode, else turn 45 deg
        elif RIGHT in k and BACKWARDS in k:
            if active_camera.name == ("Human_Camera" + suffix):
                applyrotate(
                    pos.worldOrientation *
                    Matrix.Rotation(math.pi * 5 / 4, 3, 'Z'), ow)
            else:
                applyrotate(
                    human_pos.worldOrientation *
                    Matrix.Rotation(math.pi * 7 / 4, 3, 'Z'), ow)
Beispiel #52
0
    def import_dXtree(field, lvl=0):
        tab = ' ' * lvl * 2
        if field == []:
            if show_geninfo: print('%s>> no childs, return False' % (tab))
            return False
        ob = False
        mat = False
        is_root = False
        frames = []
        obs = []

        parentname = tokens[field[0]]['parent']
        if show_geninfo: print('%s>>childs in frame %s :' % (tab, parentname))

        for tokenname in field:

            tokentype = tokens[tokenname]['type']

            # frames can contain more than one mesh
            if tokentype == 'mesh':
                # object and mesh naming :
                # if parent frame has several meshes : obname = meshname = mesh token name,
                # if parent frame has only one mesh  : obname = parent frame name, meshname =  mesh token name.
                if parentname:
                    meshcount = 0
                    for child in getChilds(parentname):
                        if tokens[child]['type'] == 'mesh':
                            meshcount += 1
                            if meshcount == 2:
                                parentname = tokenname
                                break
                else:
                    parentname = tokenname

                ob = getMesh(parentname, tokenname)
                obs.append(ob)

                if show_geninfo: print('%smesh : %s' % (tab, tokenname))

            # frames contain one matrix (empty or bone)
            elif tokentype == 'frametransformmatrix':
                [mat] = readToken(tokenname)
                if show_geninfo: print('%smatrix : %s' % (tab, tokenname))

            # frames can contain 0 or more frames
            elif tokentype == 'frame':
                frames.append(tokenname)
                if show_geninfo: print('%sframe : %s' % (tab, tokenname))

        # matrix is used for mesh transform if some mesh(es) exist(s)
        if ob:
            is_root = True
            if mat == False:
                mat = Matrix()
                if show_geninfo:
                    print(
                        '%smesh token without matrix, set it to default\n%splease report in bug tracker if you read this !'
                        % (tab, tab))
            if parentname == '':
                mat = mat * global_matrix
            if len(obs) == 1:
                ob.matrix_world = mat
            else:
                ob = bel.ob.new(parentname, None, naming_method)
                ob.matrix_world = mat
                for child in obs:
                    child.parent = ob

        # matrix only, store it as a list as we don't know if
        # it's a bone or an empty yet
        elif mat:
            ob = [parentname, mat, []]

        # nothing case ?
        else:
            ob = [parentname, Matrix() * global_matrix, []]
            if show_geninfo: print('%snothing here' % (tab))

        childs = []

        for tokenname in frames:
            if show_geninfo: print('%s<Begin %s :' % (tab, tokenname))

            # child is either False, empty, object, or a list or undefined name matrices hierarchy
            child = import_dXtree(getChilds(tokenname), lvl + 1)
            if child and type(child) != list:
                is_root = True
            childs.append([tokenname, child])
            if show_geninfo: print('%sEnd %s>' % (tab, tokenname))

        if is_root and parentname != '':

            if show_geninfo: print('%send of tree a this point' % (tab))
            if type(ob) == list:
                mat = ob[1]
                ob = bel.ob.new(parentname, None, naming_method)
            ob.matrix_world = mat

        for tokenname, child in childs:
            if show_geninfo: print('%sbegin2 %s>' % (tab, tokenname))
            # returned a list of object(s) or matrice(s)
            if child:

                # current frame is an object or an empty, we parent this frame to it
                #if eot or (ob and ( type(ob.data) == type(None) or type(ob.data) == bpy.types.Mesh ) ) :
                if is_root:
                    # this branch is an armature, convert it
                    if type(child) == list:
                        if show_geninfo:
                            print('%sconvert to armature %s' %
                                  (tab, tokenname))
                        child = buildArm(tokenname, child)

                    # parent the obj/empty/arm to current
                    # or apply the global user defined matrix to the object root
                    if parentname != '':
                        child.parent = ob
                    else:
                        child.matrix_world = global_matrix

                # returned a list of parented matrices. append it in childs list
                elif type(child[0]) == str:
                    ob[2].append(child)

                # child is an empty or a mesh, so current frame is an empty, not an armature
                elif ob and (type(child.data) == type(None)
                             or type(child.data) == bpy.types.Mesh):
                    #print('  child data type: %s'%type(child.data))
                    child.parent = ob
                    #print('%s parented to %s'%(child.name,ob.name))

            # returned False
            else:
                if show_geninfo: print('%sreturned %s, nothing' % (tab, child))

        #print('>> %s return %s'%(field,ob))
        return ob  # if ob else False
Beispiel #53
0
def get_mats_for_segment(self, context, segment, splinetype):
    '''
    Creates the Matrizies for a spline segment.
    '''
    #printd('Creating transforms for segment', splinetype)
    mats = []

    p1 = segment[0]
    p2 = segment[1]

    count = self.leafs_per_segment
    if self.bvh:
        count *= 2

    ### TRANSLATION #################
    if splinetype == 'BEZIER':
        coordsb = interpolate_bezier(p1.co, p1.handle_right, p2.handle_left,
                                     p2.co, count + 1)
        coords = [
            coordsb[i].lerp(coordsb[i + 1],
                            random() * self.loc_random)
            for i in range(len(coordsb) - 1)
        ]

    elif splinetype == 'POLY':
        if count > 1:
            positions = [i / count for i in range(count)]
        else:
            positions = [0.5]
        #printd('POLY-segment: Lerp-positions', positions)
        coords = [
            p1.co.lerp(p2.co,
                       positions[i] + (random() * self.loc_random)).to_3d()
            for i in range(count)
        ]

    mat_locs = [Matrix.Translation(co) for co in coords]

    ### SCALE #################
    mat_scales = [
        Matrix.Scale(self.scale + (random() * self.scale_random), 4)
        for i in range(len(mat_locs))
    ]

    ### ROTATION #################
    if splinetype == 'BEZIER':
        directions = [(coordsb[i + 1] - coordsb[i]).normalized()
                      for i in range(len(coordsb) - 1)]
    elif splinetype == 'POLY':
        directions = [(p2.co - p1.co).to_3d().normalized()] * len(coords)

    # COLLISION -> align leaves to surface
    if self.bvh:
        # printd('COLLISION')
        mat_rots = get_collider_aligned_rots(self, context,
                                             coords[:int(count / 2)],
                                             directions)

    # NO COLLISION
    else:
        vecs_target = directions.copy()

        # direction + random for y alignment
        vecs_target = [
            vt.lerp(vt + noise.random_unit_vector(),
                    self.rot_random).normalized() for vt in vecs_target
        ]

        # up versus random for z alignment
        vecs_alignz = [
            Vector((0, 0, 1)).lerp(noise.random_unit_vector(),
                                   self.rot_align_normal_random).normalized()
            for i in range(len(directions))
        ]

        # return alignz towards the direction vector
        vecs_alignz = [
            va.lerp(d, self.rot_align_normal).normalized()
            for va, d in zip(vecs_alignz, directions)
        ]

        mat_rots = [align(vt, va) for vt, va in zip(vecs_target, vecs_alignz)]
        #printd('FREE ROTATION Mats:', len(mat_rots))

    # COMBINED
    mats = [l * s * r for l, s, r in zip(mat_locs, mat_scales, mat_rots)]
    mats = [m for m in mats if not random() > self.leafs_per_segment_random]
    #printd('MATS: ', len(mats), len(mat_locs), len(mat_scales), len(mat_rots))
    return mats
 def dataCorrect2(self, destination, obj):
     if destination:
         return dataCorrect(destination)
     return [Matrix() for v in obj]
Beispiel #55
0
def import_model(model, options):
    # utils.delete_all_objects()

    # This seems to be the rage these days
    Context = bpy.context
    Data = bpy.data
    Ops = bpy.ops

    # Create our new collection. This will help us later on..
    collection = Data.collections.new(model.name)
    # Add our collection to the scene
    Context.scene.collection.children.link(collection)

    # TODO: clear the orphan list for ultra name purity
    sun = Data.lights.new(name="Sun", type='SUN')
    sun_object = Data.objects.new("Sun", sun)
    collection.objects.link(sun_object)

    # Create the armature
    armature = bpy.data.armatures.new(model.name)
    armature_object = bpy.data.objects.new(model.name, armature)
    armature_object.data.display_type = 'STICK'
    armature_object.show_in_front = True

    collection.objects.link(armature_object)
    armature_object.select_set(True)
    #armature_object.edit_bones()

    Context.view_layer.objects.active = armature_object
    Ops.object.mode_set(mode='EDIT')

    for node in model.nodes:
        bone = armature.edit_bones.new(node.name)
        '''
        We can be assured that the parent will always be found because
        the node list is in the same order as a depth-first traversal of the
        node hierarchy.
        '''
        bone.parent = armature.edit_bones[
            node.parent.name] if node.parent else None
        bone.tail = (1, 0, 0)
        bone.transform(node.bind_matrix)

        if bone.parent is not None:
            bone.use_connect = bone.parent.tail == bone.head
            print(bone.use_connect, node.is_removable)
        '''
        Get the forward, left, and up vectors of the bone (used later for determining the roll).
        '''
        '''
        Lithtech uses a left-handed coordinate system where:
            X+: Right
            Y+: Up
            Z+: Forward
        '''
        (forward, right, up) = map(lambda x: -x.xyz, node.bind_matrix.col[0:3])

        if node.children:
            '''
            This bone has children. To determine the tail position of this bone,
            we check if all child bone head locations are sufficiently collinear to this
            direction vector of this bone.
            '''
            is_collinear = True
            collinearity_epsilon = 0.00001

            for child in node.children:
                child_dir = child.bind_matrix.translation - bone.head
                dot_product = forward.dot(child_dir.normalized())
                if (1.0 - dot_product) > collinearity_epsilon:
                    is_collinear = False
                    break

            if is_collinear:
                '''
                All child bone head locations are collinear to the directionality of
                the bone. Set the tail of this bone to the nearest child bone whose
                head is not concurrent with the head of the current bone (i.e. we shouldn't have zero-length bones!)
                '''
                sorted_children = node.children[:]
                sorted_children.sort(key=lambda c: (
                    bone.head - c.bind_matrix.translation).length_squared)
                bone.tail = sorted_children[0].bind_matrix.translation
                # TODO: this could still be generating zero-length bones
            else:
                '''
                One or more child bone head locations are not collinear. Simply project
                the bone out along it's forward vector a reasonable distance.
                '''
                dot_products = map(
                    lambda x: forward.dot(child.bind_matrix.translation - bone.
                                          head), node.children)
                dot_products = list(filter(lambda x: x > 0, dot_products))
                bone_length = max(
                    options.bone_length_min,
                    min(dot_products)
                    if dot_products else options.bone_length_min)
                bone.tail = bone.head + bone_length * forward
        else:
            '''
            There is no child node to connect to, so we make a guess
            as to an appropriate length of the bone (half the length
            of the previous bone).
            '''
            if bone.parent is not None:
                bone_length = max(options.bone_length_min,
                                  bone.parent.length * 0.5)
            else:
                bone_length = options.bone_length_min
            bone.tail = bone.head + bone_length * forward

            # TODO: Now calculate the roll of the bone.

    Ops.object.mode_set(mode='OBJECT')
    ''' Add sockets as empties with a child-of constraint to the appropriate bone. '''
    if options.should_import_sockets:
        for socket in model.sockets:
            empty_object = Data.objects.new(socket.name, None)
            empty_object.location = socket.location
            empty_object.rotation_quaternion = socket.rotation
            empty_object.empty_display_type = 'PLAIN_AXES'
            child_of_constraint = empty_object.constraints.new('CHILD_OF')
            child_of_constraint.target = armature_object
            child_of_constraint.subtarget = model.nodes[socket.node_index].name
            empty_object.parent = armature_object
            collection.objects.link(empty_object)
    ''' Determine the amount of LODs to import. '''
    lod_import_count = model.lod_count if options.should_import_lods else 1
    ''' Create materials. '''
    materials = []

    for i, piece in enumerate(model.pieces):
        while len(materials) <= piece.material_index:
            ''' Create a material for the new piece. '''
            material = Data.materials.new(piece.name)
            material.specular_intensity = piece.specular_power / 100

            material.use_nodes = True

            # TODO: maybe put something in here for the specular scale?
            materials.append(material)
            ''' Create texture. '''

            # Swapped over to nodes
            bsdf = material.node_tree.nodes["Principled BSDF"]
            texImage = material.node_tree.nodes.new('ShaderNodeTexImage')
            material.node_tree.links.new(bsdf.inputs['Base Color'],
                                         texImage.outputs['Color'])

            texture = Data.textures.new(piece.name, type='IMAGE')

            # Note: Texture image names are stored in ModelButes.txt
            if options.image is not None:
                texture.image = bpy.data.images.new(
                    piece.name,
                    width=options.image.width,
                    height=options.image.height,
                    alpha=True)  # TODO: get real name
                texture.image.pixels[:] = options.image.pixels[:]

            texImage.image = texture.image
    ''' Create a mesh for each piece of each LOD level that we are importing. '''
    for lod_index in range(lod_import_count):
        for piece_index, piece in enumerate(model.pieces):
            lod = piece.lods[lod_index]
            ''' Create the object and mesh. '''
            mesh_name = piece.name
            if options.should_import_lods:
                mesh_name += '.LOD{0!s}'.format(lod_index)
            mesh = Data.meshes.new(model.name)
            mesh_object = Data.objects.new(mesh_name, mesh)
            ''' Add materials to mesh. '''
            for material in materials:
                ''' Create UV map. '''
                '''
                uv_texture = mesh.uv_textures.new()
                mesh.materials.append(material)
                material.texture_slots[0].uv_layer = uv_texture.name
                '''
                uv_texture = mesh.uv_layers.new()
                mesh.materials.append(material)
                # material.uv_layers[0].name = uv_texture.name
            ''' Create a vertex group for each node. '''
            for node in model.nodes:
                mesh_object.vertex_groups.new(name=node.name)

            # TODO: these need to be reset for each mesh
            vertex_offset = 0
            face_offset = 0
            ''' Populate the actual mesh data. '''
            bm = bmesh.new()
            bm.from_mesh(mesh)

            for vertex in lod.vertices:
                bm.verts.new(vertex.location)

            bm.verts.ensure_lookup_table()
            duplicate_face_indices = []
            for face_index, face in enumerate(lod.faces):
                face = [
                    bm.verts[vertex_offset + vertex.vertex_index]
                    for vertex in face.vertices
                ]
                try:
                    bmface = bm.faces.new(face)
                except ValueError:
                    '''
                    This face is a duplicate of another face, which is disallowed by Blender.
                    Mark this face for deletion after iteration.
                    '''
                    duplicate_face_indices.append(face_index)
                    continue
                '''
                Assign the material index of face based on the piece's material index.
                '''
                bmface.material_index = model.pieces[
                    piece_index].material_index
                bmface.smooth = True

            bm.faces.ensure_lookup_table()
            '''
            Warn the user of the number of duplicate faces detected, if any.
            '''
            if len(duplicate_face_indices) > 0:
                print('WARNING: {} duplicate faces detected.'.format(
                    len(duplicate_face_indices)))
            '''
            Delete any of the duplicate faces from the mesh.
            '''
            for face_index in reversed(sorted(duplicate_face_indices)):
                del lod.faces[face_index]

            vertex_offset += len(lod.vertices)
            face_offset += len(lod.faces)

            bm.to_mesh(mesh)
            '''
            Assign texture coordinates.
            '''
            material_face_offsets = [0] * len(mesh.materials)
            uv_texture = mesh.uv_layers[piece.material_index]

            # Set the correct UV as active
            uv_texture.active_render = True

            for face_index, face in enumerate(lod.faces):
                material_face_offset = material_face_offsets[
                    0]  # TODO: is this right?
                texcoords = [vertex.texcoord for vertex in face.vertices]
                for i in range(3):
                    uv = texcoords[i][0], 1.0 - texcoords[i][1]
                    uv_texture.data[(material_face_offset + face_index) * 3 +
                                    i].uv = uv
            material_face_offsets[0] += len(lod.faces)
            ''' Assign normals '''
            face_offset = 0
            polygons = mesh.polygons[face_offset:face_offset + len(lod.faces)]
            for face_index, (face,
                             polygon) in enumerate(zip(lod.faces, polygons)):
                vertices = lod.get_face_vertices(face_index)
                for vertex, loop_index in zip(vertices, polygon.loop_indices):
                    # TODO: this might not actually set the normal properly
                    n = Vector(vertex.normal)
                    mesh.loops[loop_index].normal = n
            face_offset += len(lod.faces)

            mesh.validate(clean_customdata=False)
            mesh.update(calc_edges=False)

            # add it to our collection c:
            collection.objects.link(mesh_object)

            if Ops.object.mode_set.poll():
                Ops.object.mode_set(mode='OBJECT')
            Ops.object.select_all(action='DESELECT')
            ''' Add an armature modifier. '''
            armature_modifier = mesh_object.modifiers.new(name='Armature',
                                                          type='ARMATURE')
            armature_modifier.object = armature_object
            ''' Assign vertex weighting. '''
            vertex_offset = 0
            for (vertex_index, vertex) in enumerate(lod.vertices):
                for weight in vertex.weights:
                    vertex_group_name = model.nodes[weight.node_index].name
                    vertex_group = mesh_object.vertex_groups[vertex_group_name]
                    vertex_group.add([vertex_offset + vertex_index],
                                     weight.bias, 'REPLACE')
            vertex_offset += len(lod.vertices)
            ''' Parent the mesh to the armature. '''
            mesh_object.parent = armature_object
    ''' Animations '''
    if options.should_import_animations:
        for ob in bpy.context.scene.objects:
            ob.animation_data_clear()

        assert (len(armature.bones) == len(model.nodes))

        armature_object.animation_data_create()

        actions = []

        index = 0
        for animation in model.animations:
            print("Processing ", animation.name)
            if (index > 0):
                break

            index = index + 1
            # Create a new action with the animation name
            action = bpy.data.actions.new(name=animation.name)

            # Temp set
            armature_object.animation_data.action = action

            # For every keyframe
            for keyframe_index, keyframe in enumerate(animation.keyframes):
                # Set keyframe time - Scale it down because it's way too slow for testing
                Context.scene.frame_set(keyframe.time * 0.01)
                '''
                Recursively apply transformations to a nodes children
                Notes: It carries everything (nodes, pose_bones..) with it, because I expected it to not be a child of this scope...oops!
                '''
                def recursively_apply_transform(nodes, node_index, pose_bones,
                                                parent_matrix):
                    # keyframe_index = 0
                    node = nodes[node_index]
                    pose_bone = pose_bones[node_index]
                    original_index = node_index

                    #print("[",node_index,"] Applying transform to : ", node.name)

                    # Get the current transform
                    transform = animation.node_keyframe_transforms[node_index][
                        keyframe_index]

                    # Correct-ish
                    # rotation = Quaternion( (transform.rotation.w, -transform.rotation.z, -transform.rotation.x, transform.rotation.y) )

                    rotation = Quaternion(
                        (transform.rotation.w, -transform.rotation.z,
                         -transform.rotation.x, transform.rotation.y))

                    matrix = rotation.to_matrix().to_4x4(
                    )  # transform.rotation.to_matrix().to_4x4()

                    # Apply the translation
                    matrix.Translation(transform.location.xzy)

                    # Use a matrix instead!
                    pose_bone.matrix = parent_matrix @ matrix

                    # Recursively apply our transform to our children!
                    # print("[",node_index,"] Found children count : ", node.child_count)

                    #if (node.child_count):
                    #    print("[",original_index,"] Recurse Start --- ",node.name)

                    for index in range(0, node.child_count):
                        node_index = node_index + 1
                        #print("[",original_index,"] Applying transform to child : ", nodes[node_index].name)

                        node_index = recursively_apply_transform(
                            nodes, node_index, pose_bones, pose_bone.matrix)

                    #if (node.child_count):
                    #    print("[",original_index,"] Recurse End   --- ",node.name)

                    return node_index

                '''
                Func End
                '''

                recursively_apply_transform(model.nodes,
                                            0, armature_object.pose.bones,
                                            Matrix())

                # For every bone
                for bone, node in zip(armature_object.pose.bones, model.nodes):
                    bone.keyframe_insert('location')
                    bone.keyframe_insert('rotation_quaternion')

            # Add to actions array
            actions.append(action)

        # Add our actions to animation data
        armature_object.animation_data.action = actions[0]

    # Set our keyframe time to 0
    Context.scene.frame_set(0)

    # TODO: make an option to convert to blender coordinate system
    # armature_object.rotation_euler.x = math.radians(90)
    # armature_object.scale.x = -1.0

    return {'FINISHED'}
Beispiel #56
0
    def texdata(self, face, mesh, obj):
        mat = None
        width = height = 64
        if obj.material_slots:
            mat = obj.material_slots[face.material_index].material
        if mat:
            for node in mat.node_tree.nodes:
                if node.type == 'TEX_IMAGE':
                    width, height = node.image.size
                    break
            texstring = mat.name
        else:
            texstring = self.option_skip

        V = [loop.vert.co for loop in face.loops]
        uv_layer = mesh.loops.layers.uv.active
        T = [loop[uv_layer].uv for loop in face.loops]

        # UV handling ported from: https://bitbucket.org/khreathor/obj-2-map

        if self.option_format == 'Valve':
            # [ Ux Uy Uz Uoffs ] [ Vx Vy Vz Voffs ] rotation scaleU scaleV
            dummy = ' [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1\n'

            height = -height  # workaround for flipped v

            # Set up "2d world" coordinate system with the 01 edge along X
            world01 = V[1] - V[0]
            world02 = V[2] - V[0]
            world01_02Angle = world01.angle(world02)
            if face.normal.dot(world01.cross(world02)) < 0:
                world01_02Angle = -world01_02Angle
            world01_2d = Vector((world01.length, 0.0))
            world02_2d = Vector((math.cos(world01_02Angle),
                                 math.sin(world01_02Angle))) * world02.length

            # Get 01 and 02 vectors in UV space and scale them
            tex01 = T[1] - T[0]
            tex02 = T[2] - T[0]
            tex01.x *= width
            tex02.x *= width
            tex01.y *= height
            tex02.y *= height
            '''
            a = world01_2d
            b = world02_2d
            p = tex01
            q = tex02

            [ px ]   [ m11 m12 0 ] [ ax ]
            [ py ] = [ m21 m22 0 ] [ ay ]
            [ 1  ]   [ 0   0   1 ] [ 1  ]

            [ qx ]   [ m11 m12 0 ] [ bx ]
            [ qy ] = [ m21 m22 0 ] [ by ]
            [ 1  ]   [ 0   0   1 ] [ 1  ]

            px = ax * m11 + ay * m12
            py = ax * m21 + ay * m22
            qx = bx * m11 + by * m12
            qy = bx * m21 + by * m22

            [ px ]   [ ax ay 0  0  ] [ m11 ]
            [ py ] = [ 0  0  ax ay ] [ m12 ]
            [ qx ]   [ bx by 0  0  ] [ m21 ]
            [ qy ]   [ 0  0  bx by ] [ m22 ]
            '''

            # Find an affine transformation to convert
            # world01_2d and world02_2d to their respective UV coords
            texCoordsVec = Vector((tex01.x, tex01.y, tex02.x, tex02.y))
            world2DMatrix = Matrix(((world01_2d.x, world01_2d.y, 0,
                                     0), (0, 0, world01_2d.x, world01_2d.y),
                                    (world02_2d.x, world02_2d.y, 0,
                                     0), (0, 0, world02_2d.x, world02_2d.y)))
            try:
                mCoeffs = solve(world2DMatrix, texCoordsVec)
            except:
                return texstring + dummy
            right_2dworld = Vector(mCoeffs[0:2])
            up_2dworld = Vector(mCoeffs[2:4])

            # These are the final scale values
            # (avoid division by 0 for degenerate or missing UVs)
            scalex = 1 / max(0.00001, right_2dworld.length)
            scaley = 1 / max(0.00001, up_2dworld.length)
            scale = Vector((scalex, scaley))

            # Get the angles of the texture axes. These are in the 2d world
            # coordinate system, so they're relative to the 01 vector
            right_2dworld_angle = math.atan2(right_2dworld.y, right_2dworld.x)
            up_2dworld_angle = math.atan2(up_2dworld.y, up_2dworld.x)

            # Recreate the texture axes in 3d world coordinates,
            # using the angles from the 01 edge
            rt = world01.normalized()
            up = rt.copy()
            rt.rotate(Matrix.Rotation(right_2dworld_angle, 3, face.normal))
            up.rotate(Matrix.Rotation(up_2dworld_angle, 3, face.normal))

            # Now we just need the offsets
            rt_full = rt.to_4d()
            up_full = up.to_4d()
            test_s = V[0].dot(rt) / (width * scale.x)
            test_t = V[0].dot(up) / (height * scale.y)
            rt_full[3] = (T[0].x - test_s) * width
            up_full[3] = (T[0].y - test_t) * height

            texstring += f" [ {self.printvec(rt_full)} ]"\
                        f"[ {self.printvec(up_full)} ]"\
                        f" 0 {self.printvec(scale)}\n"

        elif self.option_format == 'Quake':
            # offsetU offsetV rotation scaleU scaleV
            dummy = ' 0 0 0 1 1\n'

            # 01 and 02 in 3D space
            world01 = V[1] - V[0]
            world02 = V[2] - V[0]

            # 01 and 02 projected along the closest axis
            maxn = max(abs(round(crd, 5)) for crd in face.normal)
            for i in [2, 0, 1]:  # axis priority for 45 degree angles
                if round(abs(face.normal[i]), 5) == maxn:
                    axis = i
                    break
            world01_2d = Vector((world01[:axis] + world01[(axis + 1):]))
            world02_2d = Vector((world02[:axis] + world02[(axis + 1):]))

            # 01 and 02 in UV space (scaled to texture size)
            tex01 = T[1] - T[0]
            tex02 = T[2] - T[0]
            tex01.x *= width
            tex02.x *= width
            tex01.y *= height
            tex02.y *= height

            # Find affine transformation between 2D and UV
            texCoordsVec = Vector((tex01.x, tex01.y, tex02.x, tex02.y))
            world2DMatrix = Matrix(((world01_2d.x, world01_2d.y, 0,
                                     0), (0, 0, world01_2d.x, world01_2d.y),
                                    (world02_2d.x, world02_2d.y, 0,
                                     0), (0, 0, world02_2d.x, world02_2d.y)))
            try:
                mCoeffs = solve(world2DMatrix, texCoordsVec)
            except:
                return texstring + dummy

            # Build the transformation matrix and decompose it
            tformMtx = Matrix(((mCoeffs[0], mCoeffs[1], 0),
                               (mCoeffs[2], mCoeffs[3], 0), (0, 0, 1)))
            t0 = Vector((T[0].x * width, T[0].y * height)).to_3d()
            v0 = Vector((V[0][:axis] + V[0][(axis + 1):])).to_3d()

            offset = t0 - (tformMtx @ v0)
            rotation = math.degrees(tformMtx.inverted_safe().to_euler().z)
            scale = tformMtx.inverted_safe().to_scale()  # always positive

            # Compare normals between UV and projection to get the scale sign
            tn = tex01.to_3d().cross(tex02.to_3d())
            vn = world01_2d.to_3d().cross(world02_2d.to_3d())
            if tn.dot(vn) < 0: scale.x *= -1

            # fudge
            offset.x += width
            offset.y *= -1

            finvals = [offset.x, offset.y, rotation, scale.x, scale.y]
            texstring += f" {self.printvec(finvals)}\n"

        return texstring