TUTORIAL 8 – DNA: variations on a theme In this tutorial, we’ll explore different methods for modeling, rigging, and animating DNA. There are many ways to approach this macromolecule in Maya and each has its merits depending on what the model will be used for in your scene. We’ll start with a simple ‘plank’ DNA model that is roughly based on what is known about the molecule’s proportions, and then look at different ways to deform it. Next we’ll import a PDB coordinate set for B-DNA and experiment with different representations using particles. These first two methods assume that the helix does not need to unwind and melt. Finally, we’ll go over a programmatic approach to building DNA using PDB data for a single base pair – this method will allow us to twist and unzip the double helix. Before we jump in, let’s briefly review the structural features of B-DNA that are important for our modeling efforts: 19 Å in diameter o 10.5 base pairs per helical turn (~34 per base pair) 34 Å high per helical turn (~3.3 Å per base pair) For the purposes of our initial modeling efforts (i.e. ‘plank DNA’), we will round out these numbers to assume ~10 base pairs per helical turn and ~20 Å in diameter. One helical turn of ‘reference’ B-DNA created using the cartoon representation in PyMOL Part 1 – Plank DNA Modeling plank DNA In this first exercise, we’ll create a stand-in model for B-DNA that could be useful in schematic animations where atomic resolution is not required and melting of the double helix is not necessary. Here’s a quick overview of the process: 1) model a base pair with polygons, 2) animate its rotation and elevation to use the ‘animated snapshot’ tool, 3) create 2 NURBS curves slightly offset from the base pair, 4) use the ‘animated sweep’ tool to extrude those circles and create the backbone and finally 5) ‘duplicate special’ to create The first base pair consists of 4 polygon cubes additional helical turns to the model prior to rigging. Although we’ve reviewed B-DNA’s characteristics above, let’s also have a PDB-derived cartoon model in our scene to make sure we have the right proportions as we go through the modeling process. Go to the Learning section of www.molecularmovies.org and download supporting files. Open the ref_1helicalTurn.ma file – it’s a simple model of a single helical turn of DNA. This was generated in PyMOL (with the ‘cartoon’ representation), exported as a vrml2 file, converted to an obj, and then imported into Maya. Observe the model in various orthographic views and notice that it is 4 grid units wide and ~7 grid units high (from bottom baseTutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 1 pair to top base-pair). As expected, this is the correct ratio for B-DNA (i.e. 7units/4units = 34Å/20Å = ~1.7). Extend your timeline to 800 frames and save the file as plankDNA_01_modeling.ma. Let’s begin by creating a single base-pair with simple geometry. Using the polygon primitive cube tool, create a plank that is roughly 2 units long along the x axis, ~ 0.5 units wide along the z with just a little thickness along the y axis. Duplicated base pairs after the animated snapshot Duplicate the plank, scale it down slightly along the x axis, and move it on the other side of the origin along the x axis. Add a small plank angled at 45 degrees along the y to each larger plank (refer to the pictures on the right for placement). Select the 4 planks, group and name ‘bp.’ This base pair would need to rotate 360 degrees and travel ~7 grid units along the y axis to find itself one helical turn away from where it is now. Let’s animate that displacement: making sure you are on frame 1 of the timeline, select the bp group and key its Translate y and Rotate y attributes in the Channel Box (they should both be 0 by default). Now go to frame 100, change Translate y to 7 and Rotate y to 360 – key those values and play the animation. The base pair rises along the y axis while rotating, as if were traveling through all of the intermediate positions where the Placement of NURBS circles relative to the base pair intervening 8 base pairs would be. We will use this animation to ‘sprinkle’ a copy of the base pair at each appropriate location along the y – to do this well use Maya’s Animation Snapshot tool. With the bp group selected, go to the Animation menu set and go to Animate -> Create Animation Snapshot | Options – reset. With the Start time set to 1, the End time set to 100 (i.e. the range of your base pair animation), and the ‘Increment’ set to 10, click ‘Snapshot.’ Maya plays through the specific range of frames and takes a snapshot of the geometry every 10 frames (that’s the increment setting). Notice that it actually left out the last base pair – this is fine in that we will be Animation sweep settings for the backbone duplicating the entire helical turn later and therefore would not want this overlap. If you did want to get all 10 base pairs in the animated snapshot, you would need to set the End time to 101 (instead of 100) with the same increment of 10. Although we’ve applied it in a very basic way here (we could have used the ‘Duplicate Special’ tool here), the ‘Animated Snapshot’ technique is a powerful method of using any kind of animation to create duplicated geometry. Now we’ll use a similar to tool to create the backbone. Maya’s ‘Animated sweep’ tool, like the animated snapshot, places new copies of geometry based on an animation – but with 2 important differences: 1) it only works with curves and 2) it creates a lofted NURBS surface from all of these duplicated curves. Let’s see how this works. Create a NURBS circle and scale/position it on the grid such that it overlaps one of the outer corners of your plank. Duplicate Special settings to extend the DNA strand Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 2 Duplicate the circle and move/position it on the other side of the plank (see image on the right). Make sure they are both offset on the same side of the plank - this offset is what will create the major and minor grooving of your DNA model (i.e. the base pairs are centered on the helical axis, but the backbone strands are not). Select both circles, group and name ‘backbone circles.’ Similar to the process we used to set up the Animated Snapshot, we’ll need to animate the circles group – on frame 1, key the Translate y and Rotate y values and the on frame 100, key Translate y to 7 and Rotate y to 360. Back on frame 1 with the ‘backbone circles’ group selected in the Outliner, go to Animate -> Create Animated Sweep | Options (reset). Set the Start time to 1, the End time to 101 (we’ll want the geometry to The completed ‘plank DNA’ model extend all the way up to 7 grid units this time) and By Time to 10 – leave all the rest to defaults and press “Anim Sweep.” Notice the snapshot5 & snapshot6 groups in the Outliner, as well as 2 ‘loftedSurfaces.’ This shows you how the Animated Sweep works – it first does an Animated Snapshot operation and then lofts between the curves in the snapshot groups. Compare your modeled DNA to the reference model – they should be pretty much identical in terms of proportions (except for the intentionally missing last base pair at the top of your model). You can now hide ‘bp’ ‘backbone circles’ ‘snapshot5Group’ and Lattice settings ‘snapshot6Group’ before we proceed to growing the DNA strand. Select ‘snapshotGroups’ 1, 2, 3 and 4 (i.e. the base pairs) and the 2 lofted surfaces (i.e the backbone strands) and group them – rename the group ‘DNA.’ With this group selected in the Outliner, go to Edit -> Duplicate Special | Options (Reset). Use the following settings: Group under World, Translate y to 7, Number of copies to 4. You should now have a DNA model that is 5 helical turns – the Outliner shows every turn of the helix as a separate group. Save you file, and then Save Scene As: plankDNA_02_rigging.ma. Rigging your model There are many ways to deform this DNA model depending on the animation goals – in this tutorial, we’ll explore a technique where instead of creating a skeleton and skinning it to the geometry (which is typical), we first apply a lattice to the model and then skin the lattice to a skeleton. This can yield faster and smoother deformations – the skeleton controls the lattice, which in turn controls the model it is wrapped around. Select all the DNA groups in the Outliner and group them – rename it ‘DNA_strand.’ With this new group selected, go to Create Defomers -> Lattice | Options (Reset). We’ll use Adding a skeleton to your DNA model Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 3 settings that give us plenty of ‘deforming resolution’ along the y axis: Divisions 2 10 2 (keep the rest as defaults). You can test to see if your lattice works by RMB-clicking over the lattice and selecting ‘Lattice Point’ from the popup. Now drag-select some points and rotate or move them to deform the model. Switch to the ‘front’ orthographic camera and, with your model maximized/scaled in the viewport, go to Skeleton -> Joint Tool and create joints from bottom to top clicking at each ‘rung’ or division in the lattice. Press enter when you finished creating your skeleton – you should have 10 joints Settings for binding the lattice to the skeleton total and your joint chain should be centered inside the lattice by default. Return to the ‘perspective’ viewport. With the root joint selected (i.e. joint 1 in the Outliner), shift-select the lattice in the viewport and go Skin -> Bind Skin -> Smooth Bind | Options (Reset). Use the following settings: Bind Method: Closest distance, Max influences: 3 (rest at defaults) – click on ‘Bind Skin.’ Now select a joint at the center of the chain and rotate it – you should now see your DNA model bending around as you control the rotation of the joints! Save your scene. Controlling your rig A common way to control a skeleton is through the use of IK (Inverse Kinematics): instead of rotating and keying the position of every joint in a chain, IK allows you to key the position of a single IK handle. We already explored this when we rigged the sigma ‘tentacle’ in the Animation tutorial Rotating individuals joints deforms the lattice along with the underlying DNA model – for our model DNA, however, we’ll look at another type of IK called spline IK. The main difference is that in spline IK a curve is used to control the joint chain instead of an IK handle. Save your scene as plankDNA_03_rigControl.ma. To make things easier to select and see as we add layers of control to this rig, hide the lattice and switch your viewport to X-Ray mode (shading -> X-Ray). To add a spline Ik controller to your skeleton, go to Skeleton -> IK Spline Handle Tool | Options (Reset). As per the instructions that show up in the lower left-hand corner of your scnreen, first click on the root joint of the skeleton (joint 1 at the bottom) and then on the top joint of the chain. You’ll notice two new nodes in the Outliner: an IK handle (which, unlike ‘regular IK’, you will not be able to move) and a curve. In the ‘Show’ drop-down menu of your perspective viewport, toggle off the visibility of ‘Joints’ and ‘IK Handles.’ What should be left at the center of your DNA model is a blue curve. Select it and, in the Surfaces menu set, go to Edit Curves -> Rebuild Curves | Options (Reset) – set the Number of spans to 10, make sure it is cubic/degree 3 curve, and the ‘Keep original’ option is off – click Rebuild. With the curve selected, switch to component mode (F8), select one or several CVs and move them – the DNA model is now being Rebuilding the spline IK curve Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 4 deformed in response to the shape of the curve! Typically, if you want start keying the shape of the curve, you would select the CVs and create clusters for each one and key the position of the clusters. You could also apply any deformer to the curve – anything that influences the shape of your curve over time will animate the DNA. To add some organic motion to the DNA, we’re going to convert the spline IK curve into a softbody with goals and then apply fields. Select the curve and, in the Dynamics menu set, go to Soft/Rigid Bodies -> Create Softbody | Options (Reset) – use the following settings: Creation Options: Duplicate, make original soft (this is key since it is only the original curve that is the spline IK and controls your skeleton). Hide non-soft object is on Make non-soft a goal is on Weight: 0.3 Click ‘Create.’ Moving the CVs on the spline IK deforms the DNA As with any particles, we’ll need to add a field to see any effect – expand the ‘curve1’ node in the Outliner and select the particle object under it. Go to Fields -> Turbulence | Options (Reset) – set the magnitude to 10 and the attenuation to 0, click Create. Select the field in the Outliner and, in the Channel Box, add an expression to the Phase X channel (select the channel, RMB-click over it and select ‘Editors -> Expressions’): turbulenceField1.phaseX=time; turbulenceField1.phaseY=time; turbulenceField1.phaseZ=time; Adding a Turbulence field to affect the softbody curve If you now play the animation you should see a wiggling DNA strand! You now have all the control that dynamics affords you in terms of how the DNA follows the goal curve (fields, springs, goalPP, etc…). Instead of a softbody we could also have turned the spline IK curve into Maya hair – this option gives you even more attributes and control over a goal weight value for the softbody. If you want to add more ‘directed’ animation and motion to your DNA on top of the dynamic/organic wiggling, you still have the goal curve (hidden and called ‘copyOfcurve1) to animate. You could add clusters to each of the CVs and then key their positions and/or add non-linear deformers to the curve. For an example of both of these deformations, view the plankDNA.mov example movie associated with this tutorial on molecularmovies.org (and see the picture to the right). Fully rigged DNA model (includes clusters & sine deformer on spline IK goal curve) Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 5 Part 2 - Imported PDB DNA pdbReader & ballAndStick MEL scripts In this section of the tutorial we’ll import a PDB file for an entire strand of B-DNA using Tom Doeden’s pdbReader script that creates NURBS spheres at every PDB coordinate point. The original script has been around for while and can be downloaded form www.highend3d.com. We will actually be using a version of the script that was slightly modified by Sourcing a MEL script from the script editor Geordie Martinez (www.negative13.com) so that it works with his ballAndStick MEL script. The latter script will allow us to add bonds (NURBS cylinders) between atoms generated by the pdbReader script. Another approach will also be to take the spheres generated by the pdbReader script and, instead of adding bonds, we’ll use a MEL script to create a particle at every sphere (jPivToParticle created by Julian Mann) and then use the blobby sphere render type to render the DNA. An important note before we jump into this section – this part of the tutorial is heavily influenced by THE original tutorial on the use of these scripts: Eric Keller’s now famous “Working with Macromolecular Data in Maya: DNA” which can be found on www.highend3d.com. Kudos to Eric (www.bloopatone.com) for initially putting this material together into a tutorial – it has been widely used since it’s initial print publication in Highend3D magazine. The following is just my ‘reimplementation’ of the steps as they relate to an audience of scientists. Start with a new Maya scene and go to the script editor – under File -> Source Script… find the pdbReader.mel script. Nothing will happen when you click ‘Open.’ To run The pdbReader.mel script window the script, type ‘pdbReader’ in the MEL command line at the bottom left of the Maya interface – hit enter, and a small pop-up window should appear. At the top click on “Get PDB File” and search for the DNA.pdb file that you downloaded along with the other materials for this tutorial. Once loaded into the window, you will notice that the “Sample line of data Imported sphere model in the perspective viewport from the file” is now populated with typical PDB data – this takes a little experimenting as the columns may be slightly different for different PDBs… but the goal is to find the right x y z coordinate columns and specify them in the X Field, Y Field, Z Field in the script window. In the case of this PDB, enter 3 for the Atom Field, and 7, 8, 9, for the X, Y, Z Field values respectively. Now click on ‘PRESS ME – Create Molecule Structure.’ This may take a few moments – you will know Maya is done when you see four new nodes in the Outliner called ‘PhosphorusGrp’, ‘OxygenGrp’ etc… If you click in the perspective viewport to unselect any geometry and then press F, your camera should now zoom out to encompass The ballAndStick.mel script window Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 6 the imported model. As is typical with imported PDB data, the model is large and far away from the grid. Press 5 to view the shaded model. You’ll notice that the pdbReader script has assigned a different shader to each atom – very convenient. Let’s resist the urge to scale and center the model until we have played with the ballAndStick script a bit. In the MEL command line, type ‘ballAndStick’ and press Enter – a pop-up window appears. Read Geordie’s comments – he goes over the basics of how the script works and provides default values that work well to create bonds. As suggested, let’s begin by resizing all of the spheres in our DNA model – open each of the 4 atom groups in the Outliner and select the long list of spheres within each group, scale each down to 0.5 in the Channel Box. Now let’s test Sticks added to part of the DNA model the script – marquee-select a few spheres (~1 base pair equivalent) in the perspective viewport and run the script by pressing ‘Generate Sticks.’ You should see light grey cylinders appear between atoms in your selection. Repeat the operation a few times by selecting different sets of atoms. To view the fully-shaded bonds, go to Renderer -> High Quality Rendering in your perspective viewport dropdown menu. Creating particles with jPivToParticle In the Outliner, delete the ‘StickGroup’ that was generated as a result of running the ballAndStick script. Select the remaining 4 main groups (PhosphorusGrp, OxygenGrp etc…) and group them – name the group ‘DNA.’ Now with this new group selected, scale it down to 0.2 and center pivot. Move the model to the center of the grid and switch between orthographic views to straighten the model. Freeze transformations on the master group ‘DNA’ and the four subgroups. If you inspect the model and expand the groups in the Outliner you’ll notice that the spheres are all very low tessellation NURBS which is what makes this script so great. Indeed, a sphere model imported from any molecular graphics program would yield polygonal spheres with high tessellation (with the exception of Jmol which now has an export to the .ma file type and yields NURBS spheres – thanks to Bob Hanson for that Jmol feature!). In any case, despite this lighter geometry, it is still almost unworkable when dealing with medium to large models of proteins for example. Converting the spheres to particles increases performance and, for some like Drew Berry, is also a preferred means of rendering molecules (using Hardware rendering as opposed to Software rendering). To run the jPivToParticle script, begin by ungrouping all spheres in the Outliner: select the 4 main groups and go to Edit -> Ungroup. You should now have a long list of NURBS objects with various atom names listed directly The model scaled down and centered at the origin Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 7 under the DNA group. Select all the spheres in the Outliner and, in the MEL command line, type jPivToParticle “DNA_” and press Enter. A new particle object should appear in the Outliner, all the names of the spheres now start with DNA_ and have a number. You can now select the DNA master group and hide it – what should remain in the viewport is a mist of grey particle points. Each sphere has been replaced with a single particle and all the particles belong to the same particle object. This last point is critical it‘s what will allow us to get a blobby look between the DNA atoms (this would not happen if each atom type was in its own particle object – i.e. blobbies don’t form blobbies between particle objects). Select the particle object and, in the Attribute Editor, switch the render attributes to ‘Blobby Surface [s/w]’ – click on Current Render Type and reduce the radius to 0.3. Take a render and click the “Keep Image” button (little open grey box with a black arrow pointing down into it). Now increase the Threshold value to 0.45 and take another render – compare the two images. After running the jPivToParticle script, particles are positioned at each sphere location in the model. Points are switched to ‘blobby surfaces’ for rendering. Now that your model is made of particles, there are a number of ways to control it. Since Maya version 6, you can also add non-linear deformers to particles. For an example of a bend-deformer applied to this model, view the blobbyDNA.mov example movie associated with this tutorial on molecularmovies.org DNA rendered with blobby surfaces: Threshold=0 DNA rendered with blobby surfaces: Threshold=0.45 Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 8 Part 3 - Creating a DNA rig by Janet Iwasa In this section of the tutorial, you will use PDB reader and some rigging tricks to create a segment of DNA that can undergo strand twisting and untwisting as well as strand separation. Importing nucleotides using PDB reader The primary building block that we're going to use to create our rig is two nucleotides base paired to one another. I created a PDB for you to use by taking a PDB of doublestranded DNA, and rather laboriously deleting everything but two paired bases (plus some extra atoms for alignment). Scaling the atoms of the base pair to have a more conventional spacefilling look. If you haven't already sourced the PDB reader script, go to the script editor, select File > Source Script and select the PDBreader plugin. In the MEL command line, type "pdbReader" and press Enter. Run pdbReader as you've done in the previous example, using "oneBP.pdb" as the input pdb file. After you import the basepair, if you take a look at it (frame using the 'f' key in the perspective view), you'll see that the atoms are sort of small. Draw a selection box around all of the atoms of the basepair and scale them up so that they have a more conventional space-filling look. In the perspective window, select the atoms of one of the nucleotides, press ctrl+g to create a new group, and name it "baseL" in the outliner (by double clicking on the name). Select the atoms of the other nucleotide, create a new group, and name it "baseR." Create groups for the left and right nucleotides. Note that the atom type groups that were created by PDBreader ("NitrogenGrp," "CarbonGrp," etc) are now empty and can be deleted. Select baseL and baseR in the outliner and group them together, naming the new group "pair0." Center the pivot of pair0 (Modify > Center Pivot) and move pair0 to the center of the grid using grid snapping (by keeping x depressed while moving). Rotate pair0 so that the bases are approximately flat along the x-z plane, and scale to 0.5. Freeze the transformations of pair0 (Modify > Freeze Transformations). Creating a double stranded helix Top orthogonal and side orthogonal views of the pair0 after adjusting rotation and scale. Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 9 Select pair0 in the outliner and duplicate it (ctrl+d). This duplicate should be named "pair1" by default. In the channel box, change the rotation Y value to 36. Move pair1 around in X, Y and Z to align it so that pair 1 has overlapping oxygens with pair0 (refer to image on right). Do this without changing any of the rotation values; only change the translate values! This might be tough depending on how you set up pair0, and don't worry if it isn't perfect. If the oxygens are impossibly far apart, delete pair1 and go back and adjust the rotation of pair0, making sure to freeze transformations after you make your adjustments. Delete one of each of the overlapping oxygens (doesn't matter which one). Now select pair1 in the outliner and take a look at its translate coordinates in the channel box (remember, the rotations should all be 0 except rotate Y, which should be 36). With pair1 still selected, go to Edit > Duplicate Special and open the options box. In the Duplicate Special Options window, input the translate values for X, Y and Z of pair1 into the translate boxes. Change the rotate Y value to 36, and change number of copies to 19. Press 'Duplicate Special.' Top orthogonal and side orthogonal views of the pair1 and pair0, with overlapping oxygens shown in green for clarity. You should now have a nice helical model of DNA. Building a DNA untwister In order to unwind our DNA, we need to change the Y rotation coordinates for each of our pairs to 0. We could do this manually, or better, brainstorming a bit and coming up with some clever MEL tricks. One way that we can imagine how to rig the DNA twist is by imagining that the bottommost pair (pair0) is fixed, and that the topmost pair (pair20) is free to rotate in Y, and that its rotation will determine the rotation of all the other basepairs. Imagine, for example, holding a rope ladder from the top rung and rotating that rung around, with the bottommost rung being tied down to the ground, and thus unable to rotate. Duplicate Special Options box for creating 19 duplicates of pair1 with the correct translation and rotation values. To get started, we need to figure out what the rotation is for the topmost pair. If you click on pair20 and check out its Y rotation, you'll see that it's 0. Each 10th base should return to 0 since each base's Y rotation is offset by 36 degrees. This means that you can think of the Y rotation value of pair10 as 360 and pair20 as 720. Change the Y rotation value of pair20 to 720. Since base0 will always be 0, all the basepairs in between (base2 through base19) will be a fraction of the Y rotation of base20, such that base20 would be the master rotation controller of all of the basepairs underneath it. For this, we would want the Y rotation of base19 to be 19/20th the Y rotation of base20, base18 should be 18/20th, and so on. The DNA after duplicating pair1. You should have 21 basepairs in all. Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 10 We could do this using expressions that control the Y rotation of each pair. To see how expressions are handled in MEL, let's go through one example. Select pair19, select "RotateY" in the channel box and right click. Select "expressions" from the drop down menu. Type in the following expression: rotateY = pair20.rotateY * 0.95; and press 'Create.' (note that 0.95 is 19/20). You shouldn't notice any difference since the rotation value should be the same as it was before, but now if you rotate pair20, you should see that pair19 rotates with it (but always slightly less). Take a look at the MEL that was used to create the expression by opening the script editor (Window > General Editors > Script Editor). You should see a line that looks something like this: expression -s "rotateY = pair20.rotateY * .95;" -o pair5 -ae 1 -uc all; We want to use MEL to create this expression for pairs2 through pair19. First, make sure that the expression is no longer controlling pair19's rotation by selecting 'RotateY' in the channel editor and selecting 'Break Connections' from the drop-down menu. Now to implement the plan, type in the following in the script editor: for ($i=1; $i<=19; $i++) { float $rotY = $i * 0.05; expression -s ("rotateY = pair20.rotateY * " + $rotY + ";") -o ("pair" + $i) -ae 1 -uc all; } Select the text and press control+Enter to run it without clearing the text (which makes things easier to edit in case you made a mistake). Let's go through what the script is doing. for ($i=1; $i<=19; $i++) {} This is a for loop, similar to ones we've done before, where anything in the curly brackets will be done 19 times (starting with 1 and ending with 19). float $rotY = $i * 0.05; Here we're creating a variable, $rotY, which will determine what fraction of pair20's Y rotation will be given to the basepairs below it. In this case, we want pair1 to have a Y rotation that is 0.05 (or 1/20th), pair2 to have 0.1 (or 2/20th), and so on. expression -s ("rotateY = pair20.rotateY * " + $rotY + ";") -o ("pair" + $i) -ae 1 -uc all; For this line we simply copied and pasted from the line we saw earlier when we created a new expression, but edited it so that the pair name ("pair" + $i) changes dynamically while working through the for loop. Within the expression, we're combining a string ("rotateY = pair20.rotateY * ") with a float value ($rotY, which we defined in the previous line). Pair20 is now controlling the Y rotation of all the bases underneath it. Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 11 Take a look at the Y rotation in the channel box for each of the pairs betwen 1 and 19. You should see that the box is purple, and when you right click and select 'Expressions...,' you can view and edit the expression you made with the script. Now if you change the value of pair20's Y rotation, you should see that all of the pairs below follow. Creating a DNA Master Controller Next, we're going to build a master controller that's going to let us control our DNA's movements a little more intuitively. Creating a new attribute called 'twist' for the Create a new null group by selecting Create > Empty Group. masterController. Note the channel box on right is blank. In your outliner, you should notice that you now have something called "null1." Rename the empty group "masterController." We're going to be creating our own attributes for our masterController, and won't be needing any of the default ones. In the channel box, click-drag over everything (from TranslateX to Visibility), and with them selected, right click and select "Hide Selected" from the drop down menu. Now we'll create a new attribute. Right click in the empty channel box and select "Attributes -> Add Attribute" from the dropdown menu. In the window that appears, name the attribute "twist," make sure that's it's data type is "float" and set the minimum to 0, the maximum to 1, and the default to 1. Select "Add." Create another new attribute called "separate" with the same settings, except have the default value be 0. The channel box of the masterController now has two new attributes. So what are we going to have this master controller do? We want the twist value of the master controller to control the rotateY value of pair20, which will in turn control the rotation of the pairs below it. When twist is at 0, we want the rotateY of pair20 to also be at 0, but when twist is set to 1, we want pair20 to be 720. To set up this relationship, we'll use the "setDriven" technique. Select pair20 in the outliner, then, in the Animation menu, go to Animate > Set Driven Key > Set... A new window should appear, with pair20 appearing in the lower, "Driven" area. Now select the masterController in the outliner, and in the Set Driven Key window, click on "Load Driver." In the right section, next to "masterController," click on "twist." In the bottom right, next to "pair20," click on "rotateY." What this sets up is a relationship where we can have the masterController's twist attribute controlling the rotateY of Setting up the driver and driven objects. Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 12 pair20. Now we need to set keys to determine the range of control. Make sure that the twist attribute of the masterController is set to 1, and the rotateY attribute of pair20 is set to 720 in the channel box. Then click on "Key" in the Set Driven Key window. Now set the twist attribute of the masterController to 0, and set the rotateY of pair20 to 0 as well, and click on "Key" in the Set Driven Key window again. Now change the Twist value of the masterController. It should be controlling the twist of the DNA. A nice way to do this is to click on "Twist" in the channel box (the text should highlighted in black on a PC - as shown in the image on the right – and blue on a Mac), and middle mouse drag in the perspective window. This should allow you to dynamically change the attribute. Set the Twist value to 0. You probably already noticed that when all of the pairs Y rotation is set to 0, the DNA looks quite wavy. How can we fix this? The problem is due to the fact that when we originally created the helix, we moved the pairs in X and Z, and these movements were repeated along the length of the helix. Ideally, we'd like to keep the current values of translateX and translateZ when the helix is completely twisted, but have them set to 0 for when twist is set to 0. When twist is set to 0, the DNA looks wavy. Let's set up some more set driven keys to do this, but using MEL. If you take a look at your script editor, you should notice that the command to create a set driven key is pretty simple: setDrivenKeyframe -currentDriver masterController.twist pair20.rotateY; The -currentDriver flag indicates the driver (the twist attribute of the masterController) and the last argument (pair20.rotateY) determines what's being driven. Type in the following into the script editor: for ($i=1; $i<=19; $i++) { setAttr "masterController.twist" 1; setDrivenKeyframe -currentDriver masterController.twist ("pair" + $i + ".translateX"); setAttr "masterController.twist" 0; setAttr ("pair" + $i + ".translateX") 0; setDrivenKeyframe -currentDriver masterController.twist ("pair" + $i + ".translateX"); } Run the script (highlight it and hit Ctrl-Enter) and try changing the twist value of the masterController to check if it's working. You should see that now the translateX is moving to 0 when twist is 0, but translate Z hasn't been fixed yet. Run the previous expression again (you can cut and paste it from the upper part of the script editor) and replace all three instances of "translateX" with "translateZ." Breaking down the script: setAttr "masterController.twist" 1; Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 13 "setAttr" is short for "set Attribute" and sets, in this case, the twist attribute of the masterController to 1. The translateX (or Z) value should already be set to whatever we want it to be when twist is 1, so we can go ahead and set the driven key: setDrivenKeyframe -currentDriver masterController.twist ("pair" + $i + ".translateX"); In the 2nd half of the script, we're repeating the same thing after setting twist to 0 and translateX of the pair to 0. The last thing that we want the masterController to do is to separate the two strands of DNA. In the outliner, take a look at the hierarchy of your DNA. Each pair is made up of a "baseL" and a "baseR." For our strand separation, we'd like baseL and baseR to move in opposite directions from the origin. Depending on how you arranged your DNA, baseL may need to go in the +X, -X, +Z or -Z direction, and baseR in the opposite direction along the same axis. Figure this out before the next step! Now we'll just write a little more MEL to have the masterController's 'separate' attribute control strand separation. We will be using the exact same setDriven technique as we have before. Type in the following script into the Script Editor (keeping in mind that you’ll need to replace “translateX” and “5” with whatever axis and +/- value for 5 works in your case) Very straight DNA when twist is set to 0 for ($i=0; $i<=20; $i++) { setAttr "masterController.separate" 1; setAttr ("pair" + $i + "|baseL.translateX") 5; setDrivenKeyframe -currentDriver masterController.separate ("pair" + $i + "|baseL.translateX"); setAttr "masterController.separate" 0; setAttr ("pair" + $i + "|baseL.translateX") 0; setDrivenKeyframe -currentDriver masterController.separate ("pair" + $i + "|baseL.translateX"); }; Now test out the script by changing the masterController separate attribute. You should see that the left bases move away as the separate value gets larger. For the right bases, repeat the script above, but replace the "baseL" with "baseR" (four instances) and the 5 with -5 (or vice versa). After extending your timeline to ~200 frames, you can now key the twist channel from 0 (on frame 1) to 1 (on frame ~100). Now key the separate channel to 0 on frame 1, set another key of 0 at frame ~ 80, and then a value of 1 on frame 150. You can see that having a masterController like this could make your life much easier as you're trying to animate. Rather than needing to set keyframes on a large number of objects (42 bases, or 21 pairs of bases, in this case), we only need to set a single keyframe of a masterController attribute. A bit of Twist & Separation. Tutorial 8 – DNA: variations on a theme Fall ’08 Gaël McGill & Janet Iwasa 14