“Explore the interactive ‘JD Ball Bounce’ project, where Maya’s Python API and OpenAI’s ChatGPT join forces to create a user-friendly bouncing ball animation script, highlighting the power of AI in the 3D animation world.”
In this unique project, I leveraged the powerful combination of Autodesk Maya’s Python API and OpenAI’s language model, ChatGPT, to create a Python script that generates a bouncing ball animation within Maya.
The goal was simple: translate a high-level concept – the “JD Ball Bounce” – into a functional animation script. The journey to the finish line, however, was filled with iterative steps and constructive dialogue with ChatGPT.
I started by providing a broad description of the requirements. The script needed to be able to create a standard spherical geometry (the ball) within Maya, and initiate an animation mimicking the trajectory of a bouncing ball. Key to this was ensuring the animation followed the parabolic arc characteristic of a bouncing object under the influence of gravity.
Additionally, I wanted user interactivity with the script. I envisioned a GUI that allowed users to input parameters: the initial height, the forward travel length, and the “weight” of the ball. The weight was categorized into five options: Anvil, Heavy, Medium, Light, Feather, which influenced the bounce factor of the ball, or in other words, the height it would reach after each bounce.
I aimed for a two-step animation process: the ball hitting the ground and the ball bouncing back up. Setting keyframes for both the Y (height) and Z (length) translation attributes was vital, and adjusting their values based on the input parameters and weight category was the next logical step.
However, achieving the right bounce wasn’t a straightforward task. The height of the ball’s bounce needed to follow an exponential decay, decreasing by a certain factor after each bounce. On the other hand, the Z movement had to decrease in a more linear fashion, emulating the deceleration of a real bouncing ball.
As I worked with ChatGPT to iterate on the script, I realized the importance of addressing all the minute details. I corrected the initial parabolic arc, added robust error handling, refined the distribution of keyframes to make the animation smoother, and adjusted the tangent types of the keyframes to recreate the effects of gravity and air resistance more precisely.
The result was a sophisticated script that not only generated a realistic bouncing ball animation but also provided a GUI for user-friendly interaction. This project truly highlighted the potential of artificial intelligence, specifically ChatGPT, as a creative and problem-solving partner, enabling me to refine and enhance my script through an interactive and dynamic process.
import maya.cmds as cmds
def create_bounce(height, length, weight):
try:
# Check if input values are valid
if not (isinstance(height, int) or isinstance(height, float)) or height <= 0:
raise ValueError('Ball height must be a positive number.')
if not (isinstance(length, int) or isinstance(length, float)) or length <= 0:
raise ValueError('Ball length must be a positive number.')
# Create a ball
ball = cmds.polySphere(r=1)[0]
# Set initial position
cmds.move(0, height, 0, ball)
# Weight to bounce factor mapping
weight_map = {"Anvil": 0.1, "Heavy": 0.3, "Medium": 0.5, "Light": 0.7, "Feather": 0.9}
if weight not in weight_map:
raise ValueError('Weight must be one of the following: Anvil, Heavy, Medium, Light, Feather.')
bounce = weight_map[weight]
# Keyframe initial position and set bounce
cmds.setKeyframe(ball, attribute='translateY', t=0, v=height)
cmds.setKeyframe(ball, attribute='translateZ', t=0, v=0)
# Simulate the bounce
t = 0
bounces = 0
total_length = length
z_speed = total_length / 5 # initial Z speed
dt = 10 # initial time difference
while height > 0.01:
# Ball hits the ground
t += dt
bounces += 1
length -= z_speed
cmds.setKeyframe(ball, attribute='translateY', t=t, v=0)
cmds.setKeyframe(ball, attribute='translateZ', t=t, v=length)
cmds.keyTangent(ball, e=True, a=True, time=(t,), inTangentType='linear', outTangentType='linear', attribute='translateY')
# Ball bounces up
t += dt
height *= bounce # Decrease height according to bounce
if height > 0.01:
length -= z_speed # Continue moving in Z direction, if not the last bounce
cmds.setKeyframe(ball, attribute='translateY', t=t, v=height)
cmds.setKeyframe(ball, attribute='translateZ', t=t, v=length)
# Make the Y movement have a parabolic tangent to simulate gravity
cmds.keyTangent(ball, e=True, a=True, time=(t,), inTangentType='fast', outTangentType='fast', attribute='translateY')
# Update Z speed and time difference with exponential decay, adjust final bounce
z_speed *= 0.8
dt *= 0.8
if height <= 0.01: # If this was the last bounce
z_speed = total_length - length # Adjust Z speed so it reaches 0 at the end
except Exception as e:
cmds.warning('Failed to create bounce: {0}'.format(e))
def ball_bounce_gui():
# If the window exists, delete it
if cmds.window("ballBounceWindow", exists=True):
cmds.deleteUI("ballBounceWindow", window=True)
# Create the window
ball_bounce_window = cmds.window("ballBounceWindow", title="JD Ball Bounce", widthHeight=(200, 120) )
# Create the layout
cmds.columnLayout( adjustableColumn=True )
# Add controls
height_control = cmds.intSliderGrp(label='Ball Height', min=1, max=100, field=True)
length_control = cmds.intSliderGrp(label='Ball Length', min=1, max=100, field=True)
weight_control = cmds.optionMenu(label='Weight')
weights = ["Anvil", "Heavy", "Medium", "Light", "Feather"]
for weight in weights:
cmds.menuItem(label=weight)
# Add button
cmds.button(label='Create Bounce', command=lambda *args: create_bounce(cmds.intSliderGrp(height_control, query=True, value=True),
cmds.intSliderGrp(length_control, query=True, value=True),
cmds.optionMenu(weight_control, query=True, value=True)))
# Show the window
cmds.showWindow(ball_bounce_window)
# Run the GUI
ball_bounce_gui()