def va(vx, vz, iang, sang, n):          # shortcut Verts.append  
     for i in range(n):
         v = Vector((vx, 0, vz))
         ai = sang + iang*i
         E_rot = Euler((0, 0, ai), 'XYZ')       
         v.rotate(E_rot)  
         Verts.append((v.x, v.y, v.z)) 
Example #2
0
 def va(vx, vz, iang, sang, n):  # shortcut Verts.append
     for i in range(n):
         v = Vector((vx, 0, vz))
         ai = sang + iang * i
         E_rot = Euler((0, 0, ai), 'XYZ')
         v.rotate(E_rot)
         Verts.append((v.x, v.y, v.z))
Example #3
0
    def exportProperties(self, exportPath):
        values = {}
        values['type'] = "\"camera\""

        if bpy.data.objects.find(
                self.sp_objectProperty) != -1 and bpy.data.cameras.find(
                    bpy.data.objects[self.sp_objectProperty].data.name) != -1:
            object = bpy.data.objects[self.sp_objectProperty]
            camera = bpy.data.objects[self.sp_objectProperty].data
            # Get some parameters
            rotMatrix = object.matrix_world.to_quaternion()
            targetVec = Vector((0.0, 0.0, -1.0))
            targetVec.rotate(rotMatrix)
            targetVec += object.matrix_world.to_translation()
            upVec = Vector((0.0, 1.0, 0.0))
            upVec.rotate(rotMatrix)

            values['eye'] = [
                float(object.matrix_world[0][3]),
                float(object.matrix_world[1][3]),
                float(object.matrix_world[2][3])
            ]
            values['target'] = [targetVec[0], targetVec[1], targetVec[2]]
            values['up'] = [upVec[0], upVec[1], upVec[2]]
            values['fov'] = camera.angle_y * 180.0 / numpy.pi
            values['principalPoint'] = [
                0.5 - camera.shift_x * 2.0, 0.5 - camera.shift_y * 2.0
            ]

        values['size'] = [
            self.inputs['Width'].default_value,
            self.inputs['Height'].default_value
        ]

        return values
Example #4
0
    def make_verts(n_petals=8, vp_petal=20, profile_radius=1.3, amp=1.0):
        # variables
        z_float = 0.0
        n_verts = n_petals * vp_petal
        section_angle = 360.0 / n_verts
        position = (2 * (pi / (n_verts / n_petals)))

        # consumables
        Verts = []

        # makes vertex coordinates
        for i in range(n_verts):
            # difference is a function of the position on the circumference
            difference = amp * cos(i * position)
            arm = profile_radius + difference
            ampline = Vector((arm, 0.0, 0.0))

            rad_angle = radians(section_angle * i)
            myEuler = Euler((0.0, 0.0, rad_angle), 'XYZ')

            # changes the vector in place, successive calls are accumulative
            # we reset at the start of the loop.
            ampline.rotate(myEuler)
            x_float = ampline.x
            y_float = ampline.y
            Verts.append((x_float, y_float, z_float))
        return Verts
def simbone_bake(ob, pose_bone, edit_bone, scene):
    frames, frame_step = get_scene_frames(scene)

    matrices = get_matrices(ob, pose_bone, edit_bone, frames)
    end_mats = get_matrices_single_bone(ob, pose_bone, edit_bone, frames)

    # Main lists.
    positions = [
        mat.decompose()[0] * scene.simboneworld.spaceScale for mat in matrices
    ]
    orientations = [(matrices[i] @ end_mats[i].inverted()).decompose()[1]
                    for i in range(len(end_mats))]

    velocities = [(positions[i] - positions[max(0, i - 1)]) / frame_step
                  for i in range(len(positions))]
    accelerations = [(velocities[i] - velocities[max(0, i - 1)]) / frame_step
                     for i in range(len(velocities))]

    gravity = get_gravity(scene)
    custom_force = pose_bone.simbone.custom_force.copy()
    up_quat = Euler((pose_bone.simbone.up_offset - 90, 0, 0)).to_quaternion()
    start_dir = bone_quat_to_dir(matrices[0].decompose()[1])

    # Setup pendulum values.
    pen = Pendulum()
    pen.l = edit_bone.length * scene.simboneworld.spaceScale
    pen.m = pose_bone.simbone.m
    pen.set_coords(start_dir)
    pen.c_a = pose_bone.simbone.c_a
    pen.c_d = pose_bone.simbone.c_d

    datapath = 'pose.bones["' + pose_bone.name + '"].rotation_quaternion'
    pose_bone.rotation_mode = 'QUATERNION'
    pose_bone.rotation_quaternion = end_mats[0].decompose()[1]
    pose_bone.keyframe_insert(data_path='rotation_quaternion', frame=frames[0])
    fcurves = [
        ob.animation_data.action.fcurves.find(datapath, index=i)
        for i in range(4)
    ]

    for i in range(1, len(matrices)):
        matrix = matrices[i]
        frame = frames[i]
        g = gravity.copy()
        f = custom_force.copy()
        f.rotate(orientations[i])

        pen.w = scene.simboneworld.wind - velocities[i]
        pen.f = g + f - accelerations[i]

        pen.do_steps(frame_step * scene.simboneworld.timeScale, 1)
        direction = Vector(pen.get_coords())

        direction.rotate(orientations[i].inverted())
        direction.rotate(up_quat.inverted())
        orient = direction.to_track_quat('Y', 'Z')
        orient.rotate(up_quat)

        for i in range(4):
            fcurves[i].keyframe_points.insert(frame, orient[i])
Example #6
0
    def _gothic_arc_iterator(radius,
                             cx,
                             res,
                             low_to_high=True) -> Tuple[float, float]:
        """
        Generate (x, z) points on one side of a gothic arc with the given radius.
        :param radius: the radius of the circle that forms the arc
        :param cx: the x value of the center of the window
        :param res: the number of segments on the arc, barring the start and end point
        :param low_to_high: whether to start at the center and work outwards, or to start level and work to the top
        :return a tuple of the (x, z) coordinates where x and z are the offset from the center of the arc
        """
        # make angles negative because of how CCW rotation is negative in Blender
        start_angle, end_angle = 0, -acos(cx / radius)

        if not low_to_high:  # swap order if not low to high
            start_angle, end_angle = end_angle, start_angle

        ang_step = Euler((0, (end_angle - start_angle) / (res + 1), 0))

        v = Vector((radius, 0, 0))
        v.rotate(Euler((0, start_angle, 0)))

        for _ in range(res + 2):
            yield (v[0], v[2])  # shift x to be centered around x=0

            v.rotate(ang_step)
Example #7
0
def get_location_from_sequence_data(sequence_data, frame_id, p_bone, is_convert_local_to_pose):
    channel_values = get_values_from_sequence_data(sequence_data, frame_id)

    if len(channel_values) == 1:
        location = channel_values[0]
    else:
        location = Vector([
            channel_values[0],
            channel_values[1],
            channel_values[2],
        ])

    if not is_convert_local_to_pose:
        return location

    mat = p_bone.bone.matrix_local

    if p_bone.bone.parent is not None:
        mat = p_bone.bone.parent.matrix_local.inverted() @ p_bone.bone.matrix_local

    mat_decomposed = mat.decompose()

    bone_location = mat_decomposed[0]
    bone_rotation = mat_decomposed[1]

    diff_location = Vector((
        (location.x - bone_location.x),
        (location.y - bone_location.y),
        (location.z - bone_location.z),
    ))

    diff_location.rotate(bone_rotation.inverted())

    return diff_location
Example #8
0
    def _gimbal_xyz(self, context, am):
        rotobj = (context.active_pose_bone
                  if context.mode == 'POSE' else None) or context.active_object

        if (not rotobj) or (rotobj.rotation_mode == 'QUATERNION'):
            if not am: am = self.calc_active_matrix(context)
            xyz = am.col[:3]
        elif rotobj.rotation_mode == 'AXIS_ANGLE':
            aa = rotobj.rotation_axis_angle
            z = Vector(aa[1:]).normalized()
            q = Vector((0, 0, 1)).rotation_difference(z)
            x = (q * Vector((1, 0, 0))).normalized()
            y = z.cross(x)
        else:
            e = rotobj.rotation_euler
            m = Matrix.Identity(3)
            for e_ax in rotobj.rotation_mode:
                m = Matrix.Rotation(getattr(e, e_ax.lower()), 3, e_ax) * m
            x, y, z = m.col[:3]

        if not xyz:
            m = BlUtil.Object.matrix_parent(rotobj)
            x.rotate(m)
            y.rotate(m)
            z.rotate(m)
            xyz = x, y, z

        return xyz
Example #9
0
def get_camera_up_vector(cam, rotation=None):
    with profiler.segment("get_camera_up_vector"):
        if rotation is None:
            rotation = get_object_quat(cam)
        vec = Vector((0, 1, 0))
        vec.rotate(rotation)
        return vec
def shape_circle(context, orientation):
    center = context.scene.cursor_location
    active = context.active_object
    zed = active.location[2]

    base_dir = active.location.xy - center.xy

    if orientation == 'XY':
        zero_dir = get_xy(base_dir).resized(3)
    else:
        zero_dir = base_dir.xy.resized(3)

    num_objects = len(context.selected_objects)
    delta_angle = 2 * math.pi / num_objects

    # sort objects based on angle to center
    sorted_objects = sorted(context.selected_objects, key=lambda ob: get_angle(base_dir, ob, center))

    for i in range(num_objects):
        angle = delta_angle * i
        euler = Euler((0, 0, -angle))

        direction = Vector(zero_dir)
        direction.rotate(euler)

        sorted_objects[i].location = center + direction
        sorted_objects[i].location[2] = zed
Example #11
0
    def _bay_bow_vertical_filler_strip(
        corner_v: Vector,
        start_angle: float,
        angle: float,
        height: float,
        frame_th: float,
        shift=(0, 0, 0)) -> Tuple[list, list]:
        """
        Create the triangular filler strip found between bay and bow windows. Return vertices and faces.
        :param corner_v: the location of the corner of the frame
        :param start_angle: the angle, measured from the +X axis, with positive being CCW of corner_v
        :param angle: how wide the angle is for the triangle
        :param height: the height of the strip
        :param frame_th: the thickness of the frame
        :param shift: Amount to add to all x, y, and z positions
        :return: the vertices and faces of the strip
        """
        verts, faces = [], []
        dx, dy, dz = shift

        v1 = Vector((frame_th, 0, 0))
        v2 = v1.copy()

        v1.rotate(Euler((0, 0, start_angle)))
        v2.rotate(Euler((0, 0, start_angle + angle)))

        for x, y in (corner_v[:2], (corner_v + v1)[:2], (corner_v + v2)[:2]):
            verts.append((dx + x, dy + y, dz))
            verts.append((dx + x, dy + y, dz + height))

        faces.extend(
            ((0, 2, 3, 1), (2, 4, 5, 3), (4, 0, 1, 5), (1, 3, 5), (0, 4, 2)))

        return verts, faces
Example #12
0
 def tilt_rotate(angle):
     vec = Vector((0, 0, 1))
     vec.rotate(Euler((angle, 0, 0), 'ZYX'))
     vec.rotate(Euler((0, 0, direction)))
     if simrot.relative_to_orbit:
         vec = orbit_rotate(vec, simorbit)
     return vec
Example #13
0
 def direction_rotate(angle):
     vec = Vector((0, 0, 1))
     vec.rotate(Euler((tilt, 0, 0), 'ZYX'))
     vec.rotate(Euler((0, 0, angle)))
     if simrot.relative_to_orbit:
         vec = orbit_rotate(vec, simorbit)
     return vec - orbit_normal * cos(tilt)
Example #14
0
 def tilt_rotate(angle):
     vec = Vector((0, 0, 1))
     vec.rotate(Euler((angle, 0, 0), 'ZYX'))
     vec.rotate(Euler((0, 0, direction)))
     if simrot.relative_to_orbit:
         vec = orbit_orientation(vec, simorbit)
     return vec
Example #15
0
    def create_mesh(self):

        direction = Vector((0, 0, 1))
        direction.rotate(bpy.context.region_data.view_rotation)
        bm = self.bm

        normal = Vector()
        last_vector = None

        last_vert1 = None
        last_vert2 = None
        first_vert1 = None
        first_vert2 = None

        for point in self.stroke.points:
            vert1 = bm.verts.new((direction * -500) + point.co)
            vert2 = bm.verts.new((direction * 500) + point.co)
            if not first_vert1 and not first_vert2:
                first_vert1 = vert1
                first_vert2 = vert2
            if last_vert1 and last_vert2:
                bm.faces.new((last_vert1, last_vert2, vert2, vert1))
            last_vert1 = vert1
            last_vert2 = vert2

        if self.ciclic and len(self.stroke.points) > 2:
            bm.faces.new((last_vert1, last_vert2, first_vert2, first_vert1))

        bmesh.ops.recalc_face_normals(self.bm, faces=self.bm.faces)
Example #16
0
 def _gimbal_xyz(self, context, am):
     rotobj = (context.active_pose_bone if context.mode == 'POSE' else None) or context.active_object
     
     if (not rotobj) or (rotobj.rotation_mode == 'QUATERNION'):
         if not am: am = self.calc_active_matrix(context)
         xyz = am.col[:3]
     elif rotobj.rotation_mode == 'AXIS_ANGLE':
         aa = rotobj.rotation_axis_angle
         z = Vector(aa[1:]).normalized()
         q = Vector((0,0,1)).rotation_difference(z)
         x = (q * Vector((1,0,0))).normalized()
         y = z.cross(x)
     else:
         e = rotobj.rotation_euler
         m = Matrix.Identity(3)
         for e_ax in rotobj.rotation_mode:
             m = Matrix.Rotation(getattr(e, e_ax.lower()), 3, e_ax) * m
         x, y, z = m.col[:3]
     
     if not xyz:
         m = BlUtil.Object.matrix_parent(rotobj)
         x.rotate(m)
         y.rotate(m)
         z.rotate(m)
         xyz = x, y, z
     
     return xyz
