Make a variety of sword, knives, hammer/axes, polearms, and much more with only a few lines code.
The code is split into 3 libraries:
Mesh.py: Tools for processing triangle meshes. The triangle mesh is a list of triangles composed of 3 vertices, each with a corresponding colour (RGB from 0 to 1).
Currently the library only interprets the triangle meshes into a vpython render.
Shortly I will add .obj export here as well, but I’m neglecting to do so until I write a nice way to compress the recurring vertices into a single element while preserving the per vertex colouring as a wavefront texture.
Handle.py: is a general extruder and can be used for more than handles. It’s simlar to the vpython extrusion function but returns a triangle mesh with per vertex colouring instead of a vpython render.
and,
Blade.py: The blade sculptor. Requiring a height, width, and thickness function converting the x,y position into a thickness.
The thickness function is used for crafting the blade edges as well the rate the blade thickens at the base/centre.
The blade requires both a left and right shape, for sculpting the curves on each side of the blade.
Contains both a version for vpython and one returning a triangle mesh.
Mesh.py
from vpython import vertex,vector,triangle
import vpython
def draw_mesh(mesh):
for i in mesh:
triangle(v0=vertex(pos=vector(*i[0][0]),color=vector(*i[0][1]))
,v1=vertex(pos=vector(*i[1][0]),color=vector(*i[1][1])),
v2=vertex(pos=vector(*i[2][0]),color=vector(*i[2][1])))
Handle.py
from meshes import draw_mesh
from vpython import vertex,vector,triangle,textures,bumpmaps,faces
import vpython
from math import cos,sin,pi,atan2
from random import random
from blade import blade_mesh
def path_roll(path,roll):
while len(roll)<len(path):
roll.append(0)
return list(map(lambda a,b:(a[0],a[1],b),path,roll))
def plane(origin,xaxis,yaxis,roll=0,scale=1):
def outfunc(x,y):
rollx=cos(roll)*x+cos(roll+pi/2)*y
rolly=sin(roll)*x+sin(roll+pi/2)*y
xmove=[i*rollx*scale for i in xaxis]
ymove=[i*rolly*scale for i in yaxis]
return tuple(map(lambda a,b,c:a+b+c,origin,xmove,ymove))
#return origin[0]+xmove[0]+ymove[0],origin[1]+xmove[1]+ymove[1],origin[2]+xmove[2]+ymove[2]
return outfunc
testplane=plane((2,2,2),(1,0,0),(0,1,0),pi/2)
def midangle(a,b):
return (a+b)/2
def path_roll_to_planes(pathroll,closed=False,startangle=None,endangle=None,offset=(0,0,0)):
angles=[]
planes=[]
if closed:
pathroll.append(pathroll[-1])
for i in range(len(pathroll)-1):
p1=pathroll[i]
p2=pathroll[i+1]
angles.append(atan2(p2[1]-p1[1],p2[0]-p1[0])+pi/2)
if closed:
pass
else:
if startangle==None:
start=angles[0]
else:
start=startangle
if endangle==None:
end=angles[-1]
else:
end=endangle
mid=[]
for i in range(len(angles)-1):
mid.append(midangle(angles[i],angles[i+1]))
angles=[start]+mid+[end]
for i in range(len(angles)):
#make plane
#Path on X & Z, shape on XZ hypotenuse and Y
#origin=(offset[0]+pathroll[i][0],offset[1],offset[2]+pathroll[i][2])
#xaxis=(cos(angles[i]),0,sin(angles[i]))
#yaxis=(0,1,0)
#Path on Y&Z, shape on YZ hypotenuse and X
origin=(offset[0],pathroll[i][0]+offset[1],pathroll[i][1]+offset[2])
xaxis=(0,cos(angles[i]),sin(angles[i]))
yaxis=(1,0,0)
planes.append(plane(origin,xaxis,yaxis,pathroll[i][2]))
return planes
def randcol(basecol,variation=.5):
v=(random()-.5)*variation
return (basecol[0]+v,basecol[1]+v,basecol[2]+v)
def extrusion2d(shape2d,path,closed=False,col=(.5,.5,.5),origin=(0,0,0)):
triangle_mesh=[]
planes=path_roll_to_planes(path,closed,offset=origin)
points=[[i(*j) for j in shape2d] for i in planes]
for i in range(len(points)-1):
for j in range(len(shape2d)-1):
v0=(points[i+1][j],randcol(col,.2))
v1=(points[i+1][j+1],randcol(col,.2))
v2=(points[i][j+1],randcol(col,.2))
v3=(points[i][j],randcol(col,.2))
triangle_mesh.append((v0,v1,v2))
triangle_mesh.append((v0,v2,v3))
bottomcenter=(planes[0](0,0),randcol(col,.2))
topcenter=(planes[-1](0,0),randcol(col,.2))
for j in range(len(shape2d)-1):
#v0=(points[0][j],randcol(col,.2))
#v1=(points[0][j+1],randcol(col,.2))
#triangle_mesh.append((v0,v1,v2))
v0=(points[0][j],randcol(col,.2))
v1=(points[0][j+1],randcol(col,.2))
triangle_mesh.append((v0,v1,bottomcenter))
v0=(points[-1][j],randcol(col,.2))
v1=(points[-1][j+1],randcol(col,.2))
triangle_mesh.append((v0,v1,topcenter))
return triangle_mesh
Blade.py
from meshes import draw_mesh
from vpython import vertex,vector,triangle,textures,bumpmaps
import vpython
from math import cos,sin,pi
from random import random
def blade(height,width,thicknessfunction=lambda xr,yr:((.5-xr*.5)**(.3+xr*.75))/8,basepos=(0,0,0),axis=(0,1,0),leftfunction=lambda x:0,rightfunction=lambda x:0):
triangles=[]
vsteps=64
vstep=1/vsteps*height
hsteps=36
bottomrowheight=basepos[1]
front=[]
back=[]
for i in range(vsteps+1):
relativeheight=i/vsteps
frontrow=[]
backrow=[]
left=(width*leftfunction(relativeheight))
rowwidth=max(0,width-(width*rightfunction(relativeheight))-left)
if rowwidth>0:
for j in range(hsteps+1):
relativewidth=j/hsteps
x=left+basepos[0]+j/hsteps*rowwidth
y=basepos[1]+i/vsteps*height
z=thicknessfunction(relativewidth,relativeheight)
rcol=random()*.3+.4
point=vertex(pos=vector(z,y, x),color=vector(rcol,rcol,rcol))
frontrow.append(point)
rcol=random()*.3+.4
point=vertex(pos=vector(-z,y,x),color=vector(rcol,rcol,rcol))
backrow.append(point)
front.append(frontrow)
back.append(backrow)
#front and back faces
for i in range(vsteps):
for j in range(hsteps):
triangles.append(triangle(v0=front[i][j+1],v1=front[i+1][j+1],v2=front[i+1][j]))
triangles.append(triangle(v0=front[i][j+1],v1=front[i+1][j],v2=front[i][j]))
triangles.append(triangle(v0=back[i+1][j],v1=back[i+1][j+1],v2=back[i][j+1]))
triangles.append(triangle(v0=back[i][j],v1=back[i+1][j],v2=back[i][j+1]))
#seal ends
for i in range(vsteps):
triangles.append(triangle(v0=front[i][0],v1=back[i][0],v2=back[i+1][0]))
triangles.append(triangle(v0=front[i][0],v1=back[i+1][0],v2=front[i+1][0]))
triangles.append(triangle(v0=front[i][-1],v1=back[i][-1],v2=back[i+1][-1]))
triangles.append(triangle(v0=front[i][-1],v1=back[i+1][-1],v2=front[i+1][-1]))
return front+back
def blade_mesh(height,width,thicknessfunction=lambda xr,yr:((.5-xr*.5)**(.3+xr*.75))/8,basepos=(0,0,0),axis=(0,1,0),leftfunction=lambda x:sin(x*3.14)*.1,rightfunction=lambda x:-sin(x*3.14)*.1,resolution=(32,32),roll=0):
triangles=[]
vsteps=resolution[1]
vstep=1/vsteps*height
hsteps=resolution[0]
bottomrowheight=basepos[1]
front=[]
back=[]
for i in range(vsteps+1):
relativeheight=i/vsteps
frontrow=[]
backrow=[]
left=(width*leftfunction(relativeheight))
rowwidth=max(0,width-(width*rightfunction(relativeheight))-left)
if rowwidth>0:
for j in range(hsteps+1):
relativewidth=j/hsteps
x=left+basepos[0]+j/hsteps*rowwidth
y=basepos[1]+i/vsteps*height
z=thicknessfunction(relativewidth,relativeheight)
rcol=random()*.3+.4
point=((z,y,x),(rcol,rcol,rcol))
frontrow.append(point)
rcol=random()*.3+.4
point=((-z,y,x),(rcol,rcol,rcol))
backrow.append(point)
front.append(frontrow)
back.append(backrow)
#front and back faces
for i in range(vsteps):
for j in range(hsteps):
triangles.append((front[i][j+1],front[i+1][j+1],front[i+1][j]))
triangles.append((front[i][j+1],front[i+1][j],front[i][j]))
triangles.append((back[i+1][j],back[i+1][j+1],back[i][j+1]))
triangles.append((back[i][j],back[i+1][j],back[i][j+1]))
#seal ends
for i in range(vsteps):
triangles.append((front[i][0],back[i][0],back[i+1][0]))
triangles.append((front[i][0],back[i+1][0],front[i+1][0]))
triangles.append((front[i][-1],back[i][-1],back[i+1][-1]))
triangles.append((front[i][-1],back[i+1][-1],front[i+1][-1]))
for j in range(hsteps):
triangles.append((front[0][j],back[0][j],back[0][j+1]))
triangles.append((front[0][j],back[0][j+1],front[0][j+1]))
triangles.append((front[-1][j],back[-1][j],back[-1][j+1]))
triangles.append((front[-1][j],back[-1][j+1],front[-1][j+1]))
return triangles
Demo.py
from handles import extrusion2d
from meshes import draw_mesh
from math import cos,sin,pi
from blade import blade_mesh
####2dshapes
polygon=lambda sides,r=1,center=(0,0):[(center[0]+cos(i/sides*pi*2)*r,center[1]+sin(i/sides*pi*2)*r) for i in range(sides+1)]
square=lambda n,center=(0,0):[(center[0]-n,center[1]-n),(center[0]+n,center[1]-n),(center[0]+n,center[1]+n),(center[0]-n,center[1]+n),(center[0]-n,center[1]-n)]
######weapon maker#####
###Cleaver
#handle=extrusion2d(polygon(8,.2),[(-2,0,0),(.5,0,0)],col=(.6,.5,.2),origin=(.25,0,0))
#cleaver=blade_mesh(3,1.5,thicknessfunction=lambda xr,yr:((.5-xr*.5)**(.3+xr*.75))/8,basepos=(0,0,0),axis=(0,1,0),leftfunction=lambda x:sin(x*3.14)*.1,rightfunction=lambda x:-sin(x*3.14)*.1)
#draw_mesh(handle)
#draw_mesh(cleaver)
###Spear
#handle=extrusion2d(polygon(8,.2),[(-4,0,0),(1,0,0)],col=(.6,.5,.2),origin=(.25,0,0))
#speartip=blade_mesh(3,.8,thicknessfunction=lambda xr,yr:(1-yr)*(.5-abs(.5-xr))*.5,basepos=(-.2,1,-.25),axis=(0,1,0),leftfunction=lambda x:x*.49,rightfunction=lambda x:x*.5)
#draw_mesh(handle)
#draw_mesh(speartip)
###Dagger 1
#handle=extrusion2d(polygon(8,.2),[(-1.4,0,0),(-.4,0,0)],col=(.6,.5,.2),origin=(.25,0,0))
#daggertip=blade_mesh(2,.8,thicknessfunction=lambda xr,yr:(1-yr)*(.5-abs(.5-xr))*.5,basepos=(-.2,-.4,-.25),axis=(0,1,0),leftfunction=lambda x:x*.49,rightfunction=lambda x:x*.5)
#draw_mesh(handle)
#draw_mesh(daggertip)
###sabre
#handletop=extrusion2d(polygon(8,.4),[(-.5,0,0),(-.1,0,0)],col=(.6,.5,.2),origin=(.25,0,0))
#handle=extrusion2d(polygon(8,.2),[(-1.4,0,0),(-1,0,0),(-.7,0,0),(-.4,0,0)],col=(.6,.5,.2),origin=(.25,0,0))
#blade=blade_mesh(3,.5,thicknessfunction=lambda xr,yr:max((1-yr)*.9+.1,1-xr)*.05*(1.5-yr),basepos=(0,-.4,0),axis=(0,1,0),leftfunction=lambda x:sin(x*pi*1.2-pi/4)*.35+.4,rightfunction=lambda x:(-1.6+x*2 if x >.8 else 0)+1.1*abs(x-.7)**2-sin(x*pi*1.2-pi/4)*.25-.4)
#draw_mesh(blade)
#draw_mesh(handle)
#draw_mesh(handletop)
###broad sword
#handletop=extrusion2d([(-.2,-.6),(-.2,.6),(.2,.6),(.2,-.6),(-.2,-.6)],[(-.5,0,0),(-.2,0,0)],col=(.6,.5,.2),origin=(.5,0,0))
#handle=extrusion2d(polygon(8,.2),[(-2.5,0,0),(-1.7,0,0),(-1.0,0,0),(-.5,0,0)],col=(.6,.5,.2),origin=(.5,0,0))
#pomel=extrusion2d(polygon(8,.3),[(-2.7,0,0),(-2.5,0,0)],col=(.6,.5,.2),origin=(.5,0,0))
#blade=blade_mesh(6,1,thicknessfunction=lambda xr,yr:max((1-yr)*.9+.1,abs(.5-xr))*.05*(1.5-yr),basepos=(0,-.4,0),axis=(0,1,0),leftfunction=lambda x:.45*x**3,rightfunction=lambda x:.45*x**3)
#draw_mesh(blade)
#draw_mesh(pomel)
#draw_mesh(handle)
#draw_mesh(handletop)
#dagger2
#handletop=extrusion2d([(-.15,-.4),(-.15,.4),(.15,.4),(.15,-.4),(-.15,-.4)],[(-.5,0,0),(-.2,0,0)],col=(.6,.5,.2),origin=(.2,0,0))
#handle=extrusion2d(polygon(8,.125),[(-1.2,0,0),(-1.0,0,0),(-.5,0,0)],col=(.6,.5,.2),origin=(.2,0,0))
#pomel=extrusion2d(polygon(8,.2),[(-1.5,0,0),(-1.2,0,0)],col=(.6,.5,.2),origin=(.2,0,0))
#blade=blade_mesh(3,.35,thicknessfunction=lambda xr,yr:max((1-yr)*.9+.1,abs(.5-xr))*.05*(1.5-yr),basepos=(0,-.4,0),axis=(0,1,0),leftfunction=lambda x:.45*x**3,rightfunction=lambda x:.45*x**3)
#draw_mesh(blade)
#draw_mesh(pomel)
#draw_mesh(handle)
#draw_mesh(handletop)
#dagger3
handletop=extrusion2d([(-.15,-.4),(-.15,.4),(.15,.4),(.15,-.4),(-.15,-.4)],[(-1.5,0,0),(-1.4,0,0)],col=(.6,.5,.2),origin=(.3,0,0))
handle=extrusion2d(polygon(8,.125),[(-2.2,0,0),(-2.0,0,0),(-1.5,0,0)],col=(.6,.5,.2),origin=(.3,0,0))
pomel=extrusion2d(polygon(8,.2),[(-2.5,0,0),(-2.2,0,0)],col=(.6,.5,.2),origin=(.3,0,0))
blade=blade_mesh(6,.6,thicknessfunction=lambda xr,yr:max((1-yr)*.9+.1,.5-abs(.5-xr))*.05*(1.5-yr),basepos=(0,-1.4,0),axis=(0,1,0),leftfunction=lambda x:.45*x**3,rightfunction=lambda x:.45*x**3)
draw_mesh(blade)
draw_mesh(pomel)
draw_mesh(handle)
draw_mesh(handletop)
#Saw
#sawblade=blade_mesh(16,3,thicknessfunction=lambda xr,yr:.05-xr*.05,basepos=(0,-8,0),axis=(0,1,0),leftfunction=lambda x:sin(x*3.14)*.2-abs(.3-x)*.4,rightfunction=lambda x:-sin(x*3.14)*.2+abs(sin(x*120))*.07,resolution=(10,256))
#handle1=extrusion2d(polygon(8,.4),[(0,-4,0),(0,-1.0,0),(0,2,0)],col=(.3,.2,.1),origin=(0,-7.5,0))
#handle2=extrusion2d(polygon(8,.4),[(0,-4,0),(0,-1.0,0),(0,2,0)],col=(.3,.2,.1),origin=(0,7.5,0))
#draw_mesh(handle1)
#draw_mesh(handle2)
#draw_mesh(sawblade)
#Tonfa
#handle1=extrusion2d(polygon(4,.4),[(0,-3,0),(0,-1.5,0),(0,0,0)],col=(.3,.2,.1),origin=(0,0,0))
#handle2=extrusion2d(polygon(8,.4),[(-3,0,0),(0,0,0),(7,0,0)],col=(.3,.2,.1),origin=(0,0,0))
#draw_mesh(handle1)
#draw_mesh(handle2)
##Polearm
blade=blade_mesh(4,1,thicknessfunction=lambda xr,yr:.05-xr*.05,basepos=(0,4,0),axis=(0,1,0),leftfunction=lambda x:0,rightfunction=lambda x:-sin((x+1)*3.14*.49)*1.4,resolution=(10,40))
handle1=extrusion2d(polygon(4,.2),[(0,0,0),(0,1.0,0),(0,3.0,0)],col=(.4,.1,.1),origin=(0,4,0))
handle2=extrusion2d(polygon(64,.3),[(-3,0,0),(0,0,0),(8,0,0)],col=(.4,.1,.1),origin=(0,0,0))
handle3=extrusion2d(polygon(64,.5),[(7.5,0,0),(8,0,0)],col=(.4,.1,.1),origin=(0,0,0))
draw_mesh(handle1)
draw_mesh(handle2)
draw_mesh(handle3)
draw_mesh(blade)
0