Anim8or Community

Please login or register.

Login with username, password and session length
Advanced search  


Ian Ross has just released a book on Anim8or. It's perect for a beginner and a good reference for experienced users. It contains detailed chapters on every aspect, with many examples. Get your own copy here: "Anim8or Tutorial Book"

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - Raxx

Pages: [1] 2 3 ... 6
ASL Scripts / ASL File import?
« on: December 11, 2017, 04:10:09 pm »
Any chance of this happening any time soon? I use Anim8or when I need to 3D print stuff, but I use other cad and vector programs for when I have exacting design requirements. I've been wanting to write svg, eps, fbx, and dae importers for the object editor for a while now, without having to create a 3rd party program.

Anim8or v0.98 Discussion Forum / Bug/Issue: Normals (ASL)
« on: March 06, 2016, 09:15:49 pm »
I'm posting here since this seems like a bug to me. I'm working on a new set of scripts and part of it detects the sharpness/creases of edges in the geometry. I'm doing this by measuring the dot product of the normals of the two faces connected to an edge to get its sharpness (1 is flat, 0 is not).

To get the face normals, I'm calculating the mean of all the normals of the points in a face (ie (normal1 + normal2 + normal3)/3). I'm getting these normals using GetNormal(GetFaceNormalIndex()), rather than calculating the geometric normal manually. I'd rather not go through the hassle of triangulating and math-ing and combining for each face since it's more work, and more convoluted since I have to work with mesh data not tridata.

The issue is that I have a symmetrical mesh, and at a lot of locations a face on one side comes up with different normals than the corresponding face on the other side. I get why this can happen for n+3 sided faces, but it's also happening for triangles! And yet when I show normals in the Options->Debug menu, the triangles' normals look exactly symmetrical when the ASL version is not. This leads me to believe that there is some sort of lack of precision going on or something. My script needs precision!

So here I am reporting it. I hope it can be fixed if it's not an error on my part. Below and attached are examples that I hacked together to show what I mean.

ASL Snippet
  1. file $c;
  2. shape $s, $childShapes[0];
  3. int $i, $j, $k;
  4. float $numSides;
  5. point3 $faceNormal;
  7. $"$console", "w");
  9. project.curObject.GetShapes($childShapes);
  11. for $i = 0 to $childShapes.size - 1 do
  12. {
  13. if($childShapes[$i].GetKind() == SHAPE_KIND_MESH)
  14. {
  15. $s = $childShapes[$i];
  17. for $j = 0 to $s.GetNumFaces() - 1 do
  18. {
  19. if ($s.GetFaceSelected($j) == 1)
  20. {
  21. $faceNormal = $s.GetNormal($s.GetFaceNormalIndex($j, 0));
  22. $numSides = $s.GetNumSides($j);
  24. for $k = 1 to $numSides - 1 do
  25. {
  26. $faceNormal = $faceNormal + $s.GetNormal($s.GetFaceNormalIndex($j, $k));
  27. }
  29. $faceNormal = normalize(($faceNormal.x/$numSides, $faceNormal.y/$numSides, $faceNormal.z/$numSides));
  31. $c.print("\nFace %d has normals (%.3f, %.3f, %.3f)\n", $j, $faceNormal);
  32. }
  33. }
  34. }
  35. }
  37. $c.close();

The above script lets you select faces, so that when you run it it'll print in the console what the face normal is for each of the faces.

General Anim8or Forum / Twitch Streaming
« on: February 21, 2016, 06:02:39 pm »
Hey guys,

I'll be streaming a modeling session on Twitch at 11:00pm Eastern (GMT - 5). If you want to watch and chat, feel free set your browser to 5 hours from this post

ASL Scripts / Animated Textures Using Controller Scripts
« on: January 18, 2016, 09:10:18 am »
Animated Textures Using Controller Scripts
The not as hard way of doing it the hard way

Hello folks, here's a controller script for animating textures within the scene editor. Please read the information below on how to use it, download the .7z file containing the examples, and/or watch the video tutorial. (Note: the images in the .7z file had to be reduced in quality in order to upload correctly).

What it does
This controller script takes an Anim8or texture and swaps the file name on command, using a main controller script that reads the data of an animation controller for a sprite object. This script will animate any texture on any material that is applied to any mesh.

  • Particle effects
  • Animating facial expressions when the face or parts of the face uses textures instead of geometry (like for example, Mii characters)
  • Videos in the scene, like television screens, computer monitors, or sci-fi projections
  • Entirely 2D animated character sprites
  • Etc.

How to use the controller script
Download the .zip file attached to this forum post and extract it. The contents of the zip file should be:
  • sprite_controller.txt - This is the controller script with the default configuration. Use copies of this, change the parameters inside it, and apply the changed copies to your animated textures in Anim8or following the instructions further down.
  • Example 1 - Video and Fire.an8 - This is the same file that was made in the first part of the video tutorial. It has animated fire and an animated computer screen.
  • Example 2 - Character Sprite.an8 - This is the same file that was made in the second part of the video tutorial. It has an animated character sprite that runs and jumps.
  • Sprites folder - Contains the sprite image sequences used in the two example .an8 files

Step 1: Setting up the sprite object

A unique object, material, and texture for each unique sprite you wish to animate