Example #17
0
def draw_callback_px(self, context):
    #context.object.location.x = self.value / 100.0
    v3d = context.space_data
    rv3d = v3d.region_3d
    cursor_co = bpy.context.scene.cursor_location
    strokes = getVisibleStrokes()
    draw_plane_normal = rv3d.view_rotation
    vn = Vector((0, 0, 1))
    vn.rotate(draw_plane_normal)
    view_dir = vn
    if (rv3d.is_perspective):
        view_dir = rv3d.view_location + rv3d.view_distance * view_dir - cursor_co

    for stroke in strokes:
        if (len(stroke) <= 1): continue
        for line in getLineFromPoints(stroke):
            coord = None
            subN = line[1] - line[0]
            t_N = -((line[0].x - cursor_co.x) * view_dir.x +
                    (line[0].y - cursor_co.y) * view_dir.y +
                    (line[0].z - cursor_co.z) * view_dir.z)
            t_D = subN.x * view_dir.x + subN.y * view_dir.y + subN.z * view_dir.z
            if (t_D == 0):
                coord = line[0]
                continue
            elif abs(t_N) < abs(t_D):
                t = t_N / t_D
                coord = line[0] + subN * t
            if (coord != None):
                pos = location_3d_to_region_2d(context.region, rv3d, coord)
                draw_text_in_view(pos)
Example #18
0
def pointLight():
    world = bpy.data.worlds['World']
    world.use_nodes = True
    wnodes = world.node_tree.nodes
    bg_node = wnodes['Background']
    bg_node.inputs[1].default_value = 0

    d = random.uniform(3, 5)
    litpos = Vector(config["litpos"])
    eul = Euler((0, 0, 0), 'XYZ')
    eul.rotate_axis('Z', config["litEulerZ"])
    eul.rotate_axis('X', config["litEulerX"])
    litpos.rotate(eul)

    bpy.ops.object.add(type='LIGHT', location=litpos)
    lamp = bpy.data.lights[0]
    lamp.use_nodes = True
    nodes = lamp.node_tree.nodes
    links = lamp.node_tree.links
    for node in nodes:
        if node.type == 'OUTPUT':
            output_node = node
        elif node.type == 'EMISSION':
            lamp_node = node
    strngth = config["litStr"]
    lamp_node.inputs[1].default_value = strngth
    # Change warmness of light to simulate more natural lighting
    bbody = nodes.new(type='ShaderNodeBlackbody')
    color_temp = config["litColorTemp"]
    bbody.inputs[0].default_value = color_temp
    links.new(bbody.outputs[0], lamp_node.inputs[0])
Example #19
0
    def execute(self, context):
        obs_in_editmode = context.objects_in_mode_unique_data
        bpy.ops.object.mode_set(mode='OBJECT')
        try:
            for o in obs_in_editmode:
                viewdir = Vector((0, 0, -1))

                for area in context.screen.areas:
                    if area.type != 'VIEW_3D':
                        continue

                    r3d = area.spaces[0].region_3d
                    if r3d is None:
                        continue

                    viewdir.rotate(r3d.view_rotation)
                    break

                # For every face normal, calculate the dot product
                # with the view direction
                nrmls = get_vecs(o.data.polygons, attr='normal')
                dotprdcs = np.dot(nrmls, np.array(viewdir))

                # Select each face with dot product entry > 0
                selflags = np.greater(dotprdcs, 0)
                o.data.polygons.foreach_set('select', selflags)
        finally:
            bpy.ops.object.mode_set(mode='EDIT')

        return {'FINISHED'}
Example #20
0
    def make_verts(n_petals=8, vp_petal=20, profile_radius=1.3, amp=1.0):
        # variables
        z_float = 0.0
        n_verts = n_petals * vp_petal
        section_angle = 360.0 / n_verts
        position = (2 * (pi / (n_verts / n_petals)))

        # consumables
        Verts = []

        # makes vertex coordinates
        for i in range(n_verts):
            # difference is a function of the position on the circumference
            difference = amp * cos(i * position)
            arm = profile_radius + difference
            ampline = Vector((arm, 0.0, 0.0))

            rad_angle = radians(section_angle * i)
            myEuler = Euler((0.0, 0.0, rad_angle), 'XYZ')

            # changes the vector in place, successive calls are accumulative
            # we reset at the start of the loop.
            ampline.rotate(myEuler)
            x_float = ampline.x
            y_float = ampline.y
            Verts.append((x_float, y_float, z_float))
        return Verts
def shape_circle(context, orientation):
    center = context.scene.cursor_location
    active = context.active_object
    zed = active.location[2]

    base_dir = active.location.xy - center.xy

    if orientation == 'XY':
        zero_dir = get_xy(base_dir).resized(3)
    else:
        zero_dir = base_dir.xy.resized(3)

    num_objects = len(context.selected_objects)
    delta_angle = 2 * math.pi / num_objects

    # sort objects based on angle to center
    sorted_objects = sorted(context.selected_objects,
                            key=lambda ob: get_angle(base_dir, ob, center))

    for i in range(num_objects):
        angle = delta_angle * i
        euler = Euler((0, 0, -angle))

        direction = Vector(zero_dir)
        direction.rotate(euler)

        sorted_objects[i].location = center + direction
        sorted_objects[i].location[2] = zed
Example #22
0
 def visible_face_from_vertex(
         vertex: bpy.types.MeshVertex, scene: bpy.types.Scene,
         mesh_object: bpy.types.Object) -> bpy.types.MeshPolygon:
     """Convert the vertex's coordinates into camera space, and check
     whether its coordinates are within the frustum. Then cast a ray at it
     to see whether it's occluded."""
     cam = scene.camera
     cc = world_to_camera_view(scene, cam,
                               mesh_object.matrix_world @ vertex.co)
     cs = cam.data.clip_start
     ce = cam.data.clip_end
     # If the vertex's screen coordinates are within camera view
     if 0.0 < cc.x < 1.0 and 0.0 < cc.y < 1.0 and cs < cc.z < ce:
         # Convert the screen coordinates to a 3D vector
         frame = cam.data.view_frame(scene=scene)
         top_left = frame[3]
         pixel_vector = Vector((cc.x, cc.y, top_left[2]))
         pixel_vector.rotate(cam.matrix_world.to_quaternion())
         # Convert to target object space
         wmatrix_inv = mesh_object.matrix_world.inverted()
         origin = wmatrix_inv @ (pixel_vector +
                                 cam.matrix_world.translation)
         # Destination is the original vertex, in the same object space
         destination = wmatrix_inv @ vertex.co
         direction = (destination - origin).normalized()
         # Cast a ray from those screen coordinates to the vertex
         result, location, normal, index = mesh_object.ray_cast(
             origin, direction)
         if result and index > -1:
             # Return the face the vertex belongs to
             return mesh_object.data.polygons[index]
     return False
Example #23
0
 def direction_rotate(angle):
     vec = Vector((0, 0, 1))
     vec.rotate(Euler((tilt, 0, 0), 'ZYX'))
     vec.rotate(Euler((0, 0, angle)))
     if simrot.relative_to_orbit:
         vec = orbit_orientation(vec, simorbit)
     return vec - orbit_normal * cos(tilt)
Example #24
0
def updatePose(context, bone):
    sensor = context.scene.k_sensor
    
    for target in context.scene.kmc_props.targetBones:
        if target.value is not None and target.value == bone.name:
            # update bone pose
            head = sensor.getJoint(jointType[bonesDefinition[target.name][0]])
            tail = sensor.getJoint(jointType[bonesDefinition[target.name][1]])
            
            # axes matching
            X = 0 # inverted
            Y = 2
            Z = 1
            
            # update only tracked bones
            if(head[3] == 2) and (tail[3] == 2) :
                boneV = Vector((head[X] - tail[X], tail[Y] - head[Y], tail[Z] - head[Z]))
                
                # if first bone, update position (only for configured axes)
                if target.name == "Spine0":
                    # initialize firstFramePosition if fit isn't
                    if context.scene.kmc_props.firstFramePosition[1] == -1:
                        context.scene.kmc_props.firstFramePosition = (-1.0*head[X], head[Y], head[Z])
                        
                    ffp = context.scene.kmc_props.firstFramePosition
                    tx = context.scene.kmc_props.initialOffset[0]
                    ty = context.scene.kmc_props.initialOffset[2]
                    tz = context.scene.kmc_props.initialOffset[1]
                    if not context.scene.kmc_props.lockwidth:
                        tx += -head[X] - ffp[0]
                    if not context.scene.kmc_props.lockHeight:
                        ty += head[Z] - ffp[2]
                    if not context.scene.kmc_props.lockDepth:
                        tz += head[Y] - ffp[1]
                        
                    # translate bone
                    bone.matrix.translation = (tx, tz, ty)
                
                # convert rotation in local coordinates
                boneV = boneV * bone.matrix
                
                # compensate rest pose direction
                if target.name in restDirection :
                    boneV.rotate(restDirection[target.name])
                
                # calculate desired rotation
                rot = Vector((0,1,0)).rotation_difference(boneV)
                bone.rotation_quaternion = bone.rotation_quaternion * rot
                if context.scene.kmc_props.currentFrame == 0:
                    # first captured frame, initiate recording by setting the current frame to 1
                    context.scene.kmc_props.currentFrame += 1
                if context.scene.kmc_props.record :
                    bone.keyframe_insert(data_path="rotation_quaternion", frame=context.scene.kmc_props.currentFrame)
                    if target.name == "Spine0":
                        bone.keyframe_insert(data_path="location", frame=context.scene.kmc_props.currentFrame)
                
    # update child bones
    for child in bone.children :
        updatePose(context, child)
Example #25
0
 def __mul__(self, other):
     t = Transform()
     v = Vector(other.translation)  # dup
     v.rotate(self.rotation)
     t.translation = self.translation + v * self.scale
     t.rotation = self.rotation * other.rotation
     t.scale = self.scale * other.scale
     return t
Example #26
0
    def execute(self, context):
        print("Invoking Highlight Visible")
        # Check if a mesh object is selected
        try:
            bpy.ops.object.mode_set(mode='EDIT')
        except:
            self.report({'ERROR'}, "Must select a mesh object")
            return {'CANCELLED'}

        obj = bpy.context.edit_object
        me = obj.data

        # Get a BMesh representation
        mesh = bmesh.from_edit_mesh(me)
        # bm.from_mesh(me)

        mesh.faces.active = None

        cam = bpy.data.objects["Camera"]
        cam_rotation = cam.rotation_euler
        cam_dir = Vector((0, 0, 1))
        cam_dir.rotate(cam_rotation)
        print("Camera direction:", cam_dir)

        try:
            color_layer = mesh.loops.layers.color['Col']
        except:
            color_layer = mesh.loops.layers.color.new("Col")

        # NOTE: This does not yet correctly handle occluded geometry!
        for v in mesh.verts:
            color = (1, 1, 1, 1)

            p = world_to_camera_view(bpy.context.scene, cam, v.co)
            # Check if vertex is visible to camera
            if (0 < p.x < 1) and (0 < p.y < 1):
                # v.select = True
                # Check faces connected to vertex
                # NOTE: This is not ALL faces adjacent to a vertex. :-/
                for face in v.link_faces:
                    direction = face.normal - cam.location

                    if direction.dot(face.normal) < 0:
                        face.select = True
                        color = (1, 0, 1, 1)

            for face in v.link_faces:
                # Color faces depending on dot product direction
                for loop in face.loops:
                    loop[color_layer] = color


        # Show the updates in the viewport
        # and recalculate n-gon tessellation.
        bmesh.update_edit_mesh(me, True)
        bpy.ops.object.mode_set(mode='OBJECT')

        return {'FINISHED'}
Example #27
0
def make_coil(self):
    
    # variables and shortnames
    amp = self.profile_radius
    n_verts = self.num_verts
    n_turns = self.num_turns
    th = self.height / n_turns
    ipt = self.iterations_per_turn
    radius = self.coil_radius

    diameter = radius * 2
    two_pi = 2.0 * pi
    section_angle = two_pi / n_verts
    rad_slice = two_pi / ipt
    total_segments = (ipt * n_turns) + 1
    z_jump = self.height / total_segments

    x_rotation = atan2(th / 2, diameter)

    n = n_verts        
    Verts = []
    for segment in range(total_segments):
        rad_angle = rad_slice * segment    
    
        for i in range(n):
            
            # create the vector
            this_angle = section_angle * i
            x_float = amp * sin(this_angle) + radius
            z_float = amp * cos(this_angle)
            v1 = Vector((x_float, 0.0, z_float))
            
            # rotate it
            xz_euler = Euler((-x_rotation, 0.0, -rad_angle), 'XYZ')
            v1.rotate(xz_euler)
            
            # add extra z height per segment
            v1 += Vector((0, 0, (segment * z_jump)))
            
            # append it
            Verts.append(v1)
 
    Faces = []
    # skin it, normals facing outwards
    for t in range(total_segments-1):
        for i in range(n-1):
            p0 = i + (n*t) 
            p1 = i + (n*t) + 1
            p2 = i + (n*t + n) + 1 
            p3 = i + (n*t + n)
            Faces.append([p3,p2,p1,p0])
        p0 = n*t
        p1 = n*t + n
        p2 = n*t + (2 * n) - 1
        p3 = n*t + n-1
        Faces.append([p3,p2,p1,p0])
 
    return Verts, Faces
    def transUvVector(self):
        max_position = 0.
        min_position_x = 0.
        min_position_y = 0.

        # calculate two rotation matrix from normal vector of selected polygons
        vector_nor = self.averageNormal()

        theta_x = self.calcRotAngle('X', vector_nor.x, vector_nor.y,
                                    vector_nor.z)
        mat_rotx = Matrix.Rotation(theta_x, 3, 'X')
        vector_nor.rotate(mat_rotx)

        theta_y = self.calcRotAngle('Y', vector_nor.x, vector_nor.y,
                                    vector_nor.z)
        mat_roty = Matrix.Rotation(theta_y, 3, 'Y')

        # apply two rotation matrix to vertex
        uv_array = self.mesh.uv_layers.active.data
        for poly in self.select_poly:
            for id in range(poly.loop_start,
                            poly.loop_start + poly.loop_total):
                new_vector = Vector((
                    self.mesh.vertices[self.mesh.loops[id].vertex_index].co[0],
                    self.mesh.vertices[self.mesh.loops[id].vertex_index].co[1],
                    self.mesh.vertices[self.mesh.loops[id].vertex_index].co[2]
                ))

                new_vector.rotate(mat_rotx)
                new_vector.rotate(mat_roty)

                uv_array[id].uv = new_vector.to_2d()

                if min_position_x > uv_array[id].uv.x:
                    min_position_x = uv_array[id].uv.x
                if min_position_y > uv_array[id].uv.y:
                    min_position_y = uv_array[id].uv.y

        # recalculate uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start,
                            poly.loop_start + poly.loop_total):
                uv_array[id].uv.x = uv_array[id].uv.x + abs(min_position_x)
                uv_array[id].uv.y = uv_array[id].uv.y + abs(min_position_y)

                if max_position < uv_array[id].uv.x:
                    max_position = uv_array[id].uv.x
                if max_position < uv_array[id].uv.y:
                    max_position = uv_array[id].uv.y

        # scale uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start,
                            poly.loop_start + poly.loop_total):
                uv_array[
                    id].uv.x = uv_array[id].uv.x * MAX_LOCATION / max_position
                uv_array[
                    id].uv.y = uv_array[id].uv.y * MAX_LOCATION / max_position
Example #29
0
def make_coil(self):

    # variables and shortnames
    amp = self.profile_radius
    n_verts = self.num_verts
    n_turns = self.num_turns
    th = self.height / n_turns
    ipt = self.iterations_per_turn
    radius = self.coil_radius

    diameter = radius * 2
    two_pi = 2.0 * pi
    section_angle = two_pi / n_verts
    rad_slice = two_pi / ipt
    total_segments = (ipt * n_turns) + 1
    z_jump = self.height / total_segments

    x_rotation = atan2(th / 2, diameter)

    n = n_verts
    Verts = []
    for segment in range(total_segments):
        rad_angle = rad_slice * segment

        for i in range(n):

            # create the vector
            this_angle = section_angle * i
            x_float = amp * sin(this_angle) + radius
            z_float = amp * cos(this_angle)
            v1 = Vector((x_float, 0.0, z_float))

            # rotate it
            xz_euler = Euler((-x_rotation, 0.0, -rad_angle), 'XYZ')
            v1.rotate(xz_euler)

            # add extra z height per segment
            v1 += Vector((0, 0, (segment * z_jump)))

            # append it
            Verts.append(v1)

    Faces = []
    # skin it, normals facing outwards
    for t in range(total_segments - 1):
        for i in range(n - 1):
            p0 = i + (n * t)
            p1 = i + (n * t) + 1
            p2 = i + (n * t + n) + 1
            p3 = i + (n * t + n)
            Faces.append([p3, p2, p1, p0])
        p0 = n * t
        p1 = n * t + n
        p2 = n * t + (2 * n) - 1
        p3 = n * t + n - 1
        Faces.append([p3, p2, p1, p0])

    return Verts, Faces
Example #30
0
    def get_partial_pc(self, i):
        ''' Capture a partial point cloud (simulated depth camera) using ray casting:
        Adapted from https://blender.stackexchange.com/questions/115285/how-to-do-a-ray-cast-from-camera-originposition-to-object-in-scene-in-such-a-w'''
        # camera object which defines ray source
        cam = bpy.data.objects['Camera']
        container = bpy.data.objects['Empty']
        # save current view mode
        # mode = bpy.context.area.type
        # set view mode to 3D to have all needed variables available
        #bpy.context.area.type = "VIEW_3D"
        # get vectors which define view frustum of camera
        frame = cam.data.view_frame(scene=bpy.context.scene)
        topRight = frame[0]
        bottomRight = frame[2]
        bottomLeft = frame[2]
        topLeft = frame[3]

        label_dict = {'Landscape': 0, 'leaves': 1, 'stems_1': 2, 'trunk': 2}

        # setup vectors to match pixels
        xRange = np.linspace(topLeft[0], topRight[0], self.resolutionX)
        yRange = np.linspace(topLeft[1], bottomLeft[1], self.resolutionY)

        # array to store hit information
        values = np.empty((xRange.size, yRange.size, 3), dtype=object)
        labels = np.empty((xRange.size, yRange.size), dtype=object)

        # indices for array mapping
        indexX = 0
        indexY = 0
        # iterate over all X/Y coordinates
        for x in xRange:
            for y in yRange:
                # get current pixel vector from camera center to pixel
                pixelVector = Vector((x, y, topLeft[2]))
                # rotate that vector according to camera rotation
                pixelVector.rotate(cam.matrix_world.to_quaternion())
                #pixelVector.rotate(container.matrix_world.to_quaternion())
                #destination = matrixWorldInverted @ (pixelVector + cam.matrix_world.translation)
                #direction = (destination - origin).normalized()
                origin = cam.matrix_world.to_translation()

                # perform the actual ray casting
                hit, location, norm, face, hit_object, matrix = bpy.context.scene.ray_cast(
                    bpy.context.view_layer, origin, pixelVector)

                if hit:
                    values[indexX, indexY] = np.array(location)
                    labels[indexX,
                           indexY] = label_dict[hit_object.name.split('.')[0]]

                # update indices
                indexY += 1

            indexX += 1
            indexY = 0

        return values, labels
Example #31
0
 def pan3dView(self, sv3d: bpy.types.SpaceView3D, rv3d: bpy.types.RegionView3D, delta: Vector):
     viewPos, rot, _viewDir = prepareCameraTransformation(sv3d, rv3d)
     yawRot = Quaternion(Vector((0, 0, 1)), -delta[0])
     pitchAxis = Vector((1, 0, 0))
     pitchAxis.rotate(rot)
     pitchRot = Quaternion(pitchAxis, delta[1])
     rot.rotate(pitchRot)
     rot.rotate(yawRot)
     applyCameraTranformation(sv3d, rv3d, viewPos, rot)
Example #32
0
def hitbox_location(data, shape, length):
    origin = length * (data.origin - 0.5)

    location = Vector((0.0, -origin * hitbox_scale_y(data, shape), 0.0))
    location.rotate(data.rotation)

    location.y += origin - (length * 0.5)
    location += data.location
    return location
Example #33
0
	def rotation(self, xyz):
		xyz = Euler(xyz, 'XYZ')
		self._rotation = self.ProxyRotation(xyz)
		for line in self._lines:
			line.rotation = xyz
			length = (line.position - self.position).length
			pos = Vector([0,-length,0])
			pos.rotate(xyz)
			line.position = pos + self.position
Example #34
0
    def execute(self, context):
        # FIXME: Undo is inconsistent.
        # FIXME: Would be nicer if rotate could pick some object-local axis.

        from mathutils import Vector

        print_3d = context.scene.print_3d
        face_areas = print_3d.use_alignxy_face_area

        self.context = context
        mode_orig = context.mode
        skip_invalid = []

        for obj in context.selected_objects:
            orig_loc = obj.location.copy()
            orig_scale = obj.scale.copy()

            # When in edit mode, do as the edit mode does.
            if mode_orig == 'EDIT_MESH':
                bm = bmesh.from_edit_mesh(obj.data)
                faces = [f for f in bm.faces if f.select]
            else:
                faces = [p for p in obj.data.polygons if p.select]

            if not faces:
                skip_invalid.append(obj.name)
                continue

            # Rotate object so average normal of selected faces points down.
            normal = Vector((0.0, 0.0, 0.0))
            if face_areas:
                for face in faces:
                    normal += (face.normal * face.calc_area())
            else:
                for face in faces:
                    normal += face.normal
            normal = normal.normalized()
            normal.rotate(obj.matrix_world)  # local -> world.
            offset = normal.rotation_difference(Vector((0.0, 0.0, -1.0)))
            offset = offset.to_matrix().to_4x4()
            obj.matrix_world = offset @ obj.matrix_world
            obj.scale = orig_scale
            obj.location = orig_loc

        if len(skip_invalid) > 0:
            for name in skip_invalid:
                print(
                    f"Align to XY: Skipping object {name}. No faces selected.")
            if len(skip_invalid) == 1:
                self.report(
                    {'WARNING'},
                    f"Skipping object {skip_invalid[0]}. No faces selected.")
            else:
                self.report(
                    {'WARNING'},
                    f"Skipping some objects. No faces selected. See terminal.")
        return {'FINISHED'}
Example #35
0
 def rotation(self, xyz):
     xyz = Euler(xyz, 'XYZ')
     self._rotation = self.ProxyRotation(xyz)
     for line in self._lines:
         line.rotation = xyz
         length = (line.position - self.position).length
         pos = Vector([0, -length, 0])
         pos.rotate(xyz)
         line.position = pos + self.position
Example #36
0
def scale_along_global_z(factor, ref=None, point=None):
    obj = get_object(ref)
    axis = Vector((0.0, 0.0, 1.0))
    temp = obj.rotation_euler.copy()
    temp.x *= -1
    temp.y *= -1
    temp.z *= -1
    axis.rotate(temp)
    scale_along_axis(factor, axis, ref, point)
Example #37
0
File: utils.py Project: gjinhui/sly
def to_3d(vec, co=None, rot=None):
    """Take a 2D vector (or the XY of a 3D vector) and transform it
    according to co and rot."""
    newvec = Vector((vec[0], vec[1], 0))
    if rot:
        newvec.rotate(rot)
    if co:
        newvec += co
    return newvec
Example #38
0
def get_point_in_circle(max_radius):
    # Take vector pointing along X axis with random length less than radius
    radius = random.uniform(0, max_radius)
    vec = Vector((radius, 0.0, 0.0))
    # Rotate it random amount (0-360 degrees) along Z axis
    angle_degrees = random.uniform(0, 360)
    rot = Matrix.Rotation(radians(angle_degrees), 3, "Z")
    vec.rotate(rot)
    return vec
Example #39
0
def add_lighting():
    world=bpy.data.worlds['World']
    world.use_nodes = True
    wnodes=world.node_tree.nodes
    wlinks=world.node_tree.links
    bg_node=wnodes['Background']
    # hdr lighting
    # remove old node
    for node in wnodes:
        if node.type in ['OUTPUT_WORLD', 'BACKGROUND']:
            continue
        else:
            wnodes.remove(node)
    # hdr world lighting
    if random.random() > 0.3:
        texcoord = wnodes.new(type='ShaderNodeTexCoord')
        mapping = wnodes.new(type='ShaderNodeMapping')
        # print( 'mapping : ',  mapping.rotation[2])
        mapping.rotation[2] = random.uniform(0, 6.28)
        wlinks.new(texcoord.outputs[0], mapping.inputs[0])
        envnode=wnodes.new(type='ShaderNodeTexEnvironment')
        wlinks.new(mapping.outputs[0], envnode.inputs[0])
        idx = random.randint(0, len(envlist) - 1)
        envp = envlist[idx]
        envnode.image = bpy.data.images.load(envp[0])
        envstr = int(envp[1])
        bg_node.inputs[1].default_value=random.uniform(0.4 * envstr, 0.6 * envstr)
        wlinks.new(envnode.outputs[0], bg_node.inputs[0])
    else:
        # point light
        bg_node.inputs[1].default_value=0

        d = random.uniform(3, 5)
        litpos = Vector((0, d, 0))
        eul = Euler((0, 0, 0), 'XYZ')
        eul.rotate_axis('Z', random.uniform(0, 3.1415))
        eul.rotate_axis('X', random.uniform(math.radians(45), math.radians(135)))
        litpos.rotate(eul)

        bpy.ops.object.add(type='LIGHT', location=litpos)
        lamp = bpy.data.lights[0]
        lamp.use_nodes = True
        nodes=lamp.node_tree.nodes
        links=lamp.node_tree.links
        for node in nodes:
            if node.type=='OUTPUT':
                output_node=node
            elif node.type=='EMISSION':
                lamp_node=node
        strngth=random.uniform(200,500)
        lamp_node.inputs[1].default_value=strngth
        #Change warmness of light to simulate more natural lighting
        bbody=nodes.new(type='ShaderNodeBlackbody')
        color_temp=random.uniform(2700,10200)
        bbody.inputs[0].default_value=color_temp
        links.new(bbody.outputs[0],lamp_node.inputs[0])
    def make_coil():

        # variables
        amp = prad
        th = height / n_turns
        ipt = n_iter
        radius = crad
        diameter = radius * 2
        section_angle = 360.0 / n_verts
        rad_slice = 2.0 * pi / ipt
        total_segments = (ipt * n_turns) + 1
        z_jump = height / total_segments

        x_rotation = atan2(th / 2, diameter)

        n = n_verts
        Verts = []
        for segment in range(total_segments):
            rad_angle = rad_slice * segment

            for i in range(n):

                # create the vector
                this_angle = section_angle * i
                x_float = amp * sin(radians(this_angle)) + radius
                z_float = amp * cos(radians(this_angle))
                v1 = Vector((x_float, 0.0, z_float))

                # rotate it
                some_euler = Euler((-x_rotation, 0.0, -rad_angle), 'XYZ')
                v1.rotate(some_euler)

                # add extra z height per segment
                v1 += Vector((0, 0, (segment * z_jump)))

                # append it
                Verts.append(v1.to_tuple())

        Faces = []
        for t in range(total_segments - 1):
            for i in range(n - 1):
                p0 = i + (n * t)
                p1 = i + (n * t) + 1
                p2 = i + (n * t + n) + 1
                p3 = i + (n * t + n)
                Faces.append([p0, p1, p2, p3])
            p0 = n * t
            p1 = n * t + n
            p2 = n * t + (2 * n) - 1
            p3 = n * t + n - 1
            Faces.append([p0, p1, p2, p3])

        return Verts, Faces
