1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 "name": "Vertex Chamfer",
7 "author": "Andrew Hale (TrumanBlending)",
10 "location": "Spacebar Menu",
11 "description": "Chamfer vertex",
19 from bpy
.types
import Operator
20 from bpy
.props
import (
26 class VertexChamfer(Operator
):
27 bl_idname
= "mesh.vertex_chamfer"
28 bl_label
= "Chamfer Vertex"
29 bl_description
= "Tri chamfer selected vertices"
30 bl_options
= {'REGISTER', 'UNDO'}
32 factor
: FloatProperty(
34 description
="Size of the Champfer",
39 relative
: BoolProperty(
41 description
="If Relative, Champfer size is relative to the edge length",
44 dissolve
: BoolProperty(
46 description
="Remove/keep the original selected vertices\n"
47 "Remove creates a new triangle face between the Champfer edges,\n"
48 "similar to the Dissolve Vertices operator",
51 displace
: FloatProperty(
53 description
="Active only if Remove option is disabled\n"
54 "Displaces the original selected vertices along the normals\n"
55 "defined by the Champfer edges",
61 def poll(self
, context
):
62 return (context
.active_object
.type == 'MESH' and
63 context
.mode
== 'EDIT_MESH')
65 def draw(self
, context
):
67 layout
.prop(self
, "factor", text
="Distance" if self
.relative
else "Factor")
69 sub
.prop(self
, "relative")
70 sub
.prop(self
, "dissolve")
72 layout
.prop(self
, "displace")
74 def execute(self
, context
):
75 ob
= context
.active_object
77 bm
= bmesh
.from_edit_mesh(me
)
83 dissolve
= self
.dissolve
84 displace
= self
.displace
89 # Loop over edges to find those with both verts selected
94 elen
= e
.calc_length()
95 val
= fac
if rel
else fac
/ elen
97 # Loop over the verts of the edge to split
99 # if val == 0.5 and e.other_vert(v).tag:
101 en
, vn
= bmesh
.utils
.edge_split(e
, v
, val
)
102 en
.tag
= vn
.tag
= True
103 val
= 1.0 if val
== 1.0 else val
/ (1.0 - val
)
105 # Get all verts which are selected but not created previously
106 verts
= [v
for v
in bm
.verts
if v
.select
and not v
.tag
]
108 # Loop over all verts to split their linked edges
110 for e
in v
.link_edges
[:]:
113 elen
= e
.calc_length()
114 val
= fac
if rel
else fac
/ elen
115 bmesh
.utils
.edge_split(e
, v
, val
)
117 # Loop over all the loops of the vert
118 for l
in v
.link_loops
:
120 bmesh
.utils
.face_split(
122 l
.link_loop_next
.vert
,
123 l
.link_loop_prev
.vert
126 # Remove the vert or displace otherwise
128 bmesh
.utils
.vert_dissolve(v
)
130 v
.co
+= displace
* v
.normal
132 me
.calc_loop_triangles()
134 bpy
.ops
.object.mode_set(mode
='OBJECT')
135 bpy
.ops
.object.mode_set(mode
='EDIT')
141 bpy
.utils
.register_class(VertexChamfer
)
145 bpy
.utils
.unregister_class(VertexChamfer
)
148 if __name__
== "__main__":