The sprite object, in the object editor, needs to contain a mesh with a material applied to it. This material needs to have a texture loaded into it. The important thing is the name of this texture object (circled in red in the image above). The controller script will be swapping the filename of this texture, and to do so it needs this name.

If you want to have multiple unique sprites in the scene that use the same sequence of images (just animated differently), you need to create a new object, a new material, and a new texture for each sprite instance you want to use. You don't have to make these copies if you only want to use one instance of the sprite in multiple scenes, or if you want to use duplicates of the sprite that all animate identical to each other in the same scene.

Step 2: Setting up the scene
The first thing you need to do is create a "sprites_enabled" boolean controller in the scene, applied to the "world" element. This is an on/off switch which enables or disables all of the animated textures in the scene. This is handy because sometimes Anim8or will randomly crash if you click on the sprite element while the controller script is active (the setFileName() in the script function seems to cause this random-seeming crash).

Add a "sprites_enabled" boolean controller

Do this by going to Edit->Controllers..., select the world element in the top drop down menu, and then clicking on the "New" button. A boolean controller can only have a value of 0 or 1. In the timeline on the first frame, set its value to 1 to enable it ahead of time.

Add and name your sprite object to the scene

Next, add your sprite object to the scene and give it a suitable name. For example in the image above, I named it "fire1_sprite". The reason for the "1" in the name is in case I wanted multiple unique instances of the sprite in that scene. This name is important since the controller script will be referencing it.

Mouthe needs both an anim_controller and a swap_controller

