def save_md3(settings):
    from mathutils import Euler, Matrix, Vector
    from math import radians
    starttime = time.clock()  # start timer
    fullpath = splitext(settings.savepath)[0]
    modelname = basename(fullpath)
    logname = modelname + ".log"
    logfpath = fullpath + ".log"
    if settings.name == "":
        settings.name = modelname
    dumpall = settings.dumpall
    if settings.logtype == "append":
        log = open(logfpath,"a")
    elif settings.logtype == "overwrite":
        log = open(logfpath,"w")
    elif settings.logtype == "blender":
        log = bpy.data.texts.new(logname)
        log.clear()
    else:
        log = None
    ref_frame = settings.refframe
    if settings.refframe == -1:
        ref_frame = bpy.context.scene.frame_current
    message(log, "###################### BEGIN ######################")
    model = BlenderModelManager(settings.gzdoom, ref_frame)
    # Set up fix transformation matrix
    model.fix_transform *= Matrix.Scale(settings.scale, 4)
    model.fix_transform *= Matrix.Translation(Vector((
        settings.offsetx, settings.offsety, settings.offsetz)))
    rotation_fix = Euler()
    rotation_fix.z = radians(90)
    model.fix_transform *= rotation_fix.to_matrix().to_4x4()
    model.md3.name = settings.name
    # Add objects to model manager
    if len(bpy.context.selected_objects) == 0:
        message(log, "Select an object to export!")
    else:
        # If multiple objects are selected, they are joined together
        for bobject in bpy.context.selected_objects:
            if bobject.type == 'MESH':
                model.add_mesh(bobject)
            elif bobject.type == 'EMPTY':
                model.add_tag(bobject)
    model.setup_frames()
    model.md3.GetSize()
    print_md3(log, model.md3, dumpall)
    model.save(settings.savepath)
    endtime = time.clock() - starttime
    message(log, "Export took {:.3f} seconds".format(endtime))
def PerturbInsideCameraView(minCenterDistance, maxCenterDistance, camera, obj):
    relative_vector = Vector()
    relative_euler_orientation = Euler()    
    relative_euler_orientation.x = random.uniform(-math.pi, math.pi)
    relative_euler_orientation.y = random.uniform(-math.pi, math.pi)
    relative_euler_orientation.z = random.uniform(-math.pi, math.pi)

    #Find a position that is fully inside the camera's frustum
    obj.rotation_mode = 'XYZ'
    for i in range(0, 10000):
        distance = random.uniform(minCenterDistance, maxCenterDistance)
        relative_vector = GetRandomUnitVector()*distance

        if not approx_object_in_camera_view(camera, camera.location + relative_vector,  .15, distance, minCenterDistance, maxCenterDistance):
            continue

        bpy.context.scene.update()
        #print("Updating scene  " + str((time.time() - start )*1000.0) + " milliseconds")

        #Temporarily disabling translation for debugging
        obj.location = camera.location + relative_vector
        obj.rotation_euler = relative_euler_orientation

        #Update world matrix of object to match
        bpy.context.scene.update() 

        #if not object_center_in_camera_view(camera, obj):
        #    continue

        break
        #start = time.time()
        #if mesh_object_vertices_in_camera_view(camera, obj):
        #    print("Fine grain check  " + str((time.time() - start )*1000.0) + " milliseconds")
        #    break
       # print("Fine grain check  " + str((time.time() - start )*1000.0) + " milliseconds")
    return relative_vector, relative_euler_orientation
示例#3
0
def draw_callback_px(self, context):
    font_id = 0
    region = context.region
    UIColor = (0.992, 0.5518, 0.0, 1.0)

    # Cut Type
    RECTANGLE = 0
    LINE = 1
    CIRCLE = 2
    self.carver_prefs = context.preferences.addons[__package__].preferences

    # Color
    color1 = (1.0, 1.0, 1.0, 1.0)
    color2 = UIColor

    #The mouse is outside the active region
    if not self.in_view_3d:
        color1 = color2 = (1.0, 0.2, 0.1, 1.0)

    # Primitives type
    PrimitiveType = "Rectangle"
    if self.CutType == CIRCLE:
        PrimitiveType = "Circle"
    if self.CutType == LINE:
        PrimitiveType = "Line"

    # Width screen
    overlap = context.preferences.system.use_region_overlap

    t_panel_width = 0
    if overlap:
        for region in context.area.regions:
            if region.type == 'TOOLS':
                t_panel_width = region.width

    # Initial position
    region_width = int(region.width / 2.0)
    y_txt = 10

    # Draw the center command from bottom to top

    # Get the size of the text
    text_size = 18 if region.width >= 850 else 12
    blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale,
                          0)), 72)

    # Help Display
    if (self.ObjectMode is False) and (self.ProfileMode is False):

        # Depth Cursor
        TypeStr = "Cursor Depth [" + self.carver_prefs.Key_Depth + "]"
        BoolStr = "(ON)" if self.snapCursor else "(OFF)"
        help_txt = [[TypeStr, BoolStr]]

        # Close poygonal shape
        if self.CreateMode and self.CutType == LINE:
            TypeStr = "Close [" + self.carver_prefs.Key_Close + "]"
            BoolStr = "(ON)" if self.Closed else "(OFF)"
            help_txt += [[TypeStr, BoolStr]]

        if self.CreateMode is False:
            # Apply Booleans
            TypeStr = "Apply Operations [" + self.carver_prefs.Key_Apply + "]"
            BoolStr = "(OFF)" if self.dont_apply_boolean else "(ON)"
            help_txt += [[TypeStr, BoolStr]]

            #Auto update for bevel
            TypeStr = "Bevel Update [" + self.carver_prefs.Key_Update + "]"
            BoolStr = "(ON)" if self.Auto_BevelUpdate else "(OFF)"
            help_txt += [[TypeStr, BoolStr]]

        # Circle subdivisions
        if self.CutType == CIRCLE:
            TypeStr = "Subdivisions [" + self.carver_prefs.Key_Subrem + "][" + self.carver_prefs.Key_Subadd + "]"
            BoolStr = str((int(360 / self.stepAngle[self.step])))
            help_txt += [[TypeStr, BoolStr]]

        if self.CreateMode:
            help_txt += [["Type [Space]", PrimitiveType]]
        else:
            help_txt += [["Cut Type [Space]", PrimitiveType]]

    else:
        # Instantiate
        TypeStr = "Instantiate [" + self.carver_prefs.Key_Instant + "]"
        BoolStr = "(ON)" if self.Instantiate else "(OFF)"
        help_txt = [[TypeStr, BoolStr]]

        # Random rotation
        if self.alt:
            TypeStr = "Random Rotation [" + self.carver_prefs.Key_Randrot + "]"
            BoolStr = "(ON)" if self.RandomRotation else "(OFF)"
            help_txt += [[TypeStr, BoolStr]]

        # Thickness
        if self.BrushSolidify:
            TypeStr = "Thickness [" + self.carver_prefs.Key_Depth + "]"
            if self.ProfileMode:
                BoolStr = str(
                    round(self.ProfileBrush.modifiers["CT_SOLIDIFY"].thickness,
                          2))
            if self.ObjectMode:
                BoolStr = str(
                    round(self.ObjectBrush.modifiers["CT_SOLIDIFY"].thickness,
                          2))
            help_txt += [[TypeStr, BoolStr]]

        # Brush depth
        if (self.ObjectMode):
            TypeStr = "Carve Depth [" + self.carver_prefs.Key_Depth + "]"
            BoolStr = str(round(self.ObjectBrush.data.vertices[0].co.z, 2))
            help_txt += [[TypeStr, BoolStr]]

            TypeStr = "Brush Depth [" + self.carver_prefs.Key_BrushDepth + "]"
            BoolStr = str(round(self.BrushDepthOffset, 2))
            help_txt += [[TypeStr, BoolStr]]

    help_txt, bloc_height, max_option, max_key, comma = get_text_info(
        self, context, help_txt)
    xCmd = region_width - (max_option + max_key + comma) / 2
    draw_string(self,
                color1,
                color2,
                xCmd,
                y_txt,
                help_txt,
                max_option,
                divide=2)

    # Separator (Line)
    LineWidth = (max_option + max_key + comma) / 2
    if region.width >= 850:
        LineWidth = 140

    LineWidth = (max_option + max_key + comma)
    coords = [(int(region_width - LineWidth/2), y_txt + bloc_height + 8), \
        (int(region_width + LineWidth/2), y_txt + bloc_height + 8)]
    draw_shader(self, UIColor, 1, 'LINES', coords, self.carver_prefs.LineWidth)

    # Command Display
    if self.CreateMode and ((self.ObjectMode is False) and
                            (self.ProfileMode is False)):
        BooleanMode = "Create"
    else:
        if self.ObjectMode or self.ProfileMode:
            BooleanType = "Difference) [T]" if self.BoolOps == self.difference else "Union) [T]"
            BooleanMode = \
             "Object Brush (" + BooleanType if self.ObjectMode else "Profil Brush (" + BooleanType
        else:
            BooleanMode = \
             "Difference" if (self.shift is False) and (self.ForceRebool is False) else "Rebool"

    # Display boolean mode
    text_size = 40 if region.width >= 850 else 20
    blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale,
                          0)), 72)

    draw_string(self, color2, color2, region_width - (blf.dimensions(0, BooleanMode)[0]) / 2, \
       y_txt + bloc_height + 16, BooleanMode, 0, divide = 2)

    if region.width >= 850:

        if self.AskHelp is False:
            # "H for Help" text
            blf.size(0,
                     int(round(13 * bpy.context.preferences.view.ui_scale, 0)),
                     72)
            help_txt = "[" + self.carver_prefs.Key_Help + "] for help"
            txt_width = blf.dimensions(0, help_txt)[0]
            txt_height = (blf.dimensions(0, "gM")[1] * 1.45)

            # Draw a rectangle and put the text "H for Help"
            xrect = 40
            yrect = 40
            rect_vertices = [(xrect - 5, yrect - 5), (xrect + txt_width + 5, yrect - 5), \
                 (xrect + txt_width + 5, yrect + txt_height + 5), (xrect - 5, yrect + txt_height + 5)]
            draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', rect_vertices,
                        self.carver_prefs.LineWidth)
            draw_string(self, color1, color2, xrect, yrect, help_txt, 0)

        else:
            #Draw the help text
            xHelp = 30 + t_panel_width
            yHelp = 10

            if self.ObjectMode or self.ProfileMode:
                if self.ProfileMode:
                    help_txt = [["Object Mode", self.carver_prefs.Key_Brush]]
                else:
                    help_txt = [["Cut Mode", self.carver_prefs.Key_Brush]]

            else:
                help_txt =[
                   ["Profil Brush", self.carver_prefs.Key_Brush],\
                   ["Move Cursor", "Ctrl + LMB"]
                   ]

            if (self.ObjectMode is False) and (self.ProfileMode is False):
                if self.CreateMode is False:
                    help_txt +=[
                        ["Create geometry", self.carver_prefs.Key_Create],\
                        ]
                else:
                    help_txt +=[
                        ["Cut", self.carver_prefs.Key_Create],\
                        ]
                if self.CutMode == RECTANGLE:
                    help_txt +=[
                        ["Dimension", "MouseMove"],\
                        ["Move all", "Alt"],\
                        ["Validate", "LMB"],\
                        ["Rebool", "Shift"]
                        ]

                elif self.CutMode == CIRCLE:
                    help_txt +=[
                        ["Rotation and Radius", "MouseMove"],\
                        ["Move all", "Alt"],\
                        ["Subdivision", self.carver_prefs.Key_Subrem + " " + self.carver_prefs.Key_Subadd],\
                        ["Incremental rotation", "Ctrl"],\
                        ["Rebool", "Shift"]
                        ]

                elif self.CutMode == LINE:
                    help_txt +=[
                        ["Dimension", "MouseMove"],\
                        ["Move all", "Alt"],\
                        ["Validate", "Space"],\
                        ["Rebool", "Shift"],\
                        ["Snap", "Ctrl"],\
                        ["Scale Snap", "WheelMouse"],\
                        ]
            else:
                # ObjectMode
                help_txt +=[
                    ["Difference", "Space"],\
                    ["Rebool", "Shift + Space"],\
                    ["Duplicate", "Alt + Space"],\
                    ["Scale", self.carver_prefs.Key_Scale],\
                    ["Rotation", "LMB + Move"],\
                    ["Step Angle", "CTRL + LMB + Move"],\
                    ]

                if self.ProfileMode:
                    help_txt += [[
                        "Previous or Next Profile",
                        self.carver_prefs.Key_Subadd + " " +
                        self.carver_prefs.Key_Subrem
                    ]]

                help_txt +=[
                    ["Create / Delete rows",  chr(8597)],\
                    ["Create / Delete cols",  chr(8596)],\
                    ["Gap for rows or columns",  self.carver_prefs.Key_Gapy + " " + self.carver_prefs.Key_Gapx]
                    ]

            blf.size(0,
                     int(round(15 * bpy.context.preferences.view.ui_scale, 0)),
                     72)
            help_txt, bloc_height, max_option, max_key, comma = get_text_info(
                self, context, help_txt)
            draw_string(self, color1, color2, xHelp, yHelp, help_txt,
                        max_option)

    if self.ProfileMode:
        xrect = region.width - t_panel_width - 80
        yrect = 80
        coords = [(xrect, yrect), (xrect + 60, yrect),
                  (xrect + 60, yrect - 60), (xrect, yrect - 60)]

        # Draw rectangle background in the lower right
        draw_shader(self, (0.0, 0.0, 0.0),
                    0.3,
                    'TRI_FAN',
                    coords,
                    size=self.carver_prefs.LineWidth)

        # Use numpy to get the vertices and indices of the profile object to draw
        WidthProfil = 50
        location = Vector((region.width - t_panel_width - WidthProfil, 50, 0))
        ProfilScale = 20.0
        coords = []
        mesh = bpy.data.meshes[self.Profils[self.nProfil][0]]
        mesh.calc_loop_triangles()
        vertices = np.empty((len(mesh.vertices), 3), 'f')
        indices = np.empty((len(mesh.loop_triangles), 3), 'i')
        mesh.vertices.foreach_get("co",
                                  np.reshape(vertices,
                                             len(mesh.vertices) * 3))
        mesh.loop_triangles.foreach_get(
            "vertices", np.reshape(indices,
                                   len(mesh.loop_triangles) * 3))

        for idx, vals in enumerate(vertices):
            coords.append([
                vals[0] * ProfilScale + location.x,
                vals[1] * ProfilScale + location.y,
                vals[2] * ProfilScale + location.z
            ])

        #Draw the silhouette of the mesh
        draw_shader(self,
                    UIColor,
                    0.5,
                    'TRIS',
                    coords,
                    size=self.carver_prefs.LineWidth,
                    indices=indices)

    if self.CutMode:

        if len(self.mouse_path) > 1:
            x0 = self.mouse_path[0][0]
            y0 = self.mouse_path[0][1]
            x1 = self.mouse_path[1][0]
            y1 = self.mouse_path[1][1]

        # Cut rectangle
        if self.CutType == RECTANGLE:
            coords = [
            (x0 + self.xpos, y0 + self.ypos), (x1 + self.xpos, y0 + self.ypos), \
            (x1 + self.xpos, y1 + self.ypos), (x0 + self.xpos, y1 + self.ypos)
            ]
            indices = ((0, 1, 2), (2, 0, 3))

            self.rectangle_coord = coords

            draw_shader(self,
                        UIColor,
                        1,
                        'LINE_LOOP',
                        coords,
                        size=self.carver_prefs.LineWidth)

            #Draw points
            draw_shader(self, UIColor, 1, 'POINTS', coords, size=3)

            if self.shift or self.CreateMode:
                draw_shader(self,
                            UIColor,
                            0.5,
                            'TRIS',
                            coords,
                            size=self.carver_prefs.LineWidth,
                            indices=indices)

            # Draw grid (based on the overlay options) to show the incremental snapping
            if self.ctrl:
                mini_grid(self, context, UIColor)

        # Cut Line
        elif self.CutType == LINE:
            coords = []
            indices = []
            top_grid = False

            for idx, vals in enumerate(self.mouse_path):
                coords.append([vals[0] + self.xpos, vals[1] + self.ypos])
                indices.append([idx])

            # Draw lines
            if self.Closed:
                draw_shader(self,
                            UIColor,
                            1.0,
                            'LINE_LOOP',
                            coords,
                            size=self.carver_prefs.LineWidth)
            else:
                draw_shader(self,
                            UIColor,
                            1.0,
                            'LINE_STRIP',
                            coords,
                            size=self.carver_prefs.LineWidth)

            # Draw points
            draw_shader(self, UIColor, 1.0, 'POINTS', coords, size=3)

            # Draw polygon
            if (self.shift) or (self.CreateMode and self.Closed):
                draw_shader(self,
                            UIColor,
                            0.5,
                            'TRI_FAN',
                            coords,
                            size=self.carver_prefs.LineWidth)

            # Draw grid (based on the overlay options) to show the incremental snapping
            if self.ctrl:
                mini_grid(self, context, UIColor)

        # Circle Cut
        elif self.CutType == CIRCLE:
            # Create a circle using a tri fan
            tris_coords, indices = draw_circle(self, x0, y0)

            # Remove the vertex in the center to get the outer line of the circle
            line_coords = tris_coords[1:]
            draw_shader(self,
                        UIColor,
                        1.0,
                        'LINE_LOOP',
                        line_coords,
                        size=self.carver_prefs.LineWidth)

            if self.shift or self.CreateMode:
                draw_shader(self,
                            UIColor,
                            0.5,
                            'TRIS',
                            tris_coords,
                            size=self.carver_prefs.LineWidth,
                            indices=indices)

    if (self.ObjectMode
            or self.ProfileMode) and len(self.CurrentSelection) > 0:
        if self.ShowCursor:
            region = context.region
            rv3d = context.space_data.region_3d

            if self.ObjectMode:
                ob = self.ObjectBrush
            if self.ProfileMode:
                ob = self.ProfileBrush
            mat = ob.matrix_world

            # 50% alpha, 2 pixel width line
            bgl.glEnable(bgl.GL_BLEND)

            bbox = [mat @ Vector(b) for b in ob.bound_box]
            objBBDiagonal = objDiagonal(self.CurrentSelection[0])

            if self.shift:
                gl_size = 4
                UIColor = (0.5, 1.0, 0.0, 1.0)
            else:
                gl_size = 2
                UIColor = (1.0, 0.8, 0.0, 1.0)

            line_coords = []
            idx = 0
            CRadius = ((bbox[7] - bbox[0]).length) / 2
            for i in range(int(len(self.CLR_C) / 3)):
                vector3d = (self.CLR_C[idx * 3] * CRadius + self.CurLoc.x, \
                   self.CLR_C[idx * 3 + 1] * CRadius + self.CurLoc.y, \
                   self.CLR_C[idx * 3 + 2] * CRadius + self.CurLoc.z)
                vector2d = bpy_extras.view3d_utils.location_3d_to_region_2d(
                    region, rv3d, vector3d)
                if vector2d is not None:
                    line_coords.append((vector2d[0], vector2d[1]))
                idx += 1
            if len(line_coords) > 0:
                draw_shader(self,
                            UIColor,
                            1.0,
                            'LINE_LOOP',
                            line_coords,
                            size=gl_size)

            # Object display
            if self.quat_rot is not None:
                ob.location = self.CurLoc
                v = Vector()
                v.x = v.y = 0.0
                v.z = self.BrushDepthOffset
                ob.location += self.quat_rot @ v

                e = Euler()
                e.x = 0.0
                e.y = 0.0
                e.z = self.aRotZ / 25.0

                qe = e.to_quaternion()
                qRot = self.quat_rot @ qe
                ob.rotation_mode = 'QUATERNION'
                ob.rotation_quaternion = qRot
                ob.rotation_mode = 'XYZ'

                if self.ProfileMode:
                    if self.ProfileBrush is not None:
                        self.ProfileBrush.location = self.CurLoc
                        self.ProfileBrush.rotation_mode = 'QUATERNION'
                        self.ProfileBrush.rotation_quaternion = qRot
                        self.ProfileBrush.rotation_mode = 'XYZ'

    # Opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
