|
|
|
For each image to send to Sylvia, I started by cropping a section that I meant to cover. For example, when I wanted to create the back wall, I cropped out the back wall portion of the painting. Much of the back wall is shown in the painting, but a large amount of it is covered by the bed. Also, the top few inches of the wall isn't shown. I needed these to be able to build the wall up to the point where it can attach to the ceiling. So, I increased the canvas size and both copy chunks of the wall and used the stamp tool to get a realistic looking top few inches. Additionally, I extended the window using the paintbrush. The back wall is completely unseen in the painting. So I could be as creative as I wanted with it. I toyed with various ideas -- adding a scene from another Van Gogh painting, putting in a completely random image (say, the DeLorean from Back to the Future), etc -- but I ended up settling on making it look like another wall of the room. I added a door, which was really a modified piece of the closet from the Van Gogh painting. Then, for fun, I added various paintings. I added a piece I had painted, a Don McLean album cover, since he wrote a song about Van Gogh, some of Sylvia's artwork, and other things of the sort. On a similar note, I found a photo of Powers to put on the ceiling. |
Complete accuracy (making the exact fuzzy mix of colors rather than one, solid color for example) wasn't necessary, since I knew most of the colors will be simplified and made into shapes anyway when Sylvia put them in Illustrator. The large area behind the bed was pretty much up to me to decide what to do with. Since clothes were hanging off the rack near the bed, I drew some more clothes. I used other Photoshop effects for other parts of the room. Sometimes, it was necessary to use the liquify function, to stretch certain shapes (such as the chair) that had been painted on a tilt. The sort of diagonal lines Van Gogh used to create perspective in the painting were unnecessary in this new, three-dimensional creating. Detail had to be added to some objects. Van Gogh's bed, in particular, was lacking in detail in the painting. So I looked at various photos of beds and created additional folds in the covers and shadows in the pillows. |
|
Create an Adobe Illustrator file that is 1024x1024 pixels.
|
#!/usr/bin/python
from PySZG import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys
from PIL import Image
import skybox
firstFrame = True
LOCAL_UNITS_PER_FOOT = 1.
#### Class definitions & implementations. ####
# Chair: a chair with a white frame that changes green when touched
# (i.e. when the effector tip is within 1 ft.) and can be dragged around.
class Chair(arPyInteractable):
def __init__(self):
# must call superclass init so that on…() methods get called
# when appropriate.
arPyInteractable.__init__(self)
def __del__(self):
print ‘deleting Chair.’
# This will get called on each frame in which this object is selected for
# interaction (‘touched’)
def onProcessInteraction( self, effector ):
# button 3 toggles visibility (actually solid/wireframe)
if effector.getOnButton(3):
self.setVisible( not self.getVisible() )
def draw(self):
glColor3f(1,1,1)
glPushMatrix()
glMultMatrixf( self.getMatrix().toTuple() )
glEnable(GL_TEXTURE_2D)
glDisable(GL_DEPTH_TEST)
glPushAttrib(GL_ENABLE_BIT)
# Load texture 7 (chair)
glBindTexture(GL_TEXTURE_2D, 7)
# The following are relative coordinates to the chair’s position
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0)
glVertex3f(-1.0, -2.0, 0.0)
glTexCoord2f(1.0, 0.0)
glVertex3f(1.0, -2.0, 0.0)
glTexCoord2f(1.0, 1.0)
glVertex3f(1.0, 2.0, 0.0)
glTexCoord2f(0.0, 1.0)
glVertex3f(-1.0, 2.0, 0.0)
glEnd()
glPopAttrib()
glBindTexture(GL_TEXTURE_2D, 0)
glEnable(GL_DEPTH_TEST)
glScalef( 2., 4., 1./12. )
if self.getVisible():
# set one of two colors depending on if this object has been selected for interaction
if self.getHighlight():
glColor3f( 0,1,0 )
else:
glColor3f( 1,1,1 )
glutWireCube(1)
glPopMatrix()
class Bed(arPyInteractable):
def __init__(self):
# must call superclass init so that on…() methods get called
# when appropriate.
arPyInteractable.__init__(self)
def __del__(self):
print ‘deleting Bed.’
# This will get called on each frame in which this object is selected for
# interaction (‘touched’)
def onProcessInteraction( self, effector ):
# button 3 toggles visibility (actually solid/wireframe)
if effector.getOnButton(3):
self.setVisible( not self.getVisible() )
def draw(self):
glColor3f(1,1,1)
glPushMatrix()
glMultMatrixf( self.getMatrix().toTuple() )
glEnable(GL_TEXTURE_2D)
glDisable(GL_DEPTH_TEST)
glPushAttrib(GL_ENABLE_BIT)
# Load texture 8 (bed)
glBindTexture(GL_TEXTURE_2D, 8)
# The following are relative coordinates to the bed’s position
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0)
glVertex3f(-2.0, -1.0, 0.0)
glTexCoord2f(1.0, 0.0)
glVertex3f(2.0, -1.0, 0.0)
glTexCoord2f(1.0, 1.0)
glVertex3f(2.0, 1.0, 0.0)
glTexCoord2f(0.0, 1.0)
glVertex3f(-2.0, 1.0, 0.0)
glEnd()
glPopAttrib()
glBindTexture(GL_TEXTURE_2D, 0)
glEnable(GL_DEPTH_TEST)
glScalef( 4., 2., 1./12. )
if self.getVisible():
# set one of two colors depending on if this object has been selected for interaction
if self.getHighlight():
glColor3f( 0,1,0 )
else:
glColor3f( 1,1,1 )
glutWireCube(1)
glPopMatrix()
# RodEffector: an effector that uses input matrix 1 for its position/orientatin
# and has 6 buttons starting at index 0. It is visually and functionally a 5-ft.
# rod with the hot spot at the tip (see szg/src/interaction/arEffector.h)
class RodEffector( arEffector ):
def __init__(self):
arEffector.__init__(self,1,6,0,0,0)
# set length to 5 ft.
self.setTipOffset( arVector3(0,0,-5) )
# set to interact with closest object within 1 ft. of tip
# (see PySZG.py for alternative classes for selecting objects)
self.setInteractionSelector( arDistanceInteractionSelector(1.) )
# set to grab an object (that has already been selected for interaction
# using rule specified on previous line) when button 0 or button 2
# is pressed and held. Button 0 will allow user to drag the object with orientation
# change, button 2 will allow dragging but square will maintain fixed orientation.
# The arGrabCondition specifies that a grab will occur whenever the value
# of the specified button event # is > 0.5.
self.setDrag( arGrabCondition( AR_EVENT_BUTTON, 0, 0.5 ), arWandRelativeDrag() )
self.setDrag( arGrabCondition( AR_EVENT_BUTTON, 2, 0.5 ), arWandTranslationDrag() )
def draw(self):
glPushMatrix()
glMultMatrixf( self.getCenterMatrix().toTuple() )
# Draw grey rectangular solid 2″x2″x5′
glScalef( 2./12, 2./12., 5. )
glColor3f( .5,.5,.5 )
glutSolidCube(1.)
# Superimpose slightly larger black wireframe (makes it easier to see shape)
glColor3f(0,0,0)
glutWireCube(1.03)
glPopMatrix()
##### The application framework ####
#
# The arPyMasterSlaveFramework automatically installs certain of its methods as the
# master/slave callbacks, e.g. the draw callback is onDraw(), etc.
class SkeletonFramework(arPyMasterSlaveFramework):
def __init__(self):
arPyMasterSlaveFramework.__init__(self)
# Our objects and effector
self.theChair = Chair()
self.theBed = Bed()
self.theWand = RodEffector()
# List of objects to interact with
self.interactionList = [self.theChair, self.theBed]
# Tell the framework what units we’re using.
self.setUnitConversion( LOCAL_UNITS_PER_FOOT )
# Near & far clipping planes.
nearClipDistance = .1*LOCAL_UNITS_PER_FOOT
farClipDistance = 100.*LOCAL_UNITS_PER_FOOT
self.setClipPlanes( nearClipDistance, farClipDistance )
#### Framework callbacks — see szg/src/framework/arMasterSlaveFramework.h ####
# start (formerly init) callback (called in arMasterSlaveFramework::start())
# NOTE: now called before window is created, so no OpenGL initialization here.
def onStart( self, client ):
# Necessary to call base class method for interactive prompt
# functionality to work (run this program with ‘–prompt’).
arPyMasterSlaveFramework.onStart( self, client )
# Register variables to be shared between master & slaves
self.initSequenceTransfer(‘transferChair’)
self.initSequenceTransfer(‘transferBed’)
#Setup navigation, so we can drive around with the joystick
#
# Tilting the joystick by more than 20% along axis 1 (the vertical on ours) will cause
# translation along Z (forwards/backwards). This is actually the default behavior, so this
# line isn’t necessary.
self.setNavTransCondition( ‘z’, AR_EVENT_AXIS, 1, 0.2 )
# Tilting joystick left or right (axis 0) will rotate left/right around vertical axis (default is left/right
# translation)
self.setNavRotCondition( ‘y’, AR_EVENT_AXIS, 0, 0.2 )
# Set translation & rotation speeds to 5 ft/sec & 30 deg/sec (defaults)
self.setNavTransSpeed( 5. )
self.setNavRotSpeed( 30. )
# set square’s initial position
self.theChair.setMatrix( ar_translationMatrix(0,2,-5) )
self.theBed.setMatrix( ar_translationMatrix(1,7,-3) )
return True
# Callback for doing window OpenGL initialization. Called from framework.start().
def onWindowStartGL( self, winInfo ):
# Clear the cube
glClearColor(0,0,0,0)
# Load the skybox (textures 1-6)
skybox.loadskybox()
# Load the chair image
chairimg = Image.open(“./images/chair.jpg”).resize((256,512))
chairtex = chairimg.tostring()
# Load the bed image
bedimg = Image.open(“./images/bed.jpg”).resize((512,256))
bedtex = bedimg.tostring()
# Bind the chair to texture 7
glGenTextures(1)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glBindTexture(GL_TEXTURE_2D, 7)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, chairtex)
# Bind the bed to texture 8
glGenTextures(1)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glBindTexture(GL_TEXTURE_2D, 8)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, bedtex)
# Callback called before data is transferred from master to slaves. Now
# called _only on the master_. This is where anything having to do with
# processing user input or random variables should happen. Normally, most
# of the frame-by-frame work of the program should be done here.
def onPreExchange( self ):
# Necessary to call base class method for interactive prompt
# functionality to work (run this program with ‘–prompt’).
arPyMasterSlaveFramework.onPreExchange(self)
# handle joystick-based navigation (drive around). The resulting
# navigation matrix is automagically transferred to the slaves.
self.navUpdate()
# update the input state (placement matrix & button states) of our effector.
self.theWand.updateState( self.getInputState() )
# Handle any interaction with the squares (see interaction docs).
# Any grabbing/dragging/deletion of squares happens in here.
ar_processInteractionList( self.theWand, self.interactionList )
# Pack data we have to transfer to slaves into appropriate variables
# What we end up with here is a tuple containing two Ints and a nested tuple
# containing 16 Floats. At this end (i.e. in the master), any sequence type
# is allowed (e.g. lists, numarray arrays, array module arrays, I don’t know what
# all else), but the elements of any sequence must be Ints, Floats, or Strings (or
# a nested sequence). They don’t all have to have the same type within a sequence,
# but only those types are allowed.
transferTupleChair = (self.theChair.getHighlight(), self.theChair.getVisible(), \
self.theChair.getMatrix().toTuple())
transferTupleBed = (self.theBed.getHighlight(), self.theBed.getVisible(), \
self.theBed.getMatrix().toTuple())
self.setSequence( ‘transferChair’, transferTupleChair )
self.setSequence( ‘transferBed’, transferTupleBed )
# Callback called after transfer of data from master to slaves. Mostly used to
# synchronize slaves with master based on transferred data. Note that you normally
# Shouldn’t be doing a whole lot of computation here; the exception would be if
# you have a complex state that can be computed from a relatively small number of
# parameters, you might compute those parameters on the master, transfer them to
# the slaves, & do the complex state computation in master and slaves here.
def onPostExchange( self ):
# Do stuff after slaves got data and are again in sync with the master.
if not self.getMaster():
# Update effector’s input state. On the slaves we only need the matrix
# to be updated, for rendering purposes.
self.theWand.updateState( self.getInputState() )
# Unpack our transfer sequence. Note that no matter what sequence types
# you used at the input end in the master, they all come out as tuples here.
# For example, if in the master you passed in a sequence that was a 3-element
# numarray array of Floats, when you unpacked it here you’d have a 3-element
# tuple of Floats.
transferTupleChair = self.getSequence( ‘transferChair’ )
self.theChair.setHighlight( transferTupleChair[0] )
self.theChair.setVisible( transferTupleChair[1] )
self.theChair.setMatrix( arMatrix4( transferTupleChair[2] ) )
transferTupleBed = self.getSequence( ‘transferBed’ )
self.theBed.setHighlight( transferTupleBed[0] )
self.theBed.setVisible( transferTupleBed[1] )
self.theBed.setMatrix( arMatrix4( transferTupleBed[2] ) )
# Draw callback
def onDraw( self, win, viewport ):
skybox.drawskybox()
global firstFrame
if firstFrame:
screen = viewport.getScreen()
print ‘Screen (camera) parameters:’
print ‘ center:’,screen.getCenter()
print ‘ normal:’,screen.getNormal()
print ‘ up:’,screen.getUp()
print ‘ size:’,screen.getWidth(), ‘x’, screen.getHeight()
firstFrame = False
# Load the [inverse of the] navigation matrix onto the OpenGL modelview matrix stack.
self.loadNavMatrix()
# Draw stuff
self.theChair.draw()
self.theBed.draw()
self.theWand.draw()
if __name__ == ‘__main__’:
framework = SkeletonFramework()
if not framework.init(sys.argv):
raise PySZGException,’Unable to init framework.’
print ‘Framework inited.’
# Never returns unless something goes wrong
if not framework.start():
raise PySZGExcreption,’Unable to start framework.’