Skip to content

Instantly share code, notes, and snippets.

@dommetysk
Last active December 17, 2015 09:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dommetysk/5585487 to your computer and use it in GitHub Desktop.
Save dommetysk/5585487 to your computer and use it in GitHub Desktop.
blender addon: mesh generator for diamond (brilliant cut) objects. Written as a little exercise in python which I started learning a some weeks ago.
INSTALLATION
Copy the file add_mesh_roundBrilliant.py into Blender/.blender/scripts/addons (Windows) or Blender/blender.app/Contents/MacOS/.blender/scripts/addons (OSX). Run blender, go into Blender User Preferences and select the Addons tab. Find the "Add Mesh: Brilliant" entry and activate the add-on by checking its checkbox.
USAGE
Once installed, move your mouse cursor into the 3D View and press Shift-A. Clicking Mesh > Brilliant will generate your object with the default or previous used parameters. A interface is provided in the tool bar (press T) where you can change all parameters (mesh will be updated accordingly) and also save presets. To best and most quickly understand each parameter, simply play around and see what each parameter does.
The following parameters are available:
Number of Segments default: 16
Table width default: 0.530
Crown height default: 0.162
Girdle thickness default: 0.017
Real Girdle default: True
Smooth Girdle default: False
Pavillion depth default: 0.431
Upper facet factor default: 0.250
Lower facet factor default: 0.400
Culet size default: 0.000
Retain lower angle default: False
MORE
The script is tested with blender version 2.67.
If you encounter any bugs, please contact me.
Thanks.
KNOWN ISSUES
I'm working on the following issues:
- make smooth shading option unclickable if girdle_real = False
CHANGELOG
v0.1.4:
- smooth, real girdle now correct displayed
v0.1.3:
- user option for smooth shading of girdle (if real girdle is checked)
- upper and lower girdle polygons are more planar now ( < 1 deg distortion in op presets)
- some clean-up (pep)
- changed some default values
v0.1.2:
- crash on execution in editmode or when other objects active fixed
- code clean-up according to coding conventions
v0.1.1:
- all face normals are now consistent
- smooth shading for complex girdle added
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ##### END GPL LICENSE BLOCK #####
# Copyright (C) 2013 dommetysk
bl_info = {
"name": "Brilliant",
"author": "Dominic Kröper, (dommetysk)",
"version": (0, 1, 4),
"blender": (2, 67, 0),
"location": "View3D > Add > Mesh > New Object",
"description": "Add a realistic diamond (brilliant) object",
"warning": "",
"wiki_url": "",
"tracker_url":
"http://projects.blender.org/tracker/index.php?func=detail&aid=35389",
"category": "Add Mesh"}
import bpy
from math import pi, sin, cos, tan
from bpy.types import Operator
from bpy.props import IntProperty, FloatProperty, BoolProperty
from mathutils import Vector, Euler
# mesh/object generating function, returns final object
def addBrilliant(context, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
pavi_f, culet, girdle_real, keep_lga, g_real_smooth):
# # possible user inputs ( output 100% = 2 blender units )
# s # no. of girdle facets (steps) default: 16
# table_w # table width default: 0.530
# crown_h # crown height default: 0.162
# girdle_t # girdle thickness default: 0.017
# pavi_d # pavillion depth default: 0.431
# bezel_f # bezel factor default: 0.250
# pavi_f # pavillion factor default: 0.400
# culet # culet size default: 0.000
# girdle_real # type of girdle flat/real default: True
# g_real_smooth # smooth or flat shading default: False
# keep_lga # when culet > 0, keep lga default: False
# variables / shortcuts
if s % 2: # prevent odd number of steps (messes up mesh)
s = s - 1
if not girdle_real:
g_real_smooth = False
ang = 2*pi/s # angle step size
Verts = [] # collect all vertices
Faces = [] # collect all faces
ca = cos(ang)
ca2 = cos(ang/2)
sa4 = sin(ang/4)
ta4 = tan(ang/4)
ta8 = tan(ang/8)
def fa(*vs): # shortcut Faces.append
v = []
for u in vs:
v.append(u)
Faces.append(v)
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))
# upper girdle angle
uga = (1-bezel_f) * crown_h*2 / (ca2 -
(table_w + (1-table_w) * bezel_f) * ca2/ca)
# lower girdle angle
if keep_lga:
if pavi_f > 0 and pavi_f < 1:
lga = (1-pavi_f) * pavi_d*2 / (ca2 - pavi_f*ca2 / ca)
elif pavi_f == 1:
lga = 0
else:
lga = 2*pavi_d*ca
else:
lga = (1-pavi_f) * pavi_d*2 / (ca2 -
(culet + (1-culet) * pavi_f) * ca2/ca)
# append girdle vertices
va(1, 0, ang, 0, s)
va(1, 2*girdle_t, ang, 0, s)
# append real girdle vertices
if girdle_real:
dnu = uga * (1 - ca2)
dfu = uga * (ta8 + ta4) * sa4
dnl = lga * (1 - ca2)
dfl = lga * (ta8 + ta4) * sa4
if abs(dnu) + abs(dnl) > 2*girdle_t or dnu < 0 or dnl < 0:
girdle_real = False
else:
va(1, dnl, ang, ang/2, s)
va(1, 2*girdle_t - dnu, ang, ang/2, s)
va(1, dfl, ang/2, ang/4, 2*s)
va(1, 2*girdle_t - dfu, ang/2, ang/4, 2*s)
# make girdle faces
l1 = len(Verts) # 2*s / 8*s
for i in range(l1):
if girdle_real:
if i < s:
fa(i, i + s, 2*i + 6*s, 2*i + 4*s)
if i == 0:
fa(i, s, l1 - 1, 6*s - 1)
else:
fa(i, i + s, 2*i + 6*s - 1, 2*i + 4*s - 1)
elif i > 2*s - 1 and i < 3*s:
fa(i, i + s, 2 * (i+s), 2*i)
fa(i, i + s, 2 * (i+s) + 1, 2*i + 1)
else:
if i < s - 1:
fa(i, i + s, i + s + 1, i + 1)
elif i == s - 1:
fa(i, i + s, s, 0)
# append upper girdle facet vertices
va((table_w + (1-table_w) * bezel_f) / ca, (1-bezel_f) * 2*crown_h +
2*girdle_t, 2*ang, ang, int(s/2))
# make upper girdle facet faces
l2 = len(Verts) # 2.5*s / 8.5*s
for i in range(l2):
if i > s and i < 2*s - 1 and i % 2 != 0:
if girdle_real:
fa(i, 2 * (i + 2*s), i + 2*s, 2 * (i + 2*s) + 1, i + 1,
int(7.5*s) + int((i-1) / 2))
fa(i, 2 * (i + 2*s) - 1, i + 2*s - 1, 2 * (i + 2*s - 1),
i - 1, int(7.5*s) + int((i-1) / 2))
else:
fa(i, i + 1, int((i + 3*s) / 2))
fa(i, i - 1, int((i + 3*s) / 2))
elif i == s:
if girdle_real:
fa(i, l1 - 1, 4*s - 1, l1 - 2, 2*i - 1, l2 - 1)
fa(2*i - 2, l1 - 4, 4*s - 2, l1 - 3, 2*i - 1, l2 - 1)
else:
fa(i, 2*i - 1, l2 - 1)
fa(2*i - 1, 2*i - 2, l2 - 1)
# append table vertices
va(table_w, (crown_h + girdle_t)*2, 2*ang, 0, int(s/2))
# make bezel facet faces and star facet faces
l3 = len(Verts) # 3*s / 9*s
for i in range(l3):
if i > l2 - 1 and i < l3 - 1:
fa(i, i + 1, i - int(s/2))
fa(i + 1, i - int(s/2), 2 * (i-l2) + 2 + s, i - int(s/2) + 1)
elif i == l3 - 1:
fa(i, l2, l2 - 1)
fa(s, l2 - 1, l2, l2 - int(s/2))
# make table facet face
tf = []
for i in range(l3):
if i > l2 - 1:
tf.append(i)
fa(*tf)
# append lower girdle facet vertices
if keep_lga:
va(pavi_f/ca, (pavi_f-1) * pavi_d*2, 2*ang, ang, int(s/2))
else:
va((pavi_f * (1-culet) + culet) / ca, (pavi_f-1) * pavi_d*2, 2*ang,
ang, int(s/2))
# make lower girdle facet faces
l4 = len(Verts) # 3.5*s / 9.5*s
for i in range(l4):
if i > 0 and i < s - 1 and i % 2 == 0:
if girdle_real:
fa(i, 2 * (i + 2*s), i + 2*s, 2 * (i + 2*s) + 1, i + 1,
int(i/2) + 9*s)
fa(i, 2 * (i + 2*s) - 1, i + 2*s - 1, 2 * (i + 2*s - 1),
i-1, int(i/2) + 9*s - 1)
else:
fa(i, i + 1, int(i/2) + l4 - int(s/2))
fa(i, i - 1, int(i/2) + l4 - int(s/2) - 1)
elif i == 0:
if girdle_real:
fa(0, 4*s, 2*s, 4*s + 1, 1, 9*s)
fa(0, 6*s - 1, 3*s - 1, 6*s - 2, s - 1, l4 - 1)
else:
fa(0, 1, l4 - int(s/2))
fa(0, s - 1, l4 - 1)
# append culet vertice(s)
if culet == 0:
va(0, pavi_d*(-2), 0, 0, 1)
else:
if keep_lga:
va(culet * pavi_f / ca, pavi_d*(-2) + culet * pavi_f * 2 * pavi_d,
2*ang, ang, int(s/2))
else:
va(culet/ca, pavi_d*(-2), 2*ang, ang, int(s/2))
# make pavillion facet face
l5 = len(Verts) # 4*s / 10*s //if !culet: 3.5*s+1 / 9.5*s+1
for i in range(l5):
if i > 0 and i < s - 1 and i % 2 == 0:
if culet:
fa(i, l3 + int(i/2), l3 + int((s+i) / 2),
l3 + int((s+i) / 2) - 1, l3 + int(i/2) - 1)
else:
fa(i, l3 + int(i/2), l5 - 1, l3 + int(i/2) - 1)
elif i == 0:
if culet:
fa(i, l3, l4, l5 - 1, l4 - 1)
else:
fa(i, l3, l5 - 1, l4 - 1)
# make culet facet face
if culet:
cf = []
for i in range(l5):
if i > l4 - 1:
cf.append(i)
fa(*cf)
# bpy variables / shortcuts
scene = bpy.context.scene
# deactivate possible active Objects
bpy.context.scene.objects.active = None
# create actual mesh and object based on Verts and Faces given
dmesh = bpy.data.meshes.new("dmesh")
dmesh.from_pydata(Verts, [], Faces)
dmesh.update()
dobj = bpy.data.objects.new("dobj", dmesh)
# link object into scene
scene.objects.link(dobj)
# activate and select object
scene.objects.active = dobj
dobj.select = True
obj = bpy.context.active_object
# flip all face normals outside
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
sel_mode = bpy.context.tool_settings.mesh_select_mode
bpy.context.tool_settings.mesh_select_mode = [False, False, True]
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for i, face in enumerate(obj.data.polygons):
face.select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.normals_make_consistent(inside=False)
bpy.context.tool_settings.mesh_select_mode = sel_mode
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
# make girdle smooth for complex girdle
if girdle_real and g_real_smooth:
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_all(action='DESELECT') # deselect all mesh data
bpy.ops.object.mode_set(mode='OBJECT')
pls = []
dp = obj.data.polygons[:4*s] # only consider faces of girdle
ov = obj.data.vertices
for i, p in enumerate(dp):
pls.extend(p.vertices) # list all verts of girdle
for i, e in enumerate(obj.data.edges): # select egdes to mark sharp
if e.vertices[0] in pls and e.vertices[1] in pls and abs(
ov[e.vertices[0]].co.x - ov[e.vertices[1]].co.x):
obj.data.edges[i].select = True
continue
obj.data.edges[i].select = False
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.mark_sharp()
bpy.context.tool_settings.mesh_select_mode = [False, False, True]
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.select_all(action='DESELECT')
for i, face in enumerate(obj.data.polygons):
if i < 4*s:
face.select = True
continue
face.select = False
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.faces_shade_smooth()
bpy.ops.object.modifier_add(type='EDGE_SPLIT')
bpy.context.tool_settings.mesh_select_mode = sel_mode
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="EdgeSplit")
return dobj
# add new operator for object
class MESH_OT_primitive_brilliant_add(bpy.types.Operator):
bl_idname = "mesh.primitive_brilliant_add"
bl_label = "Custom Brilliant"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
# set user options
s = IntProperty(name="Segments",
description="Longitudial segmentation",
step=1,
min=6,
max=128,
default=16,
subtype='FACTOR')
table_w = FloatProperty(name="Table width",
description="Width of table",
min=0.001,
max=1.0,
default=0.53,
subtype='PERCENTAGE')
crown_h = FloatProperty(name="Crown height",
description="Heigth of crown",
min=0.0,
max=1.0,
default=0.162,
subtype='PERCENTAGE')
girdle_t = FloatProperty(name="Girdle height",
description="Height of girdle",
min=0.0,
max=0.5,
default=0.017,
subtype='PERCENTAGE')
girdle_real = BoolProperty(name="Real girdle",
description="More beautiful girdle; has more polygons",
default=True)
g_real_smooth = BoolProperty(name="Smooth girdle",
description=
"smooth shading for girdle, only available for real girdle",
default=False)
pavi_d = FloatProperty(name="Pavilion depth",
description="Height of pavillion",
min=0.0,
max=1.0,
default=0.431,
subtype='PERCENTAGE')
bezel_f = FloatProperty(name="Upper facet factor",
description=
"Determines the form of bezel and upper girdle facets",
min=0.0,
max=1.0,
default=0.250,
subtype='PERCENTAGE')
pavi_f = FloatProperty(name="Lower facet factor",
description=
"Determines the form of pavillion and lower girdle facets",
min=0.001,
max=1.0,
default=0.400,
subtype='PERCENTAGE')
culet = FloatProperty(name="Culet size",
description="0: no culet (default)",
min=0.0,
max=0.999,
default=0.0,
subtype='PERCENTAGE')
keep_lga = BoolProperty(name="Retain lower angle",
description="If culet > 0, retains angle of pavillion facets",
default=False)
# call mesh/object generator function with user inputs
def execute(self, context):
ob = addBrilliant(context, self.s, self.table_w, self.crown_h,
self.girdle_t, self.pavi_d, self.bezel_f,
self.pavi_f, self.culet, self.girdle_real,
self.keep_lga, self.g_real_smooth)
return {'FINISHED'}
# make operator available in layout
def menu_func(self, context):
self.layout.operator("mesh.primitive_brilliant_add",
text="Brilliant",
icon='SPACE3')
# update layout on (un)registering addon
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_mesh_add.append(menu_func)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_mesh_add.remove(menu_func)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment