Skip to content

Instantly share code, notes, and snippets.

@ameliemaia
Created April 10, 2013 18:14
Show Gist options
  • Save ameliemaia/5357070 to your computer and use it in GitHub Desktop.
Save ameliemaia/5357070 to your computer and use it in GitHub Desktop.
Two Python scripts that generate a generative sculpture of Digit London's 'D' in Maya.
"""
D sculpture
"""
import pymel.core as pm
import random
from pointset import *
sets = 2
points = [ ]
for i in range( sets ):
position = dt.FloatVector( 0, 0, i * 3 )
ps = PointSet( )
ps.generate( position, 10, 90 )
#ps.createPathOutline( )
points = points + ps.getPoints()
random.shuffle( points )
meshLines = []
curves = []
length = len( points )
for i in range( length ):
if i < length - 1:
p1 = points[ i ]
p2 = points[ i + 1 ]
size = random.uniform( 0.1, 0.15 )
vector = p2 - p1
curve = pm.curve( p=[ p1, p2 ], degree = 1 )
plane = pm.polyPlane( axis = vector, width = size, height = size, subdivisionsX = 1, subdivisionsY = 1, constructionHistory = False )
plane[0].setTranslation(p1)
pm.polyExtrudeFacet( plane[0].f, inputCurve = curve, divisions = 5, smoothingAngle = 30 )
meshLines.append(plane)
curves.append(curve)
pm.select( meshLines )
pm.polyUnite( constructionHistory = False )
pm.xform( centerPivots = True )
pm.delete( curves )
pm.delete( constructionHistory = True )
"""
This module generates a 2D point set of the Digit 'D'
"""
import pymel.core as pm
import pymel.core.datatypes as dt
import pymel.util as util
class PointSet():
""" PointSet class """
def __init__( self ):
self.WIDTH_RATIO = 0.809510045
self.CURVE_START_RATIO = 0.406360424
"""
Generate and return the pointset
Keyword arguments:
position (list) -- the position to create the pointset from
height (float) -- the height of the pointset
density (int) -- the amount of points to add to the default set, the density should be divisble by 5
"""
def generate(self, position, height, density):
self.position = dt.FloatVector(position)
self.width = height
self.width *= self.WIDTH_RATIO
self.height = height
self.density = density
self.defaultPoints = []
self.points = []
w = self.width
h = self.height
x = self.position.x
y = self.position.y
z = self.position.z
cx = x + w / 2
cy = y + h / 2
cz = z
self.center = dt.FloatVector( cx, cy, cz )
curveStart = self.width
curveStart *= self.CURVE_START_RATIO
# Default point set
p1 = dt.FloatVector( x, y, z )
p2 = dt.FloatVector( x, y + height, z )
p3 = dt.FloatVector( x + curveStart, y + h, z )
p4 = dt.FloatVector( x + w, y + h / 2, z )
p5 = dt.FloatVector( x + curveStart, y, z )
self.defaultPoints = [ p1, p2, p3, p4, p5 ]
self.points = self.defaultPoints
if self.density < 1:
return self.defaultPoints
return self.setDensity( self.density )
"""
Increase or decrease the density of the pointset
Arguments:
amount (int) -- the new amount
"""
def setDensity ( self, amount ):
# Make divisible by 5, take away default number of points
density = amount / 5
density = round( density )
density *= 5
density -= 5
self.density = int( density )
self.points = self.defaultPoints
# New point set
newPoints = [ ]
# Points per edge
pointsPerEdge = self.density / len( self.points )
# First set of points
p1 = self.points[ 0 ]
p2 = self.points[ 1 ]
vector = p2 - p1;
newPoints.append( p1 )
for i in range( 1, pointsPerEdge ):
# Create points along vector
p = p1 + ( vector / pointsPerEdge ) * i
newPoints.append(p)
# Second set of points
p1 = self.points[ 1 ]
p2 = self.points[ 2 ]
vector = p2 - p1
_pointsPerEdge = pointsPerEdge / 2
newPoints.append( p1 )
for i in range( 0, _pointsPerEdge ):
# Create points along vector
p = p1 + ( vector / _pointsPerEdge ) * i
newPoints.append( p )
# Third and forth set of points
p1 = self.points[ 2 ]
p2 = self.points[ 3 ]
_pointsPerEdge = pointsPerEdge * 2
newPoints.append( p1 )
opposite = p2.x - p1.x
adjacent = p1.y - p2.y
tan = opposite / adjacent
radius = opposite
# Loop through the points on the curve
for i in range( 0, _pointsPerEdge ):
if i == ( _pointsPerEdge / 2 ):
newPoints.append( p2 )
continue
cpx = p1.x - util.arrays.cos( util.radians(270 - (i * (180 / _pointsPerEdge))) ) * radius
cpy = p2.y - util.arrays.sin( util.radians(270 - (i * (180 / _pointsPerEdge))) ) * ( radius / tan )
cpz = p1.z
cp = dt.FloatVector( cpx, cpy, cpz )
newPoints.append( cp )
# Fifth set of points
p1 = self.points[4]
p2 = self.points[0]
vector = p2 - p1
# don't need the last point as there's already one there
_pointsPerEdge = ( pointsPerEdge / 2 ) - 1
newPoints.append( p1 )
for i in range( 0, _pointsPerEdge ):
# Create points along vector
p = p1 + ( vector / _pointsPerEdge ) * i
newPoints.append( p )
self.points = newPoints
return self.points
""" Create a CV curve around the outline of the pointset. """
def createPathOutline( self ):
curve = pm.curve( p = [ self.points[0], self.points[1] ], degree = 1 )
length = len( self.points )
for i in range( 2, length ):
p = self.points[ i ]
pm.curve( curve, p = [ p ], append = True )
return curve
def createSphereOutline( self ):
length = len( self.points )
for i in range( 0, length ):
p = self.points[ i ]
nurbsSphere = pm.sphere( radius = 0.2 )
nurbsSphere[0].setTranslation( p )
""" Return the position of the pointset (pymel.core.datatypes.FloatVector) """
def position(self):
return self.position
""" Return the points of the pointset () """
def getPoints(self):
return self.points
""" Return the width of the pointset (float) """
def width(self):
return self.width
""" Return the height of the pointset (float) """
def height(self):
return self.height
""" Return the center of the pointset (pymel.core.datatypes.FloatVector) """
def center(self):
return self.center
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment