Scripting for Animation and VFX: Week 4
Scripting for Animation and VFX: Week 4
Functions and Creating Spheres
For this weeks assignment we were working with functions using python in maya. The given code to work with and expand created randomly placed spheres and curves that connected them.
Breaking down the given code:
import random
import maya.cmds as cmds
def create_random_sphere():
# Generate random position
x = random.uniform(-100, 100)
y = random.uniform(-100, 100)
z = random.uniform(-100, 100)
# Create sphere
sphere = cmds.polySphere() [0]
# Move sphere to random position
cmds.move(x, y, z, sphere)
return sphere
def create_pipe(start, end):
# Create a pipe between two objects
curve = cmds.curve(degree=1, point=[cmds.xform(start, query=True, translation=True), cmds.xform(end, query=True, translation=True)])
return curve
def create_shaders():
black_shader = cmds.shadingNode('lambert', asShader=True, name="black")
cmds.setAttr(black_shader + '.color', 0, 0, 0, type='double3')
white_shader = cmds.shadingNode('lambert', asShader=True, name="white")
cmds.setAttr(white_shader + '.color', 1, 1, 1, type='double3')
return black_shader, white_shader
def create_spheres_and_pipes(num_spheres):
# Create spheres
spheres = []
black_shader, white_shader = create_shaders()
for i in range(num_spheres):
sphere = create_random_sphere()
spheres.append(sphere)
if i % 2 == 0:
cmds.select(sphere)
cmds.hyperShade(assign=black_shader)
else:
cmds.select(sphere)
cmds.hyperShade(assign=white_shader)
# Connect spheres with pipes
pipes = []
for i in range(len(spheres) - 1):
pipe = create_pipe(spheres[i], spheres[i + 1])
pipes.append(pipe)
# Connect last sphere with the first one
pipe = create_pipe(spheres[-1], spheres[0])
pipes.append(pipe)
return spheres, pipes
def createrandspheres(num_spheres):
# Create spheres and pipes
spheres, pipes = create_spheres_and_pipes(num_spheres)
# Create a circle curve
circle = cmds.circle(normal=(0, 1, 0), radius=0.2)
# Extrude the circle along the path curves
for pipe in pipes:
cmds.select(circle[0], pipe)
cmds.extrude(et=2, upn=True, fpt=True, ucp=1)
The first two lines of code import the libraries that will be need in this function.
import random and import cmds.maya as cmds
The next part of the code creates the first function, create_random_sphere.
This function is what creates the random spheres in the scene.
The first three lines generate a random position for the y x and z coordinates using the random.uniform function in the random library.
The next line creates the sphere, and the following line moves the sphere to the randomly generated coordinates.
The function returns the sphere.
The next function is create_pipe(start, end).
This function creates the pipes that connect the spheres.
curve = cmds.curve(degree=1, point=[cmds.xform(start, query=True,
translation=True), cmds.xform(end, query=True, translation=True)])
return curve
curve is a list that holds the information of the curve created. cmds.curve creates a curve. This maya function has parameters. We are creating a two point curve, this will make a straight line.
The next function creates the shaders. create_shaders.
def create_shaders():
black_shader = cmds.shadingNode('lambert', asShader=True, name="black")
cmds.setAttr(black_shader + '.color', 0, 0, 0, type='double3')
white_shader = cmds.shadingNode('lambert', asShader=True, name="white")
cmds.setAttr(white_shader + '.color', 1, 1, 1, type='double3')
This function creates two shaders. One black one white. These shaders are lamberts
This function used the function cmds.shadingNode create a shading node in the hypershade.
The function saves the shaders information in lists. the cmds.setAttr function is used to set what color each shader will be.
The next function uses the previously made functions to make the spheres and pipes. The firs line makes a list called spheres.
def create_spheres_and_pipes(num_spheres):
# Create spheres
spheres = []
black_shader, white_shader = create_shaders()
for i in range(num_spheres):
sphere = create_random_sphere()
spheres.append(sphere)
if i % 2 == 0:
cmds.select(sphere)
cmds.hyperShade(assign=black_shader)
else:
cmds.select(sphere)
cmds.hyperShade(assign=white_shader)
# Connect spheres with pipes
pipes = []
for i in range(len(spheres) - 1):
pipe = create_pipe(spheres[i], spheres[i + 1])
pipes.append(pipe)
# Connect last sphere with the first one
pipe = create_pipe(spheres[-1], spheres[0])
pipes.append(pipe)
return spheres, pipes
The for in loop loops as many times in range of num_spheres. The loop creates a sphere using the create_random_sphere function, adds them to a list, and will assign the black sphere to every even number of sphere. This is done by having a condition and an if else branch, if the number of sphere equals 0 when divided by 2 then it is assigned the black shader.
The next part of the function connects the spheres with the pipes.
the list pipes is created, and a for in loop is used to create the pipes using the location of and sphere and the following sphere that is made, The for in range loop uses the length of the spheres[] list - 1. This means that the range is how many spheres are in the spheres list.
pipe= create_pipe(spheres[i], spheres[i + 1])
This line creates a pipe that starts at the location of the sphere that is in the i position of the list sphere and ends at the next sphere in the list.
The next function creates the spheres and pipe and also creates a circle curve that is extruded along the pipe curves.
def createrandspheres(num_spheres):
# Create spheres and pipes
spheres, pipes = create_spheres_and_pipes(num_spheres)
# Create a circle curve
circle = cmds.circle(normal=(0, 1, 0), radius=0.2)
# Extrude the circle along the path curves
for pipe in pipes:
cmds.select(circle[0], pipe)
cmds.extrude(et=2, upn=True, fpt=True, ucp=1)
Expanding the functions and code:
So to expand on these functions and and code, I want to try to make the spheres make an interesting larger shape and include more and different shaders.
Right now the random generation of the spheres makes it so they form a cube shape. The random function that is used is uniform and is given the parameters -100 and 100 for x y and z. This makes is so the spheres form a cube shape.
Because this code uses functions, one can change the code in one function instead of having to change the whole script.
The shape I want to try to make is a helix.
My fist thought was to make a large helix out of a curve that I could potentially make the spheres generate around.
I used chatgpt to figure out where to start.
I entered the code and asked the program to write and addition to the script that would make the spheres form a helix shape.
The ai suggested modifying the create_spheres-and_pipes(num_spheres) function to generate spheres in a helix arrangement.
"To make the spheres form a helix shape, you can modify the create_spheres_and_pipes(num_spheres)
function to generate the spheres in a helical arrangement. Here's how you can achieve that:
python
import math
def create_spheres_and_pipes_helix(num_spheres, helix_radius, helix_height, num_turns):
spheres = []
black_shader, white_shader = create_shaders()
for i in range(num_spheres):
angle = (i / num_spheres) * num_turns * 2 * math.pi
x = helix_radius * math.cos(angle)
z = helix_radius * math.sin(angle)
y = (i / num_spheres) * helix_height
sphere = cmds.polySphere()[0]
cmds.move(x, y, z, sphere)
spheres.append(sphere)
if i % 2 == 0:
cmds.select(sphere)
cmds.hyperShade(assign=black_shader)
else:
cmds.select(sphere)
cmds.hyperShade(assign=white_shader)
pipes = []
for i in range(len(spheres) - 1):
pipe = create_pipe(spheres[i], spheres[i + 1])
pipes.append(pipe)
pipe = create_pipe(spheres[-1], spheres[0])
pipes.append(pipe)
return spheres, pipes
In this modified version of the function, the spheres are positioned in a helical arrangement along the y-axis while rotating around the y-axis. The helix_radius
parameter controls how far the spheres are from the y-axis (radius of the helix), the helix_height
parameter controls the vertical distance between consecutive spheres, and the num_turns
parameter controls how many turns the helix makes.
To use this modified function, call it with the desired parameters:
python
num_spheres = 20
helix_radius = 10.0
helix_height = 2.0
num_turns = 4.0
spheres, pipes = create_spheres_and_pipes_helix(num_spheres, helix_radius, helix_height, num_turns)
This will create a helical arrangement of spheres connected by pipes in the Maya scene. You can adjust the parameters to achieve the desired appearance of the helix."
I added the suggested changes to the code.
The new create_spheres_and_pipes function now had more parameters that would be used to calculate the position the spheres needed to be moved to in order to make the helix. This new function required the math python library so that was imported at the top of the code.
For each sphere that is created an angle is calculated using the i integer, and the angle is used to calculate the x and z coordinates of the sphere.
I added the variables helix_radius, helix_height, and num_turns above the calling of the final function so that they can be easily accessible and modified. The variables are used to determine the radius height and amount of turns for the helix.
Next I wanted to make a gradient with the shaders. I wanted it to go from dark to light blue up the helix.
I asked ChatGPT to write another addition to the code.
The ai suggested this:
"To create shaders that form a gradient from dark blue to light blue for the helical spheres, you can modify the create_spheres_and_pipes_helix
function to interpolate the color values for each sphere along the gradient. Here's how you can achieve that:
python
def create_spheres_and_pipes_helix_gradient(num_spheres, helix_radius, helix_height, num_turns):
spheres = []
dark_blue = (0.0, 0.0, 0.3)
light_blue = (0.5, 0.5, 1.0)
for i in range(num_spheres):
angle = (i / num_spheres) * num_turns * 2 * math.pi
x = helix_radius * math.cos(angle)
z = helix_radius * math.sin(angle)
y = (i / num_spheres) * helix_height
sphere = cmds.polySphere()[0]
cmds.move(x, y, z, sphere)
spheres.append(sphere)
# Interpolate color between dark blue and light blue based on y position
t = y / helix_height
color = (
dark_blue[0] + t * (light_blue[0] - dark_blue[0]),
dark_blue[1] + t * (light_blue[1] - dark_blue[1]),
dark_blue[2] + t * (light_blue[2] - dark_blue[2])
)
shader = cmds.shadingNode('lambert', asShader=True)
shading_group = cmds.sets(renderable=True, noSurfaceShader=True, empty=True)
cmds.setAttr(shader + '.color', color[0], color[1], color[2], type='double3')
cmds.connectAttr(shader + '.outColor', shading_group + '.surfaceShader', force=True)
cmds.select(sphere)
cmds.hyperShade(assign=shader)
pipes = []
for i in range(len(spheres) - 1):
pipe = create_pipe(spheres[i], spheres[i + 1])
pipes.append(pipe)
pipe = create_pipe(spheres[-1], spheres[0])
pipes.append(pipe)
return spheres, pipes
In this version of the function, the color of each sphere's shader is interpolated between dark blue and light blue based on its vertical position (y
) in the helix. The t
value is used to control the interpolation, where t
is in the range of 0 to 1, indicating the progress along the helical height.
You can use this modified function in a similar manner as before:
python
num_spheres = 20
helix_radius = 10.0
helix_height = 2.0
num_turns = 4.0
spheres, pipes = create_spheres_and_pipes_helix_gradient(num_spheres, helix_radius, helix_height, num_turns)
This will create a helical arrangement of spheres with shaders forming a gradient from dark blue to light blue along the helical height."
I added the suggestions from the ai.
Comments
Post a Comment