Now create two float-type controllers for that sprite element. The first one will be the animation controller, so name it something sensible like "anim_controller". The second one will be the swap controller (I usually name it "swap_controller", and is optional and only required if you want to animate two different sets of sprites on the same sprite element (like in the second .an8 file where the mouthe sprite has a run and jump animation that it swaps between).

What you just created were the controllers that tell the controller script which frames to animate for what set of textures. Next you'll have to create the element that holds the controller script itself. There is some flexibility in how you do this, but you can follow the next bit of instructions for an easy, organized way to manage your controller scripts.

Creating the containers for the controller scripts

First, add a target and name it "sprites_scripts" (or something similar). This will be the "container" that holds all of the controller scripts.

Next, add another target and name it based on the sprite you wish to control. For example in the image above, I named it "fire1_script". This target is what will hold the controller script. Then parent the "sprites_scripts" target to this target you just created. In the timeline, it should look something like in the image above.

Step 3: Configuring the controller script
In a text editor, open up the "sprite_controller.txt" file. There is a set of parameters that you need to configure in order for the script to know what textures to work with. Unless you are intentionally modifying the controller script to change its core programming, only modify the parameters that are between "/* FILL OUT ANIMATION DATA HERE */" and "/* EVERYTHING PAST HERE, LEAVE ALONE */"

Below is a description of each parameter. Please change any or all that are required for your specific sprites.

  1. $enabled = 1;

Required. Enables or disables the animation of that sprite. Handy if you have large amounts of sprites and just want to have a single one active while you work with it.

Texture Name
  1. $texName = "";

Required. This is the name of the texture that you made (circled in red in the image in Step 1).

Animation Controller Details
  1. $controllerAnimFloat = GetAttributeFloat("Sprite_Element_Name", "Anim_Controller_Name");

Required. Change "Sprite_Element_Name" to the name of the sprite element it's controlling. For example, it was "fire1_sprite" in Step 2. Change "Anim_Controller_Name" to the name of the animation controller you created for that sprite element. This was named "anim_controller" in the Step 2 example.

Animation Controller Type
  1. $controllerAnimType = "multiplier";

Required. There are two options to specify for how the controller script handles the values passed in the animation controller you specified above. The default option, "multiplier", interprets the values as the percentage of the animation cycle you want to play. For example, a value of 0 means it's the first frame of the animation cycle. A value of 1 means it's the last frame of the animation cycle. A value of 0.5 means it's the middle frame. A value of 2.5 means it's the middle frame, except in the second animation loop.

The second option is "frame". This allows you to specify the exact frame of the animation cycle (starts at 0). So a value of 0 means it's the first frame. A value of 1 means it's the second frame. A value of 51 means it's the 50th frame. If the animation cycle has only 25 images in its sequence, then a value of 51 would mean that it's at the start of the second loop.

Swap Controller Details
  1. $controllerSwapFloat = GetAttributeFloat("", "");

Optional. Leave blank if you don't need to swap the animation cycle with a different one for that particular sprite object. Fill the first string with the name of the sprite element it's controlling. For example, it was "fire1_sprite" in Step 2. Fill the second string with the name of the swap controller you created for that sprite element. This was named "swap_controller" in the Step 2 example.

Texture File Name - Prefix
  1. $texPrefix.push("");

Required. Fill in the quotation marks with the prefix of the texture file the animation cycle is using. For example, if a texture file is named "file_0001.png", then "file_" is the prefix.

If you are using a swap controller, then for each set of textures you need to animate, you have to add another '$texPrefix.push()' line. This is also required for all of the .push() parameters. The first .push() parameter corresponds to the value 0 in the swap controller. The second .push() parameter corresponds to value 1 in the swap controller. Etc, etc. Don't mix up the order of the .push() parameters.

Texture File Name - Number of digits
  1. $texDigits.push();

Required. The texture files in the animation sequence must be numbered sequentially with the same number of digits. "file_1.png" will not be considered in the same sequence as "file_0002.png". It must be named "file_0001.png". The parameter above specifies this number of digits. For example, "file_0001.png" has 4 digits, so you would place the number 4 inside the parenthesis with no quotation marks (it would look like '$texDigits.push(4);')

Texture File Name - Type
  1. $texType.push("");

Required. Set the file type. It'll be either png, bmp, gif, or jpg. For example, if the sequence of files were png files, it would look like '$texType.push("png");'

Texture File Name - Path
  1. $texPath.push("");

Required. Set the path to the sequence of files for that sprite. If you want to set a path relative to the .an8 file, and the files are in subfolders of that .an8 file, you would use something like '$texPath.push("./Path/To/Files/");'. Otherwise if you want to specify the absolute path to it, set it like '$texPath.push("C:/Path/To/Files/");' Make sure a forward slash is at the end for whichever of these options you choose.

If you placed all of the textures in the same path as what you specified for the texture directory in File->Configure, you can leave it as just '$texPath.push("");'. Note however that the script does not and can not look through subfolders.

Texture File Name - Starting Number
  1. $texStartingFrame.push();

Required. Use the same number as the first file in the sequence. For example, if the first file was named "file_0001.png", the parameter would look like '$texStartingFrame.push(1);'. If the first file was named "file_0024.png", it would look like '$texStartingFrame.push(24);'.

Texture File Name - Ending Number
  1. $texEndingFrame.push();

Required. Use the same number as the last file in the sequence. For example, if the last file was named "file_0036.png", the parameter would look like '$texEndingFrame.push(36);'. If the last file was named "file_0125.png", it would look like '$texEndingFrame.push(125);'.


If you want to make it easier to read which set of .push() parameters applies to which set of file sequences, you can re-order it to look like this:

Alternative way to set multiple swap parameters
  1. // Swap value 0
  2. $texPrefix.push("");
  3. $texDigits.push();
  4. $texType.push("");
  5. $texPath.push("");
  6. $texStartingFrame.push();
  7. $texEndingFrame.push();
  9. // Swap value 1
  10. $texPrefix.push("");
  11. $texDigits.push();
  12. $texType.push("");
  13. $texPath.push("");
  14. $texStartingFrame.push();
  15. $texEndingFrame.push();
  17. // Swap value 2
  18. $texPrefix.push("");
  19. $texDigits.push();
  20. $texType.push("");
  21. $texPath.push("");
  22. $texStartingFrame.push();
  23. $texEndingFrame.push();

Step 4: Applying the controller script
Assuming you completed Step 3, copy the entire controller script to your clipboard (Ctrl+C). Next, double-click on the controller script target you had made in Step 2. Click on the '...' button next to the Location details, set the Expressions to 'On', and click the 'Edit' button. Select everything in the text field that pops up and press Ctrl+V to replace it with the controller script.

Copy the controller script into the script target's position controller

The reason we're using a controller script target and applying the controller script to its 'position' controller is so that we can bypass a bug in Anim8or, in which after setting a controller as an Expression, you can no longer access it via the timeline (or any other means aside from editing the .an8 file in a text editor). The only way you can access a controller is through the element's dialog box and clicking on the buttons corresponding to its preset controllers. Until this bug is fixed, you'll have to do it this way. Otherwise you don't have to create controller script 'targets' and instead just add controllers directly to the controller script container target you had first created. Then you'd apply the controller scripts to these controllers.

Step 5: Animating
If you want to animate the textures, you have to keyframe the animation controller and (optionally) the swap controller assigned to that sprite element. For example, in Step 2, this was "anim_controller" and "swap_controller".

Animation Controller
This is the main meat of the animation and tells the controller script which frame of the animation cycle corresponds to which frame in the timeline. Keyframe this on the timeline to any values you need, based on the animation controller type parameter you specified in Step 3. Anim8or will interpolate between these values on the timeline. Anim8or will interpolate between these values on the timeline and the controller script will round this value to the nearest integer, thus picking which frame of the animation cycle to use.

Anim8or currently doesn't have a means to create linear keyframes (that I know of, anyway). Meaning if you look in the graph editor, the paths connecting the keyframes will all look like curves until you manually change the path nodes. If you want to slow down or speed up the animations then having curves is fine. Otherwise adjust the node handles so that these paths are as linear (straight) as possible. You may have to set the keyframe type to "corner" or "step" in order to accomplish this.

Swap Controller
This controller swaps between the sets of animation sequences you had specified in Step 3 (using the .push() parameters). The first set corresponds to the value 0. The second set corresponds to the value 1, etc etc. Keyframe this on the timeline to any values you need. Anim8or will interpolate between these values on the timeline and the controller script will round this value to the nearest integer, thus picking which set to use. I recommend using "step" type keyframes for the swap controller.

Important things to know or remember

  • Always create and use the "sprites_enabled" boolean controller in each scene that you use this controller script. A value of 1 is enabled, 0 is disabled.
  • Crashing happens much more often thanks to this script. Save often.
  • If crashing occurs as soon as you open the Anim8or project and click on one of the sprites or controllers, set "sprites_enabled" to 0 first, then click on them. It *shouldn't* crash after you enable it again during the same session, though sometimes it will anyway. Again, save often.
  • If you have a non-syntax-related error in your controller script parameters, you'll have to manually troubleshoot the problem and figure out what parameters are missing or incorrect. So double-check that each parameter has the right value.
  • Sometimes if you make major changes to the scripts or add new controller scripts, the textures will no longer swap in the workspace. This usually happens if it looks for a file that's not there (usually caused by an incorrect parameter), and almost always during the first time you set up the scene for controller scripts. To avoid frustration, once you're sure that the parameters are correct and you've set up the scene as described in the steps above, save the project and restart Anim8or. Then try moving through the frames to see if it works.
  • If you can't get it to work no matter what, look through the two provided .an8 examples for reference and/or post in this topic and attach the .an8 file and associated textures (put it all in one .zip file). If you don't want to have your project available to the public, PM me and we can work it out
  • Only tested to work with Anim8or development release 1210. I recommend using this version or higher
  • Report bugs, questions, or comments by posting in this topic

Video Tutorial

Anim8or v0.98 Discussion Forum / Various scene/controller related issues
« on: January 16, 2016, 12:14:08 pm »
Whenever I start a project, I always come across a bunch of bugs and forget to report them, especially when related to scripting. Here are some issues I've come across today:

  • In the scene editor, when a controller is made and set to be an expression, there becomes no way to edit the controller afterwards. Double-clicking it on the timeline has no effect.
  • GetAttributeFloat/etc can only use constant strings for their parameters. Being able to use string variables would allow for more flexibility, such as allowing easier user-defined configuration of shared controller scripts.
  • There are no Int controllers, but instead just a Boolean controller. There is no GetAttributeBoolean function for controllers. GetAttributeInt works on boolean controllers. This is just messy.
  • No way to set/get scene attributes via script that I know of
  • If a controller script defines a texture filename using SetFileName(), when rendering as a movie it only looks for the texture file in the texture directory that's set in the configuration, rather than locally. If it's not found, it seems to just use what's in memory. Or something like that, it's bizarre.
  • Speaking of, Anim8or seems to infinitely loop the controller script if SetFileName() is used and the Anim8or project was just opened and the user tries opening the element containing the controller on the timeline. However if the user instead disables the SetFileName() function first, then opens the element on the timeline, then enables the function, it doesn't infinitely loop thereafter. This applies only to the first time the element is clicked on (expanded or double-clicked on the timeline).
  • The in-built script viewer is horribly primitive. You can't even ctrl+a to select all the text and there's only one level of undo, and it doesn't remember window resizing. It's very unpleasurable trying to do even moderate scripting using it.

General Anim8or Forum / An8Helper
« on: January 11, 2016, 05:14:05 am »
Here's a small tool that enables fullscreen and menu bar auto-hiding.

  • Press F11 to enter fullscreen when in Anim8or
  • Press Shift+F11 to toggle the auto-hiding of the menu bar
  • A tray icon appears in the tray area of your windows task bar. Right-click for options

This isn't meant to be a big supplementary app for Anim8or, just trying out a full screen effect. It doesn't modify the Anim8or code, but rather modifies parameters on the Windows side of things. Use at your own risk.

Anim8or Challenges / Skertch #2 -- [ Rig and Pose A Mannequin ]
« on: June 26, 2015, 01:33:26 pm »
[ Rig and Pose A Mannequin ]

The next stage in a mannequin's evolution

Welcome to the second Skertch. A Skertch is a mini challenge. A mini challenge involves tasks that are fairly simple, easy to do for individuals. However, these Skertches can lead to more than just a simple trivial practice in CG. Keep that in mind!

Skertch #2 -- [ Rig and Pose A Mannequin ]
Rig and pose a 3D Mannequin. A Mannequin, in animation, is a body whose parts are separated at their joints and animated without mesh deformations. That is to say, they aren't skinned (in Anim8or terms), and instead the individual parts are assigned to the individual bones in the underlying rig. The purpose is to focus on form and gesture through actions in animation, enabling the user to strengthen their foundations and conceptualize ideas.

In the previous Skertch, the objective was to model a mannequin. As you might have guessed already, the next step is to rig it. You may use any of the posted mannequins in the previous Skertch. If you want to use your own that you made in the previous Skertch, you may do so.

  • Rig the model in the Figure Editor
  • You may use either skinning or individual bone assignments (see Notes below)
  • Pose (do not animate!) the figure in the Sequence Editor or Scene Editor, and then render the single frame in the Scene Editor using a simple but nice scene setup with lighting, shadows, and antialiasing. You may use simple primitives (cubes, spheres, cones, cylinders, pyramids) if you want to pose it interacting with objects. Do not make detailed scene props.
  • Post the .an8 file and the rendered image as attachments in this topic

You may either skin the mannequin or assign each part of the mannequin to its corresponding bone. Methods to do so are described here. Refer to the manual or forum and/or experiment if you do not know how to perform some of these actions.

Skinning: Even if you go the Skinning route, you are not allowed to have any vertices influenced by more than one bone. That is to say, a single component of the mannequin must be influenced entirely by a single bone and no other bones. Note that a bone may have more than one mannequin component, if it makes sense to do so. To perform this kind of skinning,
  • Add the object with all of the mannequin's components to a bone in the figure.
  • Create a full skeleton for the mannequin, with each bone being placed at its corresponding mannequin component. Create this skeleton with animation in mind--what's the best way to rig it so that it can handle any animation requirement? You may need to have supplementary bones to aid in various motions later.
  • You may set bone rotation limits, though I recommend having no limits
  • Click on the Multi-bone Skin tool <S> and click on the object.
  • Hit No (Painted Weights) in the resulting popup dialog.
  • Go to Build->Weight Brush... and input a weight of 1
  • Right-click on a bone to activate it in order to paint its influences
  • Left-click and drag over the vertices of the mannequin part that corresponds to that bone until those vertices are painted 100% the same color of the activated bone.
  • Repeat steps 7 & 8 for each mannequin part, making sure that each mannequin part is influenced by only one bone.
  • It may be useful to hide parts in the object editor while painting other parts in the Figure editor, so that you can avoid inadvertently painting parts you don't want to paint

Individual Bone Assigments: This is a more straightforward approach that is applicable for imitating real-life mannequins. but is more tedious and not effective for organic characters. To do this,
  • Make a new object for each mannequin part
  • In the original mannequin object, copy each part to its corresponding object (I recommend keeping the original mannequin intact)
  • In the figure editor, make a bone and add the original mannequin object to it.
  • Create a full skeleton for the mannequin, with each bone being placed at its corresponding mannequin component. Create this skeleton with animation in mind--what's the best way to rig it so that it can handle any animation requirement? You may need to have supplementary bones to aid in various motions later.
  • You may set bone rotation limits, though I recommend having no limits
  • Now select each individual bone and add its corresponding object to it, positioning and rotating it until it overlaps the original's precisely
  • When finished, remove the original mannequin object from the figure

Add the Figure to a Scene. If you want its pose to interact with other basic primitives, it'll probably be easier to pose it directly within the Scene Editor. Otherwise you can pose it in the Sequence Editor and then add the Sequence to the Figure within the Scene Editor.

Next add any primitives, lights with shadow parameters, and enable antialiasing. Render the image.

Post the image and attach the .an8 file and any associated files in the same post. You're finished with this stage! Do a good job rigging, there are at least 3 more challenges that'll use this rig in the future!

Anim8or Challenges / Skertch #1 -- [ Model A Mannequin ]
« on: June 05, 2015, 05:17:19 pm »
[ Model A Mannequin ]

By itself, a powerless puppet

Welcome to the first Skertch. A Skertch is a mini challenge. A mini challenge involves tasks that are fairly simple, easy to do for individuals. However, these Skertches can lead to more than just a simple trivial practice in CG. Keep that in mind!

Skertch #1 -- [ Model A Mannequin ]
Model a 3D Mannequin. A Mannequin, in animation, is a body whose parts are separated at their joints and animated without mesh deformations. That is to say, they aren't skinned (in Anim8or terms), and instead the individual parts are assigned to the individual bones in the underlying rig. The purpose is to focus on form and gesture through actions in animation, enabling the user to strengthen their foundations and conceptualize ideas.

  • Must be modeled in Anim8or
  • Each joint must be a separate mesh Shape. You may include balls at the start/end of a joint for aesthetic purposes
  • Do not add facial features or anything other than generic shapes that approximate the shape of that joint.
  • No textures necessary
  • It does not have to be a human
  • Leave it standing in a standard relaxed natural symmetrical pose
  • Do not rig or animate the mannequin. Leave it all in a single Object

Anim8or Terminology
  • Object: An Object is an element that contains visual 3D geometric sub-elements called Shapes. The Object Editor allows the user to create an Object and then create the shapes within that object. The Object may be further used in Figures (and thus, Sequences), or directly within the Scene Editor.
  • Shapes: These are the sub-elements in an Object. They can be a standard 3D mesh, a subdivision mesh, a parametric shape (such as cubes, spheres, cylinders, or custom Shapes from scripts), or splines. They can be individually selected in the Object Editor and edited or manipulated. They can not be directly accessed outside of the Object Editor.

Post a simple render and attach the .an8 file and any associated files in the same post!

I've been thinking about this for a while.

Since I imagine the rendering system will be focused on at some point in the near-ish future, I was thinking it'd be a good time to jump on the Physically-Based Rendering bandwagon. Though honestly, it'd be nice if instead the animation and scene toolsets were ramped up and 3rd-party rendering support was implemented instead (such as RIB output for Renderman, 3Delight, etc rendering---PBR may still be necessary).

Ongoing Anim8or Development / Topo Tool
« on: February 06, 2015, 04:16:29 pm »
The topo knife is my primary method of detailing when doing polygonal modeling. Basically it only cuts the edges/faces of faces shared by the starting point/edge, with no chance whatsoever of unintentionally cutting what you don't intend to cut (such as stuff underneath). It allows for fast, precise placement of edges.

I uploaded a youtube vid of the XSI version of the tool a while back. Its delete tool also shows what I believe is the p/e dissolve feature that you requested earlier.


I also show its usage a lot later on in my minotaur making-of video.


General Anim8or Forum / Recruiting for
« on: January 19, 2015, 12:29:21 am »
Hey folks,

I'm looking for some content creators for the website I'm working on, located at (currently under development). This site will include its own user manual/help system, a scripts repository, tutorials, and models. I also have an Anim8or UI overlay in the works that integrates An8hub's help system into Anim8or, providing help with just a click (and possibly some sort of script manager/interface).

Content creators will help author articles for the help system, properly document scripts, create and transfer tutorials to be hosted within An8hub, keep content updated, provide feedback to the site, etc.

If you:
  • Have spectacular knowledge in one or more areas related to Anim8or
  • Can write and speak English well
  • Want to give something to the community
Please reply here or send me a message. The site will be free (no ads), so no compensation will be provided, but you will be credited for your contributions.

Hope you're interested!


When disabled, does not turn on backface culling.

Anim8or Challenges / Challenge #33: Parametric Shape
« on: November 03, 2014, 03:52:23 pm »
ASL Snippet
  1. /* ------------ [ Challenge #33: Parametric Shape ------------ */

What this is...
This is a ASL scripting challenge! Consider this your opportunity to learn how to script for Anim8or! This is not a competition! Your goal is to write a parametric shape script that hasn't already been written before, and post in this topic whenever you have issues, questions, or helpful suggestions to others' scripts as they work on it!


  • No Prefabs: You cannot only create a 3D mesh and use the Mesh2A8s or Llyr Carter's cr8 plugin to automatically convert it to a parametric shape. You may however start with one of those and then program in some parameters or otherwise perform significant adjustments/additions via code.

Getting Started
Think of a shape that you think would be fun or useful to have in your arsenal, that hasn't already been made before. Announce your idea and if you like, any thoughts, and then have at it! Post your updates in this topic, including the script(s) as you work on it, to let others test it and provide feedback. If you stumble on a problem, feel free to post it here and get some pointers from other members!

ASL Scripts / [ TUTORIAL ] [ INTERMEDIATE ] N-Gon Parametric Shape
« on: October 31, 2014, 10:28:48 pm »
N-Gon Parametric Shape

Good day budding ASL gurus. Today we'll learn how to make a parametric shape plugin! This tutorial assumes you've already completed the Hello World! tutorial, so if you haven't done it yet and have never scripted before, you should complete that tutorial first.

What is a Parametric Shape?
In Anim8or, a parametric shape is a 3D mesh whose form and structure changes based on the parameters set by the user. This could be as simple as scaling a pre-made mesh or as complex as a generating a planet! There are a lot of awesome things that someone with a little scripting know-how can accomplish.

In ASL, parametric shapes are made much like any other script. You have your header with any comments, the directive(s), the variable declarations, and then the code to create the shape.

Fleshing out the framework
We'll be creating an N-Gon, much like Anim8or's native N-Gon shape, except already filled in as a mesh with UV coordinates.

So let's create ourselves a quick framework for parametric shapes so that we can come in afterwards and 'fill in the blanks'.  Type this code into a new file and save the file as 'N-Gon.a8s'

Go ahead and change the header with information pertaining to you and the script. Change "Parametric Shape Plugin" to the name of the shape  ("N-Gon Shape Plugin", perhaps). The author is you, and the rest is optional, dependent on what type of script it is and how much you want to put into it.

#Plugin Directive
Like with any script, the first command must be the directive telling Anim8or what the script is. For plugins, this is the #plugin("<editor>", "<type>", "<name>") directive. Go ahead and change the name to something like "N-Gon".

ASL Snippet
  1. #plugin("object", "mesh", "N-Gon");

Parameter Directives
Following that, we have parameters! These are the input fields that show up when you double-click the shape. The #parameter directives allow you to define the parameters of the parameters (hah).

For example,

ASL Snippet
  1. #parameter("<name>", <type>, <starting value>, <floor value>, <ceiling value>, <optional params>);
  2. #parameter("Scale", float, 1, 0.01, 10000, scale);

The label to the left of the input field will be titled "Scale", it'll be a float value (decimal number), starting with the number 1, and can range from 0.001 to 10000. Additionally, the Uniform Scale tool increases/decreases this value when it's used on the shape.

#Return Directive
The #return directive contains the shape that we're working on. This must be globally declared (see below the #button directive). If you want to make it more context-specific, you can change the variable from $S to something like $nGonShape or something. Just remember that you have to use this variable everywhere instead, and to change the global variable declaration. I tend to use very short variable names for those variables that will be referenced *a lot* in the script, possibly hundreds of times.

#button Directive
This maps out what the button looks like.

ASL Snippet
  1. #button(<width>, <height>, <number of colors>, <data>);

If you're using Kubajzz's ASL Editor, you can flesh this out using its built-in button editor. It's a little complicated otherwise, and outside the scope of this tutorial.

Global Variables
Alright, variables! In a lot of programming languages, there's something called variable scope. When you declare variables outside of any functions (we cover functions after this) at the beginning, it becomes accessible to all the functions. Such variables are called global variables, since they can be accessed and/or changed everywhere in the script. However, if you declare the variable inside a function, it can only be accessed and/or changed from within that function. Such variables are called local variables.

Because the #return directive required it, we declared the $S shape data type here. And in case we needed to access $output and $obj from within any custom functions, they were declared globally as well.

In the "Hello World!" tutorial, the script didn't have fancy functions. ASL is (currently) a procedural programming language. This means all the commands are interpreted from top to bottom, and that's how you program it. Functions add a little modularity to it, allowing you to program a block of code that can be called at any point in the script, for as many times as needed, according to parameters that you define.

In Anim8or, a function is structured like so:

ASL Snippet
  1. <type> $<name> (<parameters>){}
  3. int $RoundDown (float $a)
  4. {
  5. return $a;
  6. }

<type> is the type of data that'll be returned when you use the function in code. The type can be nearly anything, such as int, float, point2, point3, string, float4x4. For $RoundDown, int is the type. <name> needs to be structured the same as variables, with a dollar sign preceding it. It's conventional to make function names as uppercase CamelCase. That is, the beginning of every word, including the first one, is uppercase, whereas everything else is undercase. With variables, it's lowercase CamelCase, where the first word's first letter is lowercase and every subsequent word's first letter is uppercase.

The parameters are basically local variables that are created on the spot, as copies of whatever data that is input. For example , if $RoundDown(1.333); was used, $a is a variable that holds the value 1.333 within that function. So in the following example,

ASL Snippet
  1. float $plusOnePointOne (float $a)
  2. {
  3. $a = $a + 1.1;
  4. return $a;
  5. }

$a is a local variable that can be accessed anywhere within that function. So if $plusOnePointOne(1.0) was used, $a holds the value of 1.0 (a float), and in the function $a gets re-assigned as the old value of $a (that is, 1.0), plus 1.1. 1.1 + 1.0 = 2.1, which would be the result.

Notice the "return $a;" line. All functions (except those with a "void" type) require a return command that returns a value of the same type as that function. That's the point of declaring the type of the function in the first place! It can be a variable of the same type as the function, or it can be a value by itself that is of the same type. For example, "return 1.5;" would work instead of "return $a"...except that every time $plusOnePointOne() is called, it'll give the value of 1.5 regardless of the parameters used.

The $main() Function
Now, look further down in the template and find the $main() function. This is where the meat of the script needs to reside. Note the "void" data type. This means that this function doesn't return anything--it only performs actions on data that is already there (or locally created). You can create your own void-type functions to manipulate global data if need be, but the $main() function must be of the type void.

Scripts can run without a $main() function. As mentioned before, it'll just interpret the script procedurally from top to bottom. However, if you decide that you need functions, you must have a $main() function. Additionally, you can only have directives, custom functions, and globally declared variables outside of the $main() function. You can't have a command, (such as $output.print("Print Me!");) outside and roaming alone.

It should go without saying, but the $main function is what gets run when the script is executed. All other functions get compiled, but unless it's called from the $main function, it will never get used. The same goes for global variables.

Assigning Parameters to Variables
ASL has a specific function for pulling info from the parameters you specified in the #parameter directive. It's simply:

ASL Snippet
  1. parameter("<name>");

The name must be the exact same as the name in the #parameter directive. Also, the type of the variable must be exactly the same as the the type indicated in the directive, or else you'll come across errors. Note, however, that you can access the value without assigning it, just by plugging in parameter("<name>"), anywhere a normal variable or value would go. Generally it's easier to just assign it to a variable at the start and use that variable where needed.

Another note: You cannot directly change parameters via code, they can only be read from what the user input.

Opening and Closing Shapes
If you wish to edit and add onto or subtract from shapes, you have to open them first. And then when you're done, close them! So make sure you're using .Open() before you try editing a shape, and .Close() before the script ends. Simple right?

Creating the N-Gon Shape
Before you can code a parametric shape, you need to have some understanding of how to go about programming the logic of it.

What is an N-Gon?
An N-Gon is really just a single polygon with multiple points spread evenly in a circular fashion around its origin. Basically, a shape with N amount of sides. Got 4 sides? That's a square. Got 8 sides? An Octagon. Got 100 sides? Well, might as well call it a circle.

A bit of math is usually required to figure out where each point goes on the circle. If you have any experience with trigonometry, you'll know that sine and cosine are the keys to this riddle. Don't know trig? Well, here's a quick explanation (not really an explanation, just a way for you to remember what sin and cosine achieve).

What cosine and sine do is give the X and Y coordinates of a circle when you specify the angle (assume the circle starts on the positive X-axis, and the radius is 1.0). You just have to remember that cosine = X-Coordinates, sine = Y-Coordinates. You can practice with a calculator and the circle image above. Use sine and cosine on any degrees you want, and plot it on the grid above. You'll find it'll always rest on the circle!

Anim8or's sin() and cos() functions deal in radians. There are PI (3.14) radians in 180 degrees. So 2*PI radians in 360 degrees. In our code, we're going to be manipulating points based on fractions of a circle (for example, if we want 5 sides, a point will be placed every 1/5 of the circle). So when we figure out what fraction of the circle we need, we just multiply that fraction by 2*PI.

How are shapes made?
When you think about creating a parametric shape via code, you should be thinking about these things:
  • What math/formulas/algorithms/patterns do I need to plot out the points in 3D space?
  • How do I connect these points together to make faces?
  • How do I manage the UV coordinates?
  • How do I tie in the parameters?
  • Materials, textures, etc?

We'll be doing the first four of those items in this tutorial.

Time To Code!
Plotting points with math
Time to start coding! Generally, when creating a parametric shape, you plot out the points using whatever formulas or patterns you figured out, into 3D space. You do this using the point3 data type. A "point3" variable holds an x, y, and z float value (it's also known as a vector).

So in the $main() function, we need to declare a local point3 variable. In a new line under the float variable declarations, add this:

ASL Snippet
  1. point3 $p[0];

Woah! It's not just a variable, it's an array! If a variable is declared with a [number] after it, such as in the line above, that means it's an array. An array is basically a variable that holds many variables of the same type inside it, accessed by the number specified. Kind of like if you went to a library and needed a book off the shelf, you'd find it by using the catalog number it's sorted by. We call this number the index, and indexes in Anim8or start on 0 instead of 1.

When we declare an array, we must also set the array size. In some programming languages, it's required to allocate the entire size of an array first. Fortunately for us, Anim8or allows us to add or subtract from an array whenever we want. In the line above, we set the size to zero (empty), since we'll be adding to it later. If we wanted to start it with 25 null elements, we'd write "point3 $p[25]".

Let's go ahead and create the number-of-sides variable, since we'll be playing with that as well. I'm calling it "$numSides". It's an int(eger) type, since we can only deal with whole numbers when describing the number of sides of a shape. We'll also need an index variable for code later, so add $i to the int declarations. Go ahead and add $math to the float variables as well. Your local variables should look something like:

ASL Snippet
  1. /* Local Variables */
  2. float $s, $xs, $ys, $zs, $math;
  3. int $numSides, $i;
  4. point3 $p[0];

Since we want the user to be able to input the number of sides, let's start being creative. The N-Gon will exist on the X and Y plane, meaning that the Z-axis is going to be totally ignored. This means we can swap the "Z Scale" parameter for the number of sides instead.

Go back to the top of the script, and change this line:

ASL Snippet
  1. #parameter("Z Scale", float, 1, 0.01, 10000, scale_z);

to this:

ASL Snippet
  1. #parameter("Number of Sides", float, 4, 3, 250, scale_z);

What we just did replace the "Z Scale" parameter with one for the number of sides. It's a float value (scale_z only works with float types), starting with four sides, with a minimum of three sides and a max of 250 (250 is an internal limit in Anim8or for the number of sides a face can have -- See this post for a method to bypass this limit). It's going to seem a little weird since this means you can set a decimal number of sides, such as 4.37, but the decimal part will be ignored in the code. You don't have to make this into a scalable parameter and instead make it an int-type parameter, but it's fun to be able to right-click and drag to increase/decrease the number of sides ;)

Now go back in the $main() function and replace this line:

ASL Snippet
  1. $zs = parameter("Z Scale");


ASL Snippet
  1. $numSides = parameter("Number of Sides");

What this does is read the float value of the "Number of Sides" parameter, and save it as an integer to the $numSides integer variable (it rounds it down, lopping off the decimal portion).

You can delete the ", $zs" out of the local variable declarations since we no longer need it.

Alright, we're ready to start plotting those points. Go down to the area where the main shape creation code will go, after "$S.Open();". Add the following lines:
ASL Snippet
  1. /* Main shape creation code goes here */
  2. for $i = 0 to $numSides - 1 do
  3. {
  5. }

This is called a "for" loop. It's a way to repeat the same code over and over until whenever it's told to stop. It increments the initial variable (in our case, $i) every time the loop happens. So the above statement is saying "$i starts at 0. Execute the following loop until $i equals $numSides minus 1".

In any shape, the number of sides is equal to its number of points. Hence we're plotting the same number of points as the number of sides. We're starting at 0 instead of 1 to make it simpler for later code, which is why we have to do the number of sides minus 1.

Now, add this line of code inside the for loop:

ASL Snippet
  1. $p.push((0, 0, 0));

"$p" is the array that holds the points. ".push()" is a function that adds a new element to the array, containing whatever data is within the parenthesis. In our case, it's (0, 0, 0), which is the x, y, and z coordinates, in that order.

Well, (0, 0, 0) is the origin...we want each point at their rightful place on the circle! So it's time for that cosine and sine math. As a bit of an optimization, instead of doing all the math inside the for loop, let's do as much of it before the for loop as possible. Replace that line with:

ASL Snippet
  1. $p.push((cos($i*$math), sin($i*$math), 0));

Before the for loop, after the $S.Open(); line, add this line:

ASL Snippet
  1. $math = 2.0*PI/$numSides;

What we're doing is pre-computing as much of it as possible so that it doesn't have to compute it over and over every time the for loop iterates. It's not necessarily important considering how fast computers these days compute things, but it's good practice especially if you have code that needs to iterate thousands upon thousands of times.

Remember the whole fractions of circles bit that I mentioned in the trig part of this tutorial? This is it. It's not very obvious, right? Well, for the purpose of explanation, if you substituted "$math" in the for loop with "2.0*PI/$numSides", and moved the operands around, you'd have something like this (don't change to this in the code):

ASL Snippet
  1. $p.push((cos(($i/$numSides)*2*PI), sin(($i/$numSides)*2*PI), 0));

For X, we have cos(($i/$numSides)*2*PI). ($i/$numSides) is the fraction, and 2*PI is the circle. Multiplied together, you get the angle in radians. Cosine finds the X coordinates based on this angle. Sine finds the Y coordinates. It's all coming together, right?

Let's think about it just to make sure. Let's say we have four sides that we want to generate, so $numSides would have the value of 4. In the first loop, $i equals 0. So $i/$numSides = 0/4 = 0. In the second loop, $i equals 1, so $i/$numSides = 1/4 of the circle. The third loop $i equals 2 => 2/4 = 1/2, and the fourth loop $i equals 3 => 3/4. The for loop ends at $numsides = 3, since $numSides - 1 = 4 - 1 = 3. We just mapped out four points at each quarter of the circle.

Pages: [1] 2 3 ... 6