Example #41
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
Example #42
0
def sv_main(n_petals=8, vp_petal=20, profile_radius=1.3, amp=1.0):

    in_sockets = [
        ['s', 'Num Petals',  n_petals],
        ['s', 'Verts per Petal',  vp_petal],
        ['s', 'Profile Radius', profile_radius],
        ['s', 'Amp',  amp],
    ]

    from math import sin, cos, radians, pi
    from mathutils import Vector, Euler

    # variables
    z_float = 0.0
    n_verts = n_petals * vp_petal
    section_angle = 360.0 / n_verts
    position = (2 * (pi / (n_verts / n_petals)))

    # consumables
    Verts = []
    Edges = []

    # makes vertex coordinates
    for i in range(n_verts):
        # difference is a function of the position on the circumference
        difference = amp * cos(i * position)
        arm = profile_radius + difference
        ampline = Vector((arm, 0.0, 0.0))

        rad_angle = radians(section_angle * i)
        myEuler = Euler((0.0, 0.0, rad_angle), 'XYZ')

        # changes the vector in place, successive calls are accumulative
        # we reset at the start of the loop.
        ampline.rotate(myEuler)
        x_float = ampline.x
        y_float = ampline.y
        Verts.append((x_float, y_float, z_float))

    # makes edge keys
    for i in range(n_verts):
        if i == n_verts - 1:
            Edges.append([i, 0])
            break
        Edges.append([i, i + 1])

    out_sockets = [
        ['v', 'Verts', [Verts]],
        ['s', 'Edges', [Edges]],
    ]

    return in_sockets, out_sockets
Example #43
0
class Turtle:
    def __init__(self, position=(0, 0, 0),direction =(0,0,1), orientation=(0, 1, 0),axe_rotation = (0,0,1), vitesse=1, angle=90,imperfection = 0.2):
        self.position = Vector(position)
        self.direction = Vector(direction).normalized()
        self.orientation = Vector(orientation).normalized()
        self.vitesse = vitesse
        self.angle = radians(angle)
        self.memoireEtat = []
        self.comportement_initialisation()
        self.imperfection = imperfection

    def comportement_initialisation(self):
        self.comportements = {
                              '+':self.comportement_plus,
                              '-':self.comportement_moins,
                              'F':self.comportement_F,
                              '[':self.comportement_save_etat,
                              ']':self.comportement_restor_etat
        }
    
    def comportement_F(self):
        p_debut = self.position.copy()
        self.position += self.direction * self.vitesse
        dx = (random() - 0.5) * self.imperfection
        dy = (random() - 0.5) * self.imperfection
        dz = (random() - 0.5) * self.imperfection
        self.direction += Vector((dx,dy,dz))
        p_fin = self.position.copy()
        return Section(debut = p_debut,fin = p_fin)
    def comportement_save_etat(self):
        etat = (self.position.copy(),
                self.direction.copy(),
                self.vitesse,
                self.angle)
        self.memoireEtat.append(etat)
    def comportement_restor_etat(self):
        (self.position,
         self.direction,
         self.vitesse,
         self.angle) = self.memoireEtat.pop()
    def comportement_plus(self):
        rotation = Matrix.Rotation(self.angle,4,self.orientation)
        self.direction.rotate(rotation)
    def comportement_moins(self):
        rotation = Matrix.Rotation(- self.angle, 4,self.orientation)
        self.direction.rotate(rotation)
    
    def interpretation(self,s):
        for char in s:
            comportement = self.comportements[char]() if char in self.comportements else None
            yield comportement
    def transUvVector(self):
        max_position = 0.
        min_position_x = 0.
        min_position_y = 0.

        # calculate two rotation matrix from normal vector of selected polygons
        vector_nor = self.averageNormal()

        theta_x = self.calcRotAngle('X', vector_nor.x, vector_nor.y, vector_nor.z)
        mat_rotx = Matrix.Rotation(theta_x, 3, 'X')
        vector_nor.rotate(mat_rotx)

        theta_y = self.calcRotAngle('Y', vector_nor.x, vector_nor.y, vector_nor.z)
        mat_roty = Matrix.Rotation(theta_y, 3, 'Y')

        # apply two rotation matrix to vertex
        uv_array = self.mesh.uv_layers.active.data
        for poly in self.select_poly:
            for id in range(poly.loop_start, poly.loop_start + poly.loop_total):
                new_vector = Vector((self.mesh.vertices[self.mesh.loops[id].vertex_index].co[0],
                                     self.mesh.vertices[self.mesh.loops[id].vertex_index].co[1],
                                     self.mesh.vertices[self.mesh.loops[id].vertex_index].co[2]))

                new_vector.rotate(mat_rotx)
                new_vector.rotate(mat_roty)

                uv_array[id].uv = new_vector.to_2d()

                if min_position_x > uv_array[id].uv.x:
                    min_position_x = uv_array[id].uv.x
                if min_position_y > uv_array[id].uv.y:
                    min_position_y = uv_array[id].uv.y

        # recalculate uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start, poly.loop_start + poly.loop_total):
                uv_array[id].uv.x = uv_array[id].uv.x + abs(min_position_x)
                uv_array[id].uv.y = uv_array[id].uv.y + abs(min_position_y)

                if max_position < uv_array[id].uv.x:
                    max_position = uv_array[id].uv.x
                if max_position < uv_array[id].uv.y:
                    max_position = uv_array[id].uv.y

        # scale uv position
        for poly in self.select_poly:
            for id in range(poly.loop_start, poly.loop_start + poly.loop_total):
                uv_array[id].uv.x = uv_array[id].uv.x * MAX_LOCATION / max_position
                uv_array[id].uv.y = uv_array[id].uv.y * MAX_LOCATION / max_position
Example #45
0
	def setupStartPos(self):
		"""Creates the starting position information"""
		player = bpy.data.objects["Player"]
    
		viewDir = Vector((0.0, 0.0, -1.0))
		viewDir.rotate(player.rotation_euler)
		
		upDir = Vector((0.0, 1.0, 0.0))
		upDir.rotate(player.rotation_euler)
		
		start = { }
		start['position'] = { 'x': ConvertHelper.convert_pos(player.location.x), 'y': ConvertHelper.convert_pos(player.location.y), 'z': ConvertHelper.convert_pos(player.location.z) }
		start['viewDirection'] = { 'x': ConvertHelper.convert_pos(viewDir.x), 'y': ConvertHelper.convert_pos(viewDir.y), 'z': ConvertHelper.convert_pos(viewDir.z) }
		start['upDirection'] = { 'x': ConvertHelper.convert_pos(upDir.x), 'y': ConvertHelper.convert_pos(upDir.y), 'z': ConvertHelper.convert_pos(upDir.z) }
		return start
Example #46
0
	def setupEnvironments(self):
		"""Sets up the environment with the different light sources"""
		environments = { }
		lighting = { }
		pointLights = [ ]
		dirLights = [ ]
		
		storeEnv = False
		storeLighting = False
		
		for lamp in bpy.data.lamps:
			if "Ambient" == lamp.name:
				storeEnv = True
				environments['ambient'] = [ ConvertHelper.convert_pos(lamp.color.r), ConvertHelper.convert_pos(lamp.color.g), ConvertHelper.convert_pos(lamp.color.b), 1.0 ]

			if "AmbientLight" == lamp.name:
				storeLighting = True
				lighting['ambientLight'] = [ ConvertHelper.convert_pos(lamp.color.r), ConvertHelper.convert_pos(lamp.color.g), ConvertHelper.convert_pos(lamp.color.b), 1.0 ]
				
			if "Point" in lamp.name:
				storeLighting = True
				lightObject = bpy.data.objects[lamp.name]
				
				pointLight = { }
				pointLight['color'] = [ ConvertHelper.convert_pos(lamp.color.r), ConvertHelper.convert_pos(lamp.color.g), ConvertHelper.convert_pos(lamp.color.b), 1.0 ]
				pointLight['position'] = [ ConvertHelper.convert_pos(lightObject.location.x), ConvertHelper.convert_pos(lightObject.location.y), ConvertHelper.convert_pos(lightObject.location.z) ]
				pointLight['intensity'] = lamp.energy
				pointLights.append(pointLight)
				
			if "Spot" in lamp.name:
				storeLighting = True
				lightObject = bpy.data.objects[lamp.name]
				
				dirLight = { }
				dirLight['color'] = [ ConvertHelper.convert_pos(lamp.color.r), ConvertHelper.convert_pos(lamp.color.g), ConvertHelper.convert_pos(lamp.color.b), 1.0 ]

				dir = Vector((0.0, 0.0, -1.0))
				dir.rotate(lightObject.rotation_euler)
				dirLight['direction'] = [ ConvertHelper.convert_pos(dir.x), ConvertHelper.convert_pos(dir.y), ConvertHelper.convert_pos(dir.z),]
				dirLights.append(dirLight)
				
		if storeLighting:
			lighting['pointLights'] = pointLights
			lighting['directionalLights'] = dirLights
			environments['lighting'] = lighting
		
		if storeEnv:
			self.data['environments'] = environments
Example #47
0
def draw_circle(point, orientation, size, fraction=1.0, steps=36, colour=[1, 0, 0]):
    last_point = None
    shift = (2 * pi / steps)

    for step in range(int(steps / fraction) + 1):
        index = step * shift
        x = sin(index) * size
        z = cos(index) * size
        step_point = Vector((x, 0, z))

        step_point.rotate(orientation)
        step_point += point

        if last_point:
            render.drawLine(last_point, step_point, colour)

        last_point = step_point
Example #48
0
class Turtle:
    def __init__(self, position=(0, 0, 0), orientation=(1, 0, 0), vitesse=1, angle=radians(90)):
        self.position = Vector(position)
        self.orientation = Vector(orientation).normalized()
        self.vitesse = vitesse
        self.angle = angle
        self.memoireEtat = []
        self.comportement_initialisation()

    def comportement_initialisation(self):
        self.comportements = {
                              '+':self.comportement_plus,
                              '-':self.comportement_moins,
                              'F':self.comportement_F,
                              '[':self.comportement_save_etat,
                              ']':self.comportement_restor_etat
        }
    
    def comportement_F(self):
        p_debut = self.position.copy()
        self.position += self.orientation * self.vitesse
        p_fin = self.position.copy()
        return Section(debut = p_debut,fin = p_fin)
    def comportement_save_etat(self):
        etat = (self.position.copy(),
                self.orientation.copy(),
                self.vitesse,
                self.angle)
        self.memoireEtat.append(etat)
    def comportement_restor_etat(self):
        (self.position,
         self.orientation,
         self.vitesse,
         self.angle) = self.memoireEtat.pop()
    def comportement_plus(self):
        rotation = Matrix.Rotation(self.angle,4,(0,1,0))
        self.orientation.rotate(rotation)
    def comportement_moins(self):
        rotation = Matrix.Rotation(- self.angle, 4,(0,1,0))
        self.orientation.rotate(rotation)
    
    def interpretation(self,s):
        for char in s:
            comportement = self.comportements[char]() if char in self.comportements else None
            yield comportement
Example #49
0
	def onKeyPressed(self, keys):
		rot = self.obj.worldOrientation.to_euler()
		pos = Vector([0,0,0])
		if key.W in keys: rot.x += 0.01
		if key.S in keys: rot.x -= 0.01
		if key.A in keys: rot.z += 0.01
		if key.D in keys: rot.z -= 0.01
		if key.WHEELUPMOUSE in keys: pos.z = -self.obj.worldPosition.z * 0.3
		if key.WHEELDOWNMOUSE in keys: pos.z = self.obj.worldPosition.z * 0.3

		#Max speed is dependent of the Tile sizes, ex (200m/s = size) / 50fps = 4m/tick
		#Since we are using an extra radius we can guarante a speed of 8m/tick without glitches: 8*60fps = 480m/s = 1728 km/h
		#if pos.length > 8: pos.length = 8
		#But we don't care for now
		if pos.length > 50: pos.length = 50
		pos.rotate(self.obj.worldOrientation)
		self.obj.worldPosition += pos
		self.obj.worldOrientation = rot
Example #50
0
    def orientation_rotation(context, orientation: str, view: str) -> list:
        rotations = []
        if orientation == "vertical":
            if view == "top":
                rotations.append(Quaternion((0.0, 0.0, 1.0), radians(90.0)))
            elif view == "right":
                rotations.append(Quaternion((1.0, 0.0, 0.0), radians(90.0)))
            elif view == "front":
                rotations.append(Quaternion((0.0, 1.0, 0.0), radians(90.0)))
            elif view == "align":
                space_data = context.space_data
                if space_data and space_data.type != 'VIEW_3D':
                    space_data = None
                if space_data:
                    to_user_view = space_data.region_3d.view_rotation
                    z_axis = Vector((0.0, 0.0, 1.0))
                    z_axis.rotate(to_user_view)
                    rotation_in_user_view = Quaternion(z_axis, radians(90.0))
                    rotations.append(rotation_in_user_view)

        return rotations
Example #51
0
	def copy(self, text = None, offset = [0,0,0]):
		""" Retuns a copy of the label
		
		:param string text: The text of the new Label or None to copy the current text.
		:param offset: A vector representing the desplacment to be applied on the new Label from this Label position in local coordinates.
		"""
		
		if text == None: text = self._text
		size = self.scale.x * 100
		offset = Vector(offset)
		offset.rotate(self.rotation)
		
		label = Label(self.font, text, size, self.align, self.position + offset, self.rotation)
		label.color = self.color
		label.visible = self.visible
		label.blur = self.blur
		label.shadow = self.shadow
		label.shadow_blur = self.shadow_blur
		label.shadow_color = self.shadow_color
		label.shadow_offset = self.shadow_offset
		return label