示例#4
0
def duplicateObject(self):
    if self.Instantiate:
        bpy.ops.object.duplicate_move_linked(
            OBJECT_OT_duplicate={
                "linked": True,
                "mode": 'TRANSLATION',
            },
            TRANSFORM_OT_translate={
                "value": (0, 0, 0),
            },
        )
    else:
        bpy.ops.object.duplicate_move(
            OBJECT_OT_duplicate={
                "linked": False,
                "mode": 'TRANSLATION',
            },
            TRANSFORM_OT_translate={
                "value": (0, 0, 0),
            },
        )

    ob_new = bpy.context.active_object

    ob_new.location = self.CurLoc
    v = Vector()
    v.x = v.y = 0.0
    v.z = self.BrushDepthOffset
    ob_new.location += self.qRot * v

    if self.ObjectMode:
        ob_new.scale = self.ObjectBrush.scale
    if self.ProfileMode:
        ob_new.scale = self.ProfileBrush.scale

    e = Euler()
    e.x = e.y = 0.0
    e.z = self.aRotZ / 25.0

    # If duplicate with a grid, no random rotation (each mesh in the grid is already rotated randomly)
    if (self.alt is True) and ((self.nbcol + self.nbrow) < 3):
        if self.RandomRotation:
            e.z += random.random()

    qe = e.to_quaternion()
    qRot = self.qRot * qe
    ob_new.rotation_mode = 'QUATERNION'
    ob_new.rotation_quaternion = qRot
    ob_new.rotation_mode = 'XYZ'

    if (ob_new.display_type == "WIRE") and (self.BrushSolidify is False):
        ob_new.hide_viewport = True

    if self.BrushSolidify:
        ob_new.display_type = "SOLID"
        ob_new.show_in_front = False

    for o in bpy.context.selected_objects:
        UndoAdd(self, "DUPLICATE", o)

    if len(bpy.context.selected_objects) > 0:
        bpy.ops.object.select_all(action='TOGGLE')
    for o in self.all_sel_obj_list:
        o.select_set(True)

    bpy.context.view_layer.objects.active = self.OpsObj
示例#5
0
pos = Vector()
nameOfTire = "Tire"
rot = Euler((0, 0, 0))
mag = Vector((0, 0, 0))
vo = Vector((60.0, 60.0, 60.0))
targetName = "Target"

bpy.data.objects[nameOfTire + "1"].location = Vector((0.3, -0.3, 0))
bpy.data.objects[nameOfTire + "2"].location = Vector((-0.3, 0.3, 0))
bpy.data.objects[nameOfTire + "3"].location = Vector((0.3, 0.3, 0))
bpy.data.objects[nameOfTire + "4"].location = Vector((-0.3, -0.3, 0))

tires = []
frame_num = 10  # frames in animation
rot.x = 90
rot.z = 0
objTarget = bpy.data.objects[str(targetName)]
car = bpy.data.objects["car"]


def rotate(sce):

    speed = mag * vo

    for index in range(1, 5):
        name = str(nameOfTire) + str(index)
        obj = bpy.data.objects[str(name)]
        tires.insert(index, obj)
        rot.y += 1
        vo.y = rot.y * math.pi / 180
        mag.y = objTarget.location.z