def shape_square(context, orientation):
    center = context.scene.cursor_location
    active = context.active_object
    zed = active.location[2]

    base_dir = active.location.xy - center.xy
    diagonal = base_dir.length

    if orientation == 'XY':
        zero_dir = get_xy_corner(base_dir).resized(3)
    else:
        zero_dir = base_dir.xy.resized(3)

    num_objects = len(context.selected_objects)
    num_side_objects = (num_objects // 4) - 1
    ortho_angle = math.pi * 0.5

    ortho_dir = Vector(zero_dir)
    ortho_dir.rotate(Euler((0, 0, ortho_angle * 0.5)))
    ortho_dir.normalize()

    # sort objects based on angle to center
    sorted_objects = sorted(context.selected_objects, key=lambda ob: get_angle(base_dir, ob, center))

    corners = []
    for i in range(0, num_objects, num_side_objects + 1):
        corners.append(sorted_objects[i])

    assert(len(corners) == 4)

    sides = [ob for ob in sorted_objects if ob not in corners]
    side_step = math.sqrt(2 * (diagonal ** 2)) / (num_side_objects + 1)

    for i in range(4):
        # corner
        angle = ortho_angle * i
        euler = Euler((0, 0, -angle))

        direction = Vector(zero_dir)
        direction.rotate(euler)

        corners[i].location = center + direction
        corners[i].location[2] = zed

        side_dir = Vector(ortho_dir)
        side_dir.rotate(euler)

        for j in range(num_side_objects):
            ob = sides[(i * num_side_objects) + j]
            step = (j + 1) * side_step

            ob.location = center + direction
            ob.location.xy -= side_dir.xy * step

            ob.location[2] = zed
Example #53
0
 def vectorsFromMatrix(matrix):
     rot = matrix.to_euler("XYZ")
     # re-add 90° on x-axis
     rot.x=math.radians(math.degrees(rot.x)+90)
     
     vx = Vector((1.0,0.0,0.0))
     vy = Vector((0.0,1.0,0.0))
     vz = Vector((0.0,0.0,1.0))
     vx.rotate(rot)
     vy.rotate(rot)
     vz.rotate(rot)
     vectors = (vx,vy,vz)
     return vectors
Example #54
0
def draw_arrow(point, orientation, length=1.5, branch_length=0.4, angle=30, colour=[1, 0, 0]):
    left = Vector((sin(radians(angle)), -cos(radians(angle)), 0))
    right = Vector((-sin(radians(angle)), -cos(radians(angle)), 0))

    left.rotate(orientation)
    right.rotate(orientation)

    left.length = branch_length
    right.length = branch_length

    direction = Vector((0, 1, 0)) * length
    direction.rotate(orientation)

    render.drawLine(point, point + direction, colour)
    render.drawLine(point + direction, point + direction + right, colour)
    render.drawLine(point + direction, point + direction + left, colour)
Example #55
0
def updateMesh(self, context):
	o = context.object

	material_list = getMaterialList(o)
		
	if o.pattern == 'Regular':
		nplanks = (o.width + o.originy) / o.plankwidth
		verts, faces, uvs = planks(nplanks, o.length + o.originx,
												o.planklength, o.planklengthvar,
												o.plankwidth, o.plankwidthvar,
												o.longgap, o.shortgap,
												o.offset, o.randomoffset, o.minoffset,
												o.randomseed,
												o.randrotx, o.randroty, o.randrotz,
												o.originx, o.originy)
	elif o.pattern == 'Herringbone':
		# note that there is a lot of extra length and width here to make sure that  we create a pattern w.o. gaps at the edges
		v = o.plankwidth * sqrt(2.0)
		w = o.planklength * sqrt(2.0)
		nplanks = int((o.width+o.planklength + o.originy*2) / v)+1
		nplanksc = int((o.length + o.originx*2) / w)+1
		verts, faces, uvs = herringbone(nplanks, nplanksc,
												o.planklength, o.plankwidth,
												o.longgap, o.shortgap,
												o.randomseed,
												o.randrotx, o.randroty, o.randrotz,
												o.originx, o.originy)
	elif o.pattern == 'Square':
		rows = int((o.width + o.originy)/ o.planklength)+1
		cols = int((o.length + o.originx)/ o.planklength)+1
		verts, faces, uvs = square(rows, cols, o.planklength, o.nsquare, o.border, o.longgap, o.shortgap, o.randomseed,
									o.randrotx, o.randroty, o.randrotz,
									o.originx, o.originy)
	elif o.pattern == 'Versaille':
		rows = int((o.width + o.originy)/ o.planklength)+2
		cols = int((o.length + o.originx)/ o.planklength)+2
		verts, faces, uvs = versaille(rows, cols, 
										o.planklength, o.plankwidth,
										o.longgap, o.shortgap,
										o.randrotx, o.randroty, o.randrotz,
										o.originx, o.originy,
										o.borderswitch)

	# create mesh &link object to scene
	emesh = o.data

	mesh = bpy.data.meshes.new(name='Planks')
	mesh.from_pydata(verts, [], faces)

	mesh.update(calc_edges=True)

	# more than one object can refer to the same emesh
	for i in bpy.data.objects:
		if i.data == emesh:
			i.data = mesh

	name = emesh.name
	emesh.user_clear() # this way the old mesh is marked as used by noone and not saved on exit
	bpy.data.meshes.remove(emesh)
	mesh.name = name
	if bpy.context.mode != 'EDIT_MESH':
		bpy.ops.object.editmode_toggle()
		bpy.ops.object.editmode_toggle()

	bpy.ops.object.shade_smooth()

	# add uv-coords and per face random vertex colors
	rot = Euler((0,0,o.uvrotation))
	mesh.uv_textures.new()
	uv_layer = mesh.uv_layers.active.data
	vertex_colors = mesh.vertex_colors.new().data
	offset = Vector()
	# note that the uvs that are returned are shuffled
	for poly in mesh.polygons:
		color = [rand(), rand(), rand()]
		if o.randomuv == 'Random':
			offset = Vector((rand(), rand(), 0))
		if o.randomuv == 'Restricted':
			offset = Vector((rand()*2-1, rand()*2-1, 0))
			for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total):
				co = offset + mesh.vertices[mesh.loops[loop_index].vertex_index].co
				if co.x > o.length or co.x < 0:
					offset[0] = 0
				if co.y > o.width or co.y < 0:
					offset[1] = 0
		elif o.randomuv == 'Packed':
			x = []
			y = []
			for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total):
				x.append(uvs[mesh.loops[loop_index].vertex_index].x)
				y.append(uvs[mesh.loops[loop_index].vertex_index].y)
			offset = Vector((-min(x), -min(y), 0))
		for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total):
			if o.randomuv == 'Shuffle':
				coords = uvs[mesh.loops[loop_index].vertex_index]
			elif o.randomuv in ('Random', 'Restricted'):
				coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co + offset
			elif o.randomuv == 'Packed':
				coords = uvs[mesh.loops[loop_index].vertex_index] + offset
			else:
				coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co
			coords = Vector(coords) # copy
			coords.x *= o.uvscalex
			coords.y *= o.uvscaley
			coords.rotate(rot)
			uv_layer[loop_index].uv = coords.xy
			vertex_colors[loop_index].color = color

	# subdivide mesh and warp it
	warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0
	if warped:
		bm = bmesh.new()
		bm.from_mesh(mesh)

		# calculate hollowness for each face
		dshortmap = {}
		dlongmap = {}
		for face in bm.faces:
			dshort = o.hollowshort * rand()
			dlong = o.hollowlong * rand()
			for v in face.verts:
				dshortmap[v.index] = dshort
				dlongmap[v.index] = dlong

		bm.to_mesh(mesh)
		bm.free()

		# at this point all new geometry is selected and subdivide works in all selection modes
		bpy.ops.object.editmode_toggle()
		bpy.ops.mesh.subdivide()  # bmesh subdivide doesn't work for me ...
		bpy.ops.object.editmode_toggle()

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

		for v in bm.verts:
			if o.twist and len(v.link_edges) == 4:  # vertex in the middle of the plank
				dtwist = o.twist * randuni(-1, 1)
				for e in v.link_edges:
					v2 = e.other_vert(v)  # the vertices on the side of the plank
					if shortside(v2):
						for e2 in v2.link_edges:
							v3 = e2.other_vert(v2)
							if len(v3.link_edges) == 2:
								v3.co.z += dtwist
								dtwist = -dtwist  # one corner up, the other corner down
			elif len(v.link_edges) == 3:  # vertex in the middle of a side of the plank
				for e in v.link_edges:
					v2 = e.other_vert(v)
					if len(v2.link_edges) == 2:  # hollowness values are stored with the all original corner vertices
						dshort = dshortmap[v2.index]
						dlong = dlongmap[v2.index]
						break
				if shortside(v):
					v.co.z -= dlong
				else:
					v.co.z -= dshort

		creases = bm.edges.layers.crease.new()
		for edge in bm.edges:
			edge[creases] = 1
			for vert in edge.verts:
				if len(vert.link_edges) == 4:
					edge[creases] = 0
					break

		bm.to_mesh(mesh)
		bm.free()

	
	# remove all modifiers to make sure the boolean will be last & only modifier
	n = len(o.modifiers)
	while n > 0:
		n -= 1
		bpy.ops.object.modifier_remove(modifier=o.modifiers[-1].name)
	
	# add thickness
	bpy.ops.object.mode_set(mode='EDIT')
	bm = bmesh.from_edit_mesh(o.data)
	
	# extrude to give thickness
	ret=bmesh.ops.extrude_face_region(bm,geom=bm.faces[:])
	ret=bmesh.ops.translate(bm,vec=Vector((0,0,self.thickness)),verts=[el for el in ret['geom'] if isinstance(el, bmesh.types.BMVert)] )
	
	# trim excess flooring
	ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(o.length,0,0), plane_no=(1,0,0), clear_outer=True)
	ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,0,0), plane_no=(-1,0,0), clear_outer=True)
	ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,o.width,0), plane_no=(0,1,0), clear_outer=True)
	ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,0,0), plane_no=(0,-1,0), clear_outer=True)
	
	# fill in holes caused by the trimming
	open_edges = [e for e in bm.edges if len(e.link_faces)==1]
	bmesh.ops.edgeloop_fill(bm, edges=open_edges, mat_nr=0, use_smooth=False)
	
	creases = bm.edges.layers.crease.active
	if creases is not None:
		for edge in open_edges:
			edge[creases] = 1

	bmesh.update_edit_mesh(o.data)
	bpy.ops.object.mode_set(mode='OBJECT')
	
	# intersect with a floorplan. Note the floorplan must be 2D (all z-coords must be identical) and a closed polygon.
	if self.usefloorplan and self.floorplan != ' None ':
		# make the floorplan the only active an selected object
		bpy.ops.object.select_all(action='DESELECT')
		context.scene.objects.active = bpy.data.objects[self.floorplan]
		bpy.data.objects[self.floorplan].select = True

		# duplicate the selected geometry into a separate object
		me = context.scene.objects.active.data
		selected_faces = [p.index for p in me.polygons if p.select]
		bpy.ops.object.editmode_toggle()
		bpy.ops.mesh.duplicate()
		bpy.ops.mesh.separate()
		bpy.ops.object.editmode_toggle()
		me = context.scene.objects.active.data
		for i in selected_faces:
			me.polygons[i].select = True

		# now there will be two selected objects
		# the one with the new name will be the copy
		for ob in context.selected_objects:
			if ob.name != self.floorplan:
				fpob = ob
		
		# make that copy active and selected
		for ob in context.selected_objects:
			ob.select = False
		fpob.select = True
		context.scene.objects.active = fpob
		# add thickness
		# let normals of select faces point in same direction
		bpy.ops.object.editmode_toggle()
		bpy.ops.mesh.select_all(action='SELECT')
		bpy.ops.mesh.normals_make_consistent(inside=False)
		bpy.ops.object.editmode_toggle()
		# add solidify modifier
		# NOTE: for some reason bpy.ops.object.modifier_add doesn't work here
		# even though fpob at this point is verifyable the active and selected object ...
		mod = fpob.modifiers.new(name='Solidify', type='SOLIDIFY')
		mod.offset = 1.0 # in the direction of the normals
		mod.thickness = 2000 # very thick
		bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify")
		bpy.ops.object.editmode_toggle()
		bpy.ops.mesh.select_all(action='SELECT')
		bpy.ops.mesh.normals_make_consistent(inside=False)
		bpy.ops.object.editmode_toggle()
		fpob.location -= Vector((0,0,1000)) # actually this should be in the negative direction of the normals not just plain downward...
		
		# at this point the floorplan object is the active and selected object
		if True:
			# make the floorboards active and selected
			for ob in context.selected_objects:
				ob.select = False
			context.scene.objects.active = o
			o.select = True
			
			# add-and-apply a boolean modifier to get the intersection with the floorplan copy
			bpy.ops.object.modifier_add(type='BOOLEAN') # default is intersect
			o.modifiers[-1].object = fpob
			if True:
				bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
				# delete the copy
				bpy.ops.object.select_all(action='DESELECT')
				context.scene.objects.active = fpob
				fpob.select = True
				bpy.ops.object.delete()
			# make the floorboards active and selected
			context.scene.objects.active = o
			o.select = True
		
	if self.modify:
		mods = o.modifiers
		if len(mods) == 0: # always true
			bpy.ops.object.modifier_add(type='BEVEL')
			#bpy.ops.object.modifier_add(type='EDGE_SPLIT')
			mods = o.modifiers
			mods[0].show_expanded = False
			#mods[1].show_expanded = False
			mods[0].width = self.bevel
			mods[0].segments = 2
			mods[0].limit_method = 'ANGLE'
			mods[0].angle_limit = (85/90.0)*PI/2
		if warped and not ('SUBSURF' in [m.type for m in mods]):
			bpy.ops.object.modifier_add(type='SUBSURF')
			mods[-1].show_expanded = False
			mods[-1].levels = 2
		if not warped and ('SUBSURF' in [m.type for m in mods]):
			bpy.ops.object.modifier_remove(modifier='Subsurf')

	if self.preservemats and len(material_list)>0:
		rebuildMaterialList(o, material_list)    
		assignRandomMaterial(len(material_list))
Example #56
0
from math import sin, cos, radians, pi
from mathutils import Vector, Euler

# create flower
n_verts = n_petals * vp_petal
section_angle = 360.0 / n_verts
position = (2 * (pi / (n_verts / n_petals)))
x, y, z = origin[:3]

Verts = []
Edges = []

for i in range(n_verts):
    difference = amp * cos(i * position)
    arm = profile_radius + difference
    ampline = Vector((arm, 0.0, 0.0))

    rad_angle = radians(section_angle * i)
    myEuler = Euler((0.0, 0.0, rad_angle), 'XYZ')
    ampline.rotate(myEuler)
    Verts.append((ampline.x+x, ampline.y+y, 0.0+z))

# makes edge keys, ensure cyclic
if Verts:
    i = 0
    Edges.extend([[i, i + 1] for i in range(n_verts - 1)])
    Edges.append([len(Edges), 0])

verts = [Verts]
edges = [Edges]
Example #57
0
def createIvyGeometry(IVY, growLeaves):
    '''Create the curve geometry for IVY'''
    # Compute the local size and the gauss weight filter
    #local_ivyBranchSize = IVY.ivyBranchSize  # * radius * IVY.ivySize
    gaussWeight = (1.0, 2.0, 4.0, 7.0, 9.0, 10.0, 9.0, 7.0, 4.0, 2.0, 1.0)

    # Create a new curve and intialise it
    curve = bpy.data.curves.new("IVY", type='CURVE')
    curve.dimensions = '3D'
    curve.bevel_depth = 1
    curve.use_fill_front = curve.use_fill_back = False
    curve.resolution_u = 4

    if growLeaves:
        # Create the ivy leaves
        # Order location of the vertices
        signList = ((-1.0, +1.0),
                    (+1.0, +1.0),
                    (+1.0, -1.0),
                    (-1.0, -1.0),
                    )

        # Get the local size
        #local_ivyLeafSize = IVY.ivyLeafSize  # * radius * IVY.ivySize

        # Initialise the vertex and face lists
        vertList = deque()

        # Store the methods for faster calling
        addV = vertList.extend
        rotMat = Matrix.Rotation

    # Loop over all roots to generate its nodes
    for root in IVY.ivyRoots:
        # Only grow if more than one node
        numNodes = len(root.ivyNodes)
        if numNodes > 1:
            # Calculate the local radius
            local_ivyBranchRadius = 1.0 / (root.parents + 1) + 1.0
            prevIvyLength = 1.0 / root.ivyNodes[-1].length
            splineVerts = [ax for n in root.ivyNodes for ax in n.pos.to_4d()]

            radiusConstant = local_ivyBranchRadius * IVY.ivyBranchSize
            splineRadii = [radiusConstant * (1.3 - n.length * prevIvyLength)
                                                        for n in root.ivyNodes]

            # Add the poly curve and set coords and radii
            newSpline = curve.splines.new(type='POLY')
            newSpline.points.add(len(splineVerts) // 4 - 1)
            newSpline.points.foreach_set('co', splineVerts)
            newSpline.points.foreach_set('radius', splineRadii)

            # Loop over all nodes in the root
            for i, n in enumerate(root.ivyNodes):
                for k in range(len(gaussWeight)):
                    idx = max(0, min(i + k - 5, numNodes - 1))
                    n.smoothAdhesionVector += (gaussWeight[k] *
                                             root.ivyNodes[idx].adhesionVector)
                n.smoothAdhesionVector /= 56.0
                n.adhesionLength = n.smoothAdhesionVector.length
                n.smoothAdhesionVector.normalize()

                if growLeaves and (i < numNodes - 1):
                    node = root.ivyNodes[i]
                    nodeNext = root.ivyNodes[i + 1]

                    # Find the weight and normalise the smooth adhesion vector
                    weight = pow(node.length * prevIvyLength, 0.7)

                    # Calculate the ground ivy and the new weight
                    groundIvy = max(0.0, -node.smoothAdhesionVector.z)
                    weight += groundIvy * pow(1 - node.length *
                                                              prevIvyLength, 2)

                    # Find the alignment weight
                    alignmentWeight = node.adhesionLength

                    # Calculate the needed angles
                    phi = atan2(node.smoothAdhesionVector.y,
                                node.smoothAdhesionVector.x) - pi / 2.0

                    theta = (0.5 *
                        node.smoothAdhesionVector.angle(Vector((0, 0, -1)), 0))

                    # Find the size weight
                    sizeWeight = 1.5 - (cos(2 * pi * weight) * 0.5 + 0.5)

                    # Randomise the angles
                    phi += (rand_val() - 0.5) * (1.3 - alignmentWeight)
                    theta += (rand_val() - 0.5) * (1.1 - alignmentWeight)

                    # Calculate the leaf size an append the face to the list
                    leafSize = IVY.ivyLeafSize * sizeWeight

                    for j in range(10):
                        # Generate the probability
                        probability = rand_val()

                        # If we need to grow a leaf, do so
                        if (probability * weight) > IVY.leafProbability:

                            # Generate the random vector
                            randomVector = Vector((rand_val() - 0.5,
                                                   rand_val() - 0.5,
                                                   rand_val() - 0.5,
                                                   ))

                            # Find the leaf center
                            center = (node.pos.lerp(nodeNext.pos, j / 10.0) +
                                               IVY.ivyLeafSize * randomVector)

                            # For each of the verts, rotate/scale and append
                            basisVecX = Vector((1, 0, 0))
                            basisVecY = Vector((0, 1, 0))

                            horiRot = rotMat(theta, 3, 'X')
                            vertRot = rotMat(phi, 3, 'Z')

                            basisVecX.rotate(horiRot)
                            basisVecY.rotate(horiRot)

                            basisVecX.rotate(vertRot)
                            basisVecY.rotate(vertRot)

                            basisVecX *= leafSize
                            basisVecY *= leafSize

                            addV([k1 * basisVecX + k2 * basisVecY + center for
                                                           k1, k2 in signList])

    # Add the object and link to scene
    newCurve = bpy.data.objects.new("IVY_Curve", curve)
    bpy.context.scene.objects.link(newCurve)

    if growLeaves:
        faceList = [[4 * i + l for l in range(4)] for i in
                                                     range(len(vertList) // 4)]

        # Generate the new leaf mesh and link
        me = bpy.data.meshes.new('IvyLeaf')
        me.from_pydata(vertList, [], faceList)
        me.update(calc_edges=True)
        ob = bpy.data.objects.new('IvyLeaf', me)
        bpy.context.scene.objects.link(ob)

        tex = me.uv_textures.new("Leaves")

        # Set the uv texture coords
        # TODO, this is non-functional, default uvs are ok?
        '''
        for d in tex.data:
            uv1, uv2, uv3, uv4 = signList
        '''

        ob.parent = newCurve
Example #58
0
def write_leveldata(context, filepath, overwrite_existing, clean):
    print("running write_leveldata...")

    #prepare axes
    xx = 0
    yx = 2
    zx = 1

    xm = +1
    ym = +1
    zm = -1

    #activate object mode and deselect all objects
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set( mode = 'OBJECT' )
    bpy.ops.object.select_all( action = 'DESELECT' )

    #apend convenience methods
    setattr( xml.dom.minidom.Element, 'appendElement', appendElement )
    setattr( xml.dom.minidom.Element, 'appendTextElement', appendTextElement )

    #create xml document
    doc = xml.dom.minidom.Document()
    rootElem = doc.createElement( 'Level' )
    doc.appendChild( rootElem )

    directory = os.path.dirname( filepath ) + '/'

    if clean:
        for file in os.listdir( directory ):
            if re.search( '.*\.bmd$|.*.\.xml$|.*\.png$', file ) != None:
                os.remove( directory + file )

    #add data to dom
    for ob in bpy.context.scene.objects:
        if ob.type == 'MESH':
            if 'noexport' in ob.keys():
                continue
            elif 'player' in ob.keys():
                #player start
                elem = rootElem.appendElement( doc, 'Player' )
                pos = elem.appendElement( doc, 'StartPosition' )
                pos.appendTextElement( doc, 'X', str( ob.location[xx] * xm ) )
                pos.appendTextElement( doc, 'Y', str( ob.location[yx] * ym ) )
                pos.appendTextElement( doc, 'Z', str( ob.location[zx] * zm ) )
            elif 'direction' in ob.keys():
                elem = rootElem.appendElement( doc, 'DirectionChanger' )
                pos = elem.appendElement( doc, 'Position' )
                pos.appendTextElement( doc, 'X', str( ob.location[xx] * xm ) )
                pos.appendTextElement( doc, 'Y', str( ob.location[yx] * ym ) )
                pos.appendTextElement( doc, 'Z', str( ob.location[zx] * zm ) )

                d = Vector()
                d[xx] = 0;
                d[yx] = 0;
                d[zx] = 1;
                d.rotate( ob.rotation_euler )

                direction = elem.appendElement( doc, 'Direction' )
                direction.appendTextElement( doc, 'X', str( d[xx] * xm ) )
                direction.appendTextElement( doc, 'Y', str( d[yx] * ym ) )
                direction.appendTextElement( doc, 'Z', str( d[zx] * zm ) )

                elem.appendTextElement( doc, 'Radius', str( ob.dimensions[0] / 2 ) )

                mode = 'Fixed'
                if ob.id_data['direction'] == 'free':
                    mode = 'Free'

                elem.appendTextElement( doc, 'Mode', mode )
            else:
                #level geometry
                name = ob.name
                if len( ob.users_group ) > 0:
                    if( ob.users_group[0].name == 'NoCollision' ):
                        if len( ob.users_group ) > 1:
                            name = ob.users_group[1].name
                    else:
                        name = ob.users_group[0].name

                if overwrite_existing or not os.path.exists( directory + name + '.bmd' ):
                    bpy.ops.object.select_name( name = ob.name )
                    bpy.ops.object.mode_set( mode = 'OBJECT' )
                    bpy.ops.export_mesh.bmd( filepath = directory + name + '.bmd' )
                    bpy.ops.object.select_all( action = 'DESELECT' )

                elem = rootElem.appendElement( doc, 'Mesh' )
                elem.appendTextElement( doc, 'File', name + '.bmd' )

                pos = elem.appendElement( doc, 'Position' )
                pos.appendTextElement( doc, 'X', str( ob.location[xx] * xm ) )
                pos.appendTextElement( doc, 'Y', str( ob.location[yx] * ym ) )
                pos.appendTextElement( doc, 'Z', str( ob.location[zx] * zm ) )

                rot = elem.appendElement( doc, 'Rotation' )
                rot.appendTextElement( doc, 'X', str( ob.rotation_euler[xx] * xm ) )
                rot.appendTextElement( doc, 'Y', str( ob.rotation_euler[yx] * ym ) )
                rot.appendTextElement( doc, 'Z', str( ob.rotation_euler[zx] * zm ) )

                noCollision = 'False'

                for group in ob.users_group:
                    if group.name == 'NoCollision':
                        noCollision = 'True'
                elem.appendTextElement( doc, 'NoCollision', noCollision )
        elif ob.type == 'CURVE':
            if ob.data.splines[0].type == 'BEZIER' and 'enemy' in ob.keys():
                #enemy paths
                elem = rootElem.appendElement( doc, 'Enemy' )
                elem.appendTextElement( doc, 'Name', ob.id_data['enemy'] )

                hp = 3
                if 'hitpoints' in ob.keys():
                    hp = ob.id_data['hitpoints']

                elem.appendTextElement( doc, 'Hitpoints', str( hp ) )
                elem.appendTextElement( doc, 'Looping', str( ob.data.splines[0].use_cyclic_u ) )
                numNodes = len( ob.data.splines[0].bezier_points ) - 1

                for index in range( 0, numNodes ):
                    node = ob.data.splines[0].bezier_points[index]
                    nx = ob.location[xx] * xm
                    ny = ob.location[yx] * ym
                    nz = ob.location[zx] * zm
                    point = elem.appendElement( doc, 'PathNode' )
                    point.appendTextElement( doc, 'X', str( node.co[xx] * xm + nx ) )
                    point.appendTextElement( doc, 'Y', str( node.co[yx] * ym + ny ) )
                    point.appendTextElement( doc, 'Z', str( node.co[zx] * zm + nz) )
                    point = elem.appendElement( doc, 'PathNode' )
                    point.appendTextElement( doc, 'X', str( node.handle_right[xx] * xm + nx ) )
                    point.appendTextElement( doc, 'Y', str( node.handle_right[yx] * ym + ny ) )
                    point.appendTextElement( doc, 'Z', str( node.handle_right[zx] * zm + nz ) )
                    node = ob.data.splines[0].bezier_points[index + 1]
                    point = elem.appendElement( doc, 'PathNode' )
                    point.appendTextElement( doc, 'X', str( node.handle_left[xx] * xm + nx ) )
                    point.appendTextElement( doc, 'Y', str( node.handle_left[yx] * ym + ny ) )
                    point.appendTextElement( doc, 'Z', str( node.handle_left[zx] * zm + nz ) )
                    point = elem.appendElement( doc, 'PathNode' )
                    point.appendTextElement( doc, 'X', str( node.co[xx] * xm + nx ) )
                    point.appendTextElement( doc, 'Y', str( node.co[yx] * ym + ny ) )
                    point.appendTextElement( doc, 'Z', str( node.co[zx] * zm + nz ) )

    #write xml
    file = open( filepath, 'w+' )
    file.write( doc.toprettyxml() )
    #file.write( doc.toxml() )
    file.close()
    return {'FINISHED'}
def extract_primitives(glTF, blender_mesh, blender_vertex_groups, modifiers, export_settings):
    """
    Extract primitives from a mesh. Polygons are triangulated and sorted by material.

    Furthermore, primitives are split up, if the indices range is exceeded.
    Finally, triangles are also split up/duplicated, if face normals are used instead of vertex normals.
    """
    print_console('INFO', 'Extracting primitive: ' + blender_mesh.name)

    use_tangents = False
    if blender_mesh.uv_layers.active and len(blender_mesh.uv_layers) > 0:
        try:
            blender_mesh.calc_tangents()
            use_tangents = True
        except Exception:
            print_console('WARNING', 'Could not calculate tangents. Please try to triangulate the mesh first.')

    #

    material_map = {}

    #
    # Gathering position, normal and tex_coords.
    #
    no_material_attributes = {
        POSITION_ATTRIBUTE: [],
        NORMAL_ATTRIBUTE: []
    }

    if use_tangents:
        no_material_attributes[TANGENT_ATTRIBUTE] = []

    #
    # Directory of materials with its primitive.
    #
    no_material_primitives = {
        MATERIAL_ID: '',
        INDICES_ID: [],
        ATTRIBUTES_ID: no_material_attributes
    }

    material_name_to_primitives = {'': no_material_primitives}

    #

    vertex_index_to_new_indices = {}

    material_map[''] = vertex_index_to_new_indices

    #
    # Create primitive for each material.
    #
    for blender_material in blender_mesh.materials:
        if blender_material is None:
            continue

        attributes = {
            POSITION_ATTRIBUTE: [],
            NORMAL_ATTRIBUTE: []
        }

        if use_tangents:
            attributes[TANGENT_ATTRIBUTE] = []

        primitive = {
            MATERIAL_ID: blender_material.name,
            INDICES_ID: [],
            ATTRIBUTES_ID: attributes
        }

        material_name_to_primitives[blender_material.name] = primitive

        #

        vertex_index_to_new_indices = {}

        material_map[blender_material.name] = vertex_index_to_new_indices

    tex_coord_max = 0
    if blender_mesh.uv_layers.active:
        tex_coord_max = len(blender_mesh.uv_layers)

    #

    vertex_colors = {}

    color_index = 0
    for vertex_color in blender_mesh.vertex_colors:
        vertex_color_name = COLOR_PREFIX + str(color_index)
        vertex_colors[vertex_color_name] = vertex_color

        color_index += 1
        if color_index >= GLTF_MAX_COLORS:
            break
    color_max = color_index

    #

    bone_max = 0
    for blender_polygon in blender_mesh.polygons:
        for loop_index in blender_polygon.loop_indices:
            vertex_index = blender_mesh.loops[loop_index].vertex_index
            bones_count = len(blender_mesh.vertices[vertex_index].groups)
            if bones_count > 0:
                if bones_count % 4 == 0:
                    bones_count -= 1
                bone_max = max(bone_max, bones_count // 4 + 1)

    #

    morph_max = 0

    blender_shape_keys = []

    if blender_mesh.shape_keys is not None:
        morph_max = len(blender_mesh.shape_keys.key_blocks) - 1

        for blender_shape_key in blender_mesh.shape_keys.key_blocks:
            if blender_shape_key != blender_shape_key.relative_key:
                blender_shape_keys.append(ShapeKey(
                    blender_shape_key,
                    blender_shape_key.normals_vertex_get(),  # calculate vertex normals for this shape key
                    blender_shape_key.normals_polygon_get()))  # calculate polygon normals for this shape key

    #
    # Convert polygon to primitive indices and eliminate invalid ones. Assign to material.
    #
    for blender_polygon in blender_mesh.polygons:
        export_color = True

        #

        if blender_polygon.material_index < 0 or blender_polygon.material_index >= len(blender_mesh.materials) or \
                blender_mesh.materials[blender_polygon.material_index] is None:
            primitive = material_name_to_primitives['']
            vertex_index_to_new_indices = material_map['']
        else:
            primitive = material_name_to_primitives[blender_mesh.materials[blender_polygon.material_index].name]
            vertex_index_to_new_indices = material_map[blender_mesh.materials[blender_polygon.material_index].name]
        #

        attributes = primitive[ATTRIBUTES_ID]

        face_normal = blender_polygon.normal
        face_tangent = Vector((0.0, 0.0, 0.0))
        face_bitangent = Vector((0.0, 0.0, 0.0))
        if use_tangents:
            for loop_index in blender_polygon.loop_indices:
                temp_vertex = blender_mesh.loops[loop_index]
                face_tangent += temp_vertex.tangent
                face_bitangent += temp_vertex.bitangent

            face_tangent.normalize()
            face_bitangent.normalize()

        #

        indices = primitive[INDICES_ID]

        loop_index_list = []

        if len(blender_polygon.loop_indices) == 3:
            loop_index_list.extend(blender_polygon.loop_indices)
        elif len(blender_polygon.loop_indices) > 3:
            # Triangulation of polygon. Using internal function, as non-convex polygons could exist.
            polyline = []

            for loop_index in blender_polygon.loop_indices:
                vertex_index = blender_mesh.loops[loop_index].vertex_index
                v = blender_mesh.vertices[vertex_index].co
                polyline.append(Vector((v[0], v[1], v[2])))

            triangles = tessellate_polygon((polyline,))

            for triangle in triangles:
                loop_index_list.append(blender_polygon.loop_indices[triangle[0]])
                loop_index_list.append(blender_polygon.loop_indices[triangle[2]])
                loop_index_list.append(blender_polygon.loop_indices[triangle[1]])
        else:
            continue

        for loop_index in loop_index_list:
            vertex_index = blender_mesh.loops[loop_index].vertex_index

            if vertex_index_to_new_indices.get(vertex_index) is None:
                vertex_index_to_new_indices[vertex_index] = []

            #

            v = None
            n = None
            t = None
            b = None
            uvs = []
            colors = []
            joints = []
            weights = []

            target_positions = []
            target_normals = []
            target_tangents = []

            vertex = blender_mesh.vertices[vertex_index]

            v = convert_swizzle_location(vertex.co, export_settings)
            if blender_polygon.use_smooth:
                if blender_mesh.has_custom_normals:
                    n = convert_swizzle_location(blender_mesh.loops[loop_index].normal, export_settings)
                else:
                    n = convert_swizzle_location(vertex.normal, export_settings)
                if use_tangents:
                    t = convert_swizzle_tangent(blender_mesh.loops[loop_index].tangent, export_settings)
                    b = convert_swizzle_location(blender_mesh.loops[loop_index].bitangent, export_settings)
            else:
                n = convert_swizzle_location(face_normal, export_settings)
                if use_tangents:
                    t = convert_swizzle_tangent(face_tangent, export_settings)
                    b = convert_swizzle_location(face_bitangent, export_settings)

            if use_tangents:
                tv = Vector((t[0], t[1], t[2]))
                bv = Vector((b[0], b[1], b[2]))
                nv = Vector((n[0], n[1], n[2]))

                if (nv.cross(tv)).dot(bv) < 0.0:
                    t[3] = -1.0

            if blender_mesh.uv_layers.active:
                for tex_coord_index in range(0, tex_coord_max):
                    uv = blender_mesh.uv_layers[tex_coord_index].data[loop_index].uv
                    uvs.append([uv.x, 1.0 - uv.y])

            #

            if color_max > 0 and export_color:
                for color_index in range(0, color_max):
                    color_name = COLOR_PREFIX + str(color_index)
                    color = vertex_colors[color_name].data[loop_index].color
                    colors.append([
                        color_srgb_to_scene_linear(color[0]),
                        color_srgb_to_scene_linear(color[1]),
                        color_srgb_to_scene_linear(color[2]),
                        1.0
                    ])

            #

            bone_count = 0

            if blender_vertex_groups is not None and vertex.groups is not None and len(vertex.groups) > 0 and export_settings[gltf2_blender_export_keys.SKINS]:
                joint = []
                weight = []
                vertex_groups = vertex.groups
                if not export_settings['gltf_all_vertex_influences']:
                    # sort groups by weight descending
                    vertex_groups = sorted(vertex.groups, key=attrgetter('weight'), reverse=True)
                for group_element in vertex_groups:

                    if len(joint) == 4:
                        bone_count += 1
                        joints.append(joint)
                        weights.append(weight)
                        joint = []
                        weight = []

                    #

                    joint_weight = group_element.weight
                    if joint_weight <= 0.0:
                        continue

                    #

                    vertex_group_index = group_element.group
                    vertex_group_name = blender_vertex_groups[vertex_group_index].name

                    joint_index = None

                    if modifiers is not None:
                        modifiers_dict = {m.type: m for m in modifiers}
                        if "ARMATURE" in modifiers_dict:
                            modifier = modifiers_dict["ARMATURE"]
                            armature = modifier.object
                            if armature:
                                skin = gltf2_blender_gather_skins.gather_skin(armature, modifier.id_data, export_settings)
                                for index, j in enumerate(skin.joints):
                                    if j.name == vertex_group_name:
                                        joint_index = index
                                        break

                    #
                    if joint_index is not None:
                        joint.append(joint_index)
                        weight.append(joint_weight)

                if len(joint) > 0:
                    bone_count += 1

                    for fill in range(0, 4 - len(joint)):
                        joint.append(0)
                        weight.append(0.0)

                    joints.append(joint)
                    weights.append(weight)

            for fill in range(0, bone_max - bone_count):
                joints.append([0, 0, 0, 0])
                weights.append([0.0, 0.0, 0.0, 0.0])

            #

            if morph_max > 0 and export_settings[gltf2_blender_export_keys.MORPH]:
                for morph_index in range(0, morph_max):
                    blender_shape_key = blender_shape_keys[morph_index]

                    v_morph = convert_swizzle_location(blender_shape_key.shape_key.data[vertex_index].co,
                                                       export_settings)

                    # Store delta.
                    v_morph -= v

                    target_positions.append(v_morph)

                    #

                    n_morph = None

                    if blender_polygon.use_smooth:
                        temp_normals = blender_shape_key.vertex_normals
                        n_morph = (temp_normals[vertex_index * 3 + 0], temp_normals[vertex_index * 3 + 1],
                                   temp_normals[vertex_index * 3 + 2])
                    else:
                        temp_normals = blender_shape_key.polygon_normals
                        n_morph = (
                            temp_normals[blender_polygon.index * 3 + 0], temp_normals[blender_polygon.index * 3 + 1],
                            temp_normals[blender_polygon.index * 3 + 2])

                    n_morph = convert_swizzle_location(n_morph, export_settings)

                    # Store delta.
                    n_morph -= n

                    target_normals.append(n_morph)

                    #

                    if use_tangents:
                        rotation = n_morph.rotation_difference(n)

                        t_morph = Vector((t[0], t[1], t[2]))

                        t_morph.rotate(rotation)

                        target_tangents.append(t_morph)

            #
            #

            create = True

            for current_new_index in vertex_index_to_new_indices[vertex_index]:
                found = True

                for i in range(0, 3):
                    if attributes[POSITION_ATTRIBUTE][current_new_index * 3 + i] != v[i]:
                        found = False
                        break

                    if attributes[NORMAL_ATTRIBUTE][current_new_index * 3 + i] != n[i]:
                        found = False
                        break

                if use_tangents:
                    for i in range(0, 4):
                        if attributes[TANGENT_ATTRIBUTE][current_new_index * 4 + i] != t[i]:
                            found = False
                            break

                if not found:
                    continue

                for tex_coord_index in range(0, tex_coord_max):
                    uv = uvs[tex_coord_index]

                    tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)
                    for i in range(0, 2):
                        if attributes[tex_coord_id][current_new_index * 2 + i] != uv[i]:
                            found = False
                            break

                if export_color:
                    for color_index in range(0, color_max):
                        color = colors[color_index]

                        color_id = COLOR_PREFIX + str(color_index)
                        for i in range(0, 3):
                            # Alpha is always 1.0 - see above.
                            current_color = attributes[color_id][current_new_index * 4 + i]
                            if color_srgb_to_scene_linear(current_color) != color[i]:
                                found = False
                                break

                if export_settings[gltf2_blender_export_keys.SKINS]:
                    for bone_index in range(0, bone_max):
                        joint = joints[bone_index]
                        weight = weights[bone_index]

                        joint_id = JOINTS_PREFIX + str(bone_index)
                        weight_id = WEIGHTS_PREFIX + str(bone_index)
                        for i in range(0, 4):
                            if attributes[joint_id][current_new_index * 4 + i] != joint[i]:
                                found = False
                                break
                            if attributes[weight_id][current_new_index * 4 + i] != weight[i]:
                                found = False
                                break

                if export_settings[gltf2_blender_export_keys.MORPH]:
                    for morph_index in range(0, morph_max):
                        target_position = target_positions[morph_index]
                        target_normal = target_normals[morph_index]
                        if use_tangents:
                            target_tangent = target_tangents[morph_index]

                        target_position_id = MORPH_POSITION_PREFIX + str(morph_index)
                        target_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)
                        target_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)
                        for i in range(0, 3):
                            if attributes[target_position_id][current_new_index * 3 + i] != target_position[i]:
                                found = False
                                break
                            if attributes[target_normal_id][current_new_index * 3 + i] != target_normal[i]:
                                found = False
                                break
                            if use_tangents:
                                if attributes[target_tangent_id][current_new_index * 3 + i] != target_tangent[i]:
                                    found = False
                                    break

                if found:
                    indices.append(current_new_index)

                    create = False
                    break

            if not create:
                continue

            new_index = 0

            if primitive.get('max_index') is not None:
                new_index = primitive['max_index'] + 1

            primitive['max_index'] = new_index

            vertex_index_to_new_indices[vertex_index].append(new_index)

            #
            #

            indices.append(new_index)

            #

            attributes[POSITION_ATTRIBUTE].extend(v)
            attributes[NORMAL_ATTRIBUTE].extend(n)
            if use_tangents:
                attributes[TANGENT_ATTRIBUTE].extend(t)

            if blender_mesh.uv_layers.active:
                for tex_coord_index in range(0, tex_coord_max):
                    tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)

                    if attributes.get(tex_coord_id) is None:
                        attributes[tex_coord_id] = []

                    attributes[tex_coord_id].extend(uvs[tex_coord_index])

            if export_color:
                for color_index in range(0, color_max):
                    color_id = COLOR_PREFIX + str(color_index)

                    if attributes.get(color_id) is None:
                        attributes[color_id] = []

                    attributes[color_id].extend(colors[color_index])

            if export_settings[gltf2_blender_export_keys.SKINS]:
                for bone_index in range(0, bone_max):
                    joint_id = JOINTS_PREFIX + str(bone_index)

                    if attributes.get(joint_id) is None:
                        attributes[joint_id] = []

                    attributes[joint_id].extend(joints[bone_index])

                    weight_id = WEIGHTS_PREFIX + str(bone_index)

                    if attributes.get(weight_id) is None:
                        attributes[weight_id] = []

                    attributes[weight_id].extend(weights[bone_index])

            if export_settings[gltf2_blender_export_keys.MORPH]:
                for morph_index in range(0, morph_max):
                    target_position_id = MORPH_POSITION_PREFIX + str(morph_index)

                    if attributes.get(target_position_id) is None:
                        attributes[target_position_id] = []

                    attributes[target_position_id].extend(target_positions[morph_index])

                    target_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)

                    if attributes.get(target_normal_id) is None:
                        attributes[target_normal_id] = []

                    attributes[target_normal_id].extend(target_normals[morph_index])

                    if use_tangents:
                        target_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)

                        if attributes.get(target_tangent_id) is None:
                            attributes[target_tangent_id] = []

                        attributes[target_tangent_id].extend(target_tangents[morph_index])

    #
    # Add primitive plus split them if needed.
    #

    result_primitives = []

    for material_name, primitive in material_name_to_primitives.items():
        export_color = True

        #

        indices = primitive[INDICES_ID]

        if len(indices) == 0:
            continue

        position = primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]
        normal = primitive[ATTRIBUTES_ID][NORMAL_ATTRIBUTE]
        if use_tangents:
            tangent = primitive[ATTRIBUTES_ID][TANGENT_ATTRIBUTE]
        tex_coords = []
        for tex_coord_index in range(0, tex_coord_max):
            tex_coords.append(primitive[ATTRIBUTES_ID][TEXCOORD_PREFIX + str(tex_coord_index)])
        colors = []
        if export_color:
            for color_index in range(0, color_max):
                tex_coords.append(primitive[ATTRIBUTES_ID][COLOR_PREFIX + str(color_index)])
        joints = []
        weights = []
        if export_settings[gltf2_blender_export_keys.SKINS]:
            for bone_index in range(0, bone_max):
                joints.append(primitive[ATTRIBUTES_ID][JOINTS_PREFIX + str(bone_index)])
                weights.append(primitive[ATTRIBUTES_ID][WEIGHTS_PREFIX + str(bone_index)])

        target_positions = []
        target_normals = []
        target_tangents = []
        if export_settings[gltf2_blender_export_keys.MORPH]:
            for morph_index in range(0, morph_max):
                target_positions.append(primitive[ATTRIBUTES_ID][MORPH_POSITION_PREFIX + str(morph_index)])
                target_normals.append(primitive[ATTRIBUTES_ID][MORPH_NORMAL_PREFIX + str(morph_index)])
                if use_tangents:
                    target_tangents.append(primitive[ATTRIBUTES_ID][MORPH_TANGENT_PREFIX + str(morph_index)])

        #

        count = len(indices)

        if count == 0:
            continue

        max_index = max(indices)

        #

        # NOTE: Values used by some graphics APIs as "primitive restart" values are disallowed.
        # Specifically, the value 65535 (in UINT16) cannot be used as a vertex index.
        # https://github.com/KhronosGroup/glTF/issues/1142
        # https://github.com/KhronosGroup/glTF/pull/1476/files

        range_indices = 65535

        #

        if max_index >= range_indices:
            #
            # Splitting result_primitives.
            #

            # At start, all indices are pending.
            pending_attributes = {
                POSITION_ATTRIBUTE: [],
                NORMAL_ATTRIBUTE: []
            }

            if use_tangents:
                pending_attributes[TANGENT_ATTRIBUTE] = []

            pending_primitive = {
                MATERIAL_ID: material_name,
                INDICES_ID: [],
                ATTRIBUTES_ID: pending_attributes
            }

            pending_primitive[INDICES_ID].extend(indices)

            pending_attributes[POSITION_ATTRIBUTE].extend(position)
            pending_attributes[NORMAL_ATTRIBUTE].extend(normal)
            if use_tangents:
                pending_attributes[TANGENT_ATTRIBUTE].extend(tangent)
            tex_coord_index = 0
            for tex_coord in tex_coords:
                pending_attributes[TEXCOORD_PREFIX + str(tex_coord_index)] = tex_coord
                tex_coord_index += 1
            if export_color:
                color_index = 0
                for color in colors:
                    pending_attributes[COLOR_PREFIX + str(color_index)] = color
                    color_index += 1
            if export_settings[gltf2_blender_export_keys.SKINS]:
                joint_index = 0
                for joint in joints:
                    pending_attributes[JOINTS_PREFIX + str(joint_index)] = joint
                    joint_index += 1
                weight_index = 0
                for weight in weights:
                    pending_attributes[WEIGHTS_PREFIX + str(weight_index)] = weight
                    weight_index += 1
            if export_settings[gltf2_blender_export_keys.MORPH]:
                morph_index = 0
                for target_position in target_positions:
                    pending_attributes[MORPH_POSITION_PREFIX + str(morph_index)] = target_position
                    morph_index += 1
                morph_index = 0
                for target_normal in target_normals:
                    pending_attributes[MORPH_NORMAL_PREFIX + str(morph_index)] = target_normal
                    morph_index += 1
                if use_tangents:
                    morph_index = 0
                    for target_tangent in target_tangents:
                        pending_attributes[MORPH_TANGENT_PREFIX + str(morph_index)] = target_tangent
                        morph_index += 1

            pending_indices = pending_primitive[INDICES_ID]

            # Continue until all are processed.
            while len(pending_indices) > 0:

                process_indices = pending_primitive[INDICES_ID]
                max_index = max(process_indices)

                pending_indices = []

                #
                #

                all_local_indices = []

                for i in range(0, (max_index // range_indices) + 1):
                    all_local_indices.append([])

                #
                #

                # For all faces ...
                for face_index in range(0, len(process_indices), 3):

                    written = False

                    face_min_index = min(process_indices[face_index + 0], process_indices[face_index + 1],
                                         process_indices[face_index + 2])
                    face_max_index = max(process_indices[face_index + 0], process_indices[face_index + 1],
                                         process_indices[face_index + 2])

                    # ... check if it can be but in a range of maximum indices.
                    for i in range(0, (max_index // range_indices) + 1):
                        offset = i * range_indices

                        # Yes, so store the primitive with its indices.
                        if face_min_index >= offset and face_max_index < offset + range_indices:
                            all_local_indices[i].extend(
                                [process_indices[face_index + 0], process_indices[face_index + 1],
                                 process_indices[face_index + 2]])

                            written = True
                            break

                    # If not written, the triangle face has indices from different ranges.
                    if not written:
                        pending_indices.extend([process_indices[face_index + 0], process_indices[face_index + 1],
                                                process_indices[face_index + 2]])

                # Only add result_primitives, which do have indices in it.
                for local_indices in all_local_indices:
                    if len(local_indices) > 0:
                        current_primitive = extract_primitive_floor(pending_primitive, local_indices, use_tangents)

                        result_primitives.append(current_primitive)

                        print_console('DEBUG', 'Adding primitive with splitting. Indices: ' + str(
                            len(current_primitive[INDICES_ID])) + ' Vertices: ' + str(
                            len(current_primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]) // 3))

                # Process primitive faces having indices in several ranges.
                if len(pending_indices) > 0:
                    pending_primitive = extract_primitive_pack(pending_primitive, pending_indices, use_tangents)

                    print_console('DEBUG', 'Creating temporary primitive for splitting')

        else:
            #
            # No splitting needed.
            #
            result_primitives.append(primitive)

            print_console('DEBUG', 'Adding primitive without splitting. Indices: ' + str(
                len(primitive[INDICES_ID])) + ' Vertices: ' + str(
                len(primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]) // 3))

    print_console('INFO', 'Primitives created: ' + str(len(result_primitives)))

    return result_primitives
class Turtle(object):

    def __init__(self,
                 tropism=(0, 0, 0),
                 tropismsize=0,
                 pitch_angle=radians(30),
                 yaw_angle=radians(30),
                 roll_angle=radians(30),
                 radius=0.2,
                 iseed=42):
        self.tropism = Vector(tropism).normalized()
        self.magnitude = tropismsize
        self.forward = Vector((1, 0, 0))
        self.up = Vector((0, 0, 1))
        self.right = self.forward.cross(self.up)
        self.stack = []
        self.stack_curly = []
        self.position = Vector((0, 0, 0))
        self.pitch_angle = pitch_angle
        self.yaw_angle = yaw_angle
        self.roll_angle = roll_angle
        self.radius = radius
        self.__init_terminals()
        seed(iseed)

    def __init_terminals(self):
        """
        Initialize a map of predefined terminals.
        """
        self.terminals = {
            '+': self.term_plus,
            '-': self.term_minus,
            '[': self.term_push,
            ']': self.term_pop,
            '(': self.term_push_curly,
            ')': self.term_pop_curly,
            '/': self.term_slash,
            '\\': self.term_backslash,
            '<': self.term_less,
            '>': self.term_greater,
            '&': self.term_amp,
            '!': self.term_expand,
            '@': self.term_shrink,
            '#': self.term_fatten,
            '%': self.term_slink,
            '^': self.term_expand_g,
            '*': self.term_shrink_g,
            '=': self.term_fatten_g,
            '|': self.term_slink_g,
            'F': self.term_edge,
            'Q': self.term_quad,
            # '{': self.term_object
            }

    def apply_tropism(self):
        # tropism is a normalized vector
        t = self.tropism * self.magnitude
        tf = self.forward + t
        tf.normalize()
        q = tf.rotation_difference(self.forward)
        self.forward.rotate(q)
        self.up.rotate(q)
        self.right.rotate(q)

    def term_plus(self, value=None):
        val = radians(value) if not value is None else self.pitch_angle
        r = Matrix.Rotation(val, 4, self.right)
        self.forward.rotate(r)
        self.up.rotate(r)

    def term_minus(self, value=None):
        val = radians(value) if not value is None else self.pitch_angle
        r = Matrix.Rotation(-val, 4, self.right)
        self.forward.rotate(r)
        self.up.rotate(r)

    def term_amp(self, value=30):
        k = (random() - 0.5) * value
        self.term_plus(value=k)
        k = (random() - 0.5) * value
        self.term_slash(value=k)

    def term_slash(self, value=None):
        r = Matrix.Rotation(radians(value) if not value is None
                            else self.yaw_angle, 4, self.up)
        self.forward.rotate(r)
        self.right.rotate(r)

    def term_backslash(self, value=None):
        r = Matrix.Rotation(-radians(value) if not value is None
                            else -self.yaw_angle, 4, self.up)
        self.forward.rotate(r)
        self.right.rotate(r)

    def term_less(self, value=None):
        r = Matrix.Rotation(radians(value) if not value is None
                            else self.roll_angle, 4, self.forward)
        self.up.rotate(r)
        self.right.rotate(r)

    def term_greater(self, value=None):
        r = Matrix.Rotation(-radians(value) if not value is None
                            else -self.roll_angle, 4, self.forward)
        self.up.rotate(r)
        self.right.rotate(r)

    def term_pop(self, value=None):
        t = self.stack.pop()
        (self.forward,
         self.up,
         self.right,
         self.position,
         self.radius) = t

    def term_push(self, value=None):
        t = (self.forward.copy(),
             self.up.copy(),
             self.right.copy(),
             self.position.copy(),
             self.radius)
        self.stack.append(t)

    def term_pop_curly(self, value=None):
        t = self.stack_curly.pop()
        (self.forward,
         self.up,
         self.right,
         self.position,
         self.radius) = t

    def term_push_curly(self, value=None):
        t = (self.forward.copy(),
             self.up.copy(),
             self.right.copy(),
             self.position.copy(),
             self.radius)
        self.stack_curly.append(t)

    expand_shrink_factor = 0.1
    fatten_slink_factor = 0.045
    expand_shrink_factor_g = 0.2
    fatten_slink_factor_g = 0.48

    def term_expand(self, value=1 + expand_shrink_factor):
        self.forward *= value
        self.up *= value
        self.right *= value

    def term_shrink(self, value=1 - expand_shrink_factor):
        self.forward *= value
        self.up *= value
        self.right *= value

    def term_fatten(self, value=1 + fatten_slink_factor):
        self.radius *= value

    def term_slink(self, value=1 - fatten_slink_factor):
        self.radius *= value

    def term_expand_g(self, value=1 + expand_shrink_factor_g):
        self.term_expand(value)

    def term_shrink_g(self, value=1 - expand_shrink_factor_g):
        self.term_shrink(value)

    def term_fatten_g(self, value=1 + fatten_slink_factor_g):
        self.term_fatten(value)

    def term_slink_g(self, value=1 - fatten_slink_factor_g):
        self.term_slink(value)

    def term_edge(self, value=None):
        s = self.position.copy()
        self.apply_tropism()
        self.position += self.forward
        e = self.position.copy()
        return Edge(start=s, end=e, radius=self.radius)

    def term_quad(self, value=0.5):
        return Quad(pos=self.position,
                    right=self.right,
                    up=self.up,
                    forward=self.forward)

    def term_object(self, value=None, name=None):
        s = self.position.copy()
        self.apply_tropism()
        self.position += self.forward
        return BObject(name=name,
                       pos=s,
                       right=self.right,
                       up=self.up,
                       forward=self.forward)

    def interpret(self, s):
        """
        interpret the iterable s, yield Quad, Edge or Object named tuples.
        """
        print('interpret:', s)
        name = ''
        for c in s:
            t = None
            #print(c,name)
            if c == '}':
                t = self.term_object(name=name[1:])
                name = ''
            elif c == '{' or name != '':
                name += c
                continue
            elif name != '':
                continue
            elif c in self.terminals:
                t = self.terminals[c]()
            #print('yield',t)
            if not t is None:
                yield t