Models for Animal Evolution
Click here to view the GitHub repository for this project.
Click here to get the current Unity project build for Windows. Note that there have been major updates since the expo, fixing a major bug and adding a randomizer slider that makes animals start with modified statistics from the beginning.
Click here to view a demonstration video of the project.
Click here to view the poster that was made for this project for a contest.
Link to the original project: https://github.com/K-WS/Algorithmics_Evolution
The original project was created during the Algorithmics (MTAT.03.238) course. It is a Unity application, where animals compete with each other to collect food in order to survive.
The user can initially set the statistics that all animals start with, as well as the amount of animals and food placed into the arena.
The animals select and chase after food based on the nearest neighbor algorithm, where under normal circumstances, they pick the food closest to them, that has not already been occupied by another animal.
Animals can either die due to not getting enough food, get just enough to survive to the next round, or get enough food to reproduce. When reproducing, another copy of the animal is created, and both of them get mutations, which slightly alter their statistics. This can be visually seen based on their current color combination:
- Red indicates how fast they move every step.
- Green indicates their size, which can also be directly compared since... it's their size. This also gives animals an exception condition, where they can pick food that is already occupied by another animal, if they are large enough. When done so, the smaller animal is "scared" away to find another piece of food, while the larger animal gets the old food.
- Blue indicates minimum food quality preference. Since food is spawned in varying qualities, better ones giving more points for reproduction, a higher food preference means ignoring chasing lower quality food altogether, unless there is no food of their preferred quality left.
Since having higher stats is generally better, all animals also have an energy meter that is consumed every step. The calculation for this is speed2 * size3 . Note that quality isn't part of it due to higher values being both potentially useful and detrimental for the animal.
There is also a bias variable. If animals are able to reproduce again with their new stats, they are biased to mutate more towards that direction, as these are perceived as beneficial stats. Should this happen 5 times in a row, they will get stuck in evolving only in that direction (until failing to reproduce several times), causing overspecialization and probable extinction. Otherwise simply surviving halves their current bias, to give a better chance at trying different mutations and seeing if it gives them an edge.
CG Project Idea
The idea for this course is to expand on the original project by giving the option to use more detailed models that are animated. I decided that a dinosaur model of sorts would be suitable for this, with an example on what it could look like on the right.
Their skin color would be the same as how the original animal orbs are colored, while additional stripes could be added which could also use some form of unique coloring.
For animation, the legs should definitely be moving as part of the animation, definitely at least 1 movement animation, potentially 2 or more animations that are used depending on what speed the dinosaur is moving in. Also depending on the complexity, another optional thing to animate could be their mouth and arms.
Used technologies will be Unity again, as the environment where the models are going to be used in, as well as Blender, a free modelling software that I have some familiarity with from earlier courses, but need to relearn due to major updates.
The main difficulty is definitely going to be the creation and animation of the model. While I have some experience in creating models, I've yet to fully animate one in such a way that it would be usable in a project.
- Milestone 1
- Refamiliarization with the Blender modelling tool and initially creating a basic model of the dinosaur.
- Milestone 2
- Finalizing all the details of the dinosaur model.
- Milestone 3
- Building the animation skeleton within the dinosaur model
- Animating in Blender? (unsure if this is done here or in Unity)
- Milestone 4
- Buffer milestone, depending on how much time it took to actually create the model and/or skeleton, this milestone is either used to ensure that the previous milestones would get completed properly, or that the following Milestones could be started earlier. Regardless, there are several optional ideas that could be implemented and are listed here.
- Skeleton and animation for the hands
- Skeleton and animation for the mouth.
- Multiple different animations for movement speeds.
- Optional horns/scales/appendages that could grow out of the dinosaur in varying lengths, depending on specific stats.
- Instead of simply standing after finishing collecting food, this could also be either animated, or they could be in a resting position (This would require a much more robust animation skeleton).
- Alternatively, changing animation speed in Unity
- Milestone 5
- Adding an additional option in the original project to either use the orb animal models or the new dinosaur models.
- Getting the dinosaur models inside the Unity project. At the very least they should be visible in their standing position, and all the effects for the original orb models also affect the dinosaur models (skin color).
- Milestone 6
- Full finalization of the project, with the dinosaurs animations working.
- Refamiliarization with the Blender modelling tool and initially creating a basic model of the dinosaur. (7h)
- Actual time - 8h
The original plan was to finish a basic model by the end of this milestone, but progress went much faster than expected and now the model can be considered nearly finished. There are some details that still need to be tweaked here and there, but otherwise it's looking really close to what my intended vision of the model was.
This means that starting from the next milestone, much less time will be spent to finish the model, while also being able to start rigging it up earlier as well.
Some details that still need to be finished - Figuring out how to extrude the top set of teeth the same way as the bottom ones, extruding the eye, maybe slightly widening the head (4th image). After that, it's pretty much either bevelling to make some parts smoother, or rigging the model, creating loopcuts wherever needed to make sure that the animation movement is smooth.
- Finish modelling the dinosaur (3.5h)
- Figure out how to give the top set of teeth a similar effect as the bottom set.
- Depending on the situation, if I'm planning on adding mouth movement to the animation, figure out how to separate the teeth from each other, as well as adding some sort of mouth so the empty insides can't be seen when the mouth is open.
- Extrude out the eye
- Smoothen the model
- Ensure that there aren't any faces that are supposed to move with more than 4 vertices
- Start rigging the dinousaur (3.5h)
- Giving a skeleton for the dinosaur
- Making sure there aren't any weird movements with the faces while limbs are being moved.
- Total actual time taken - ~9h
Blender has a built-in rigify function that allows complicated animations at the click of a button. However, in order for it to actually function, really specific rules would have to be followed for it to properly generate the model.
Despite that, there are built-in models via an add-on available for various figures. Unfortunately, there wasn't a particular way to effectively reposition any of the premade models in such a way that it would make sense for a dinosaur, so I had to do the rigging and inverse kinematic effects separately.
There was an initial hurdle in understanding how building bones correctly works, and how to follow the naming convention, it went relatively smoothly after that. The body bones could easily be positioned when viewing the model horizontally/vertically, while the arms and legs only needed one half completed, give inverse kinematic rigging effects to them, and could then be symmetrically copied to the other side. After that, the only thing left was to parent the bones and the model together and it would start moving immediately in pose mode.
The dinosaur also has a proper mouth that blocks seeing the insides of the dinosaur, which can be easily be shown by moving the head bones apart from each other.
There are some weird effects occuring with the model though. For some reason, part of the mouth moves very slightly when the arm is moved around and the top half of the mouth slightly warps downwards when the bottom part is moved too much. During movement, these would probably not be noticeable, but I'm considering figuring out why this is happening and if possible, fix it.
Another issue is that the root node is the tail, for some reason, meaning I can't actually make some kind of tail wiggle animation, which should probably be addressed.
- Fix some of the issues that the inverse kinematic bones have? (2h)
- Moving the hand slightly moves the mouth
- Moving the bottom half of the mouth moves part of the upper half slightly
- Inverse Kinematic effect on toes (for easier animation)
- Get the root bone to be the middle of the body, not the tail.
- Create a moving animation (5h)
- Planning on creating a walking animation
- If it goes faster than expected, start creating a running animation as well
- Actual time taken - 9h
Weight Paint / IK
A lot more time than intended went into fixing all issues with the model animation, which left much less time into learning more about animations and creating the walk cycle.
What ended up happening was that I managed to fix the warping effects of certain body parts when other limbs were moved around (weight painting), but when checking the inverse kinematic effect for toes, I had to redo the legs. This caused the weights and bone names to get messed up, making me have to reweigh the model with the new skeleton. This meant that I had to redo the first part again and had to address any new issues caused by the redone leg bones.
For the new legs, it now follows the generic structure on how a leg is formed, with toes being separately connected instead. An additional IK limb is placed at the toe region to be able to rotate the leg such that the toe doesn't rotate simultaneously. This gives a lot more control, as now I can either rotate the entire foot, or rotate it without rotating the toes.
Due to how far apart all 3 toes are from each other, only the middle toe actually moves around during rotation.
Since a lot of time was spent fixing the bones and weight paint, I only managed to do the leg movement part of the walking animation. Despite that, some errors aside, it looks quite good (in my opinion at least). One thing that I would do is slightly reduce the weight paint so that it doesn't reach the arms, but other than that, it has a more comical, lighter type of movement that makes it appear more dynamic.
For the next milestone, I intend to slightly modify the weight paint, give arms, mouth, tail movement for the walk animation. This should be doable much faster now that I have a better understanding on how animations work, so the main issue is figuring out how to make it look good.
After that, I'll be creating the running animation, which also should take a bit faster. Since there is potentially a surplus of time left after that, one of the optional tasks from the original project plan could be implemented, but what it could be is something I want to discuss during the milestone presentation. Main ideas that interest me is spikes growing out of the dinosaur's back, implementing the unique coloration that the original illustration had (the orange spots), or a tail that can grow longer.
- Finish the walking animation (1.5h)
- Weight paint
- Mouth, arms, tail
- Running animation (2.5h)
- Potential surplus time (3h)
- Tail scaling (multiple bones)?
- multi-material (check in Unity)
- Actual time... 8h?
This milestone has been a complete mess.
The only part of this milestone that can be considered properly finished. The dinosaur model now has walking and running animations. Getting both animations completely finished took longer than expected, but I still had extra time at the end.
Importing to Unity
The next part that I wanted to do was check how the model imports into Unity. I found out that you can just copy a .blend file directly into a Unity project, which I did. However, in that case, the animations weren't imported with it. So I decided to try making an FBX model, which did. Both cases had the model at reasonable sizes as well, being easy enough to rescale in case it was needed.
Materials were also already separated into groups, where I could just put Unity materials directly on to them and the correct areas would become colored.
By this point I was satisfied with the result, deleted the models from the project and continued on.
Extra Textures and Spikes
As I stated during the previous milestone presentation, adding extra textures was simple enough. I could just use the knife tool to add a few cuts and recolor some areas with a new material group, which would then remain in Unity.
After I had done this, I started to work on the spikes that could rotate out of the model. This is where everything started to go wrong.
First off, for some reason, whenever I'm making a new mesh, it doesn't display properly. The dinosaur model is taking priority for some reason, and any model, even in front of it, becomes invisible. This made it really difficult to actually add spikes. I couldn't figure out how to fix this in Blender and couldn't find any answers either.
Then, any time I added spikes, it added garbage animation data that I couldn't delete at all. This also happened when I was creating the original model, but at that point I could just rename them and use them for the actual animations. Now that I have 7-8 empty animations that I can't delete, the animation selection menu has become cluttered.
Finally, something went really wrong with my model during this process. For some reason, the armature started having issues and the spike model had a weirdly positioned origin point, the animations all got displaced and weren't properly aligned to the world point.
I had deleted the spikes and thought that maybe this should be a next milestone thing, but I wanted to try and reimport the model one more time into Unity before that.
The FBX file import is broken. I have no idea what happened, but now every time I export the model in FBX form, it's really tiny in Unity. Not only that, but scaling doesn't appear to help either, it's moving the model instead of making the model larger.
So now I'm stuck with a broken file that doesn't work...
Or at least thats what I would say if I hadn't accidentally created a copy of the file after the running animation was finished. The extra texture is missing on this, but that is easily fixable.
Because of this though, I don't know which way to go with Milestone 5 now. On one hand, I'd still like to do the spikes, but the Blender issue needs to get fixed. On the other hand, I'm thinking that maybe I should take my losses, take the old model, give it the few improvements that I managed to do before and start adding these models inside Unity instead for now.
Oh, and for some reason, I have a bizarre bug in Blender, where depending on the computer window where its positioned, on the 60Hz screen the animation works fine, but on the 144Hz screen, despite the 60 fps cap, it hovers around 70 fps and doesn't look good. Not sure what causes this either.
- Implement the model inside the Unity application.
- Add additional buttons in the Unity application to choose between basic and dinosaur models.
- Get the model properly scaled in and figure out how to access animations.
- Give material dependencies for the model.
- Make sure that the model has a standing pose to go to whenever it runs out of energy or gets enough food.
Fixing Model Normals and Scaling
One of the issues during the process of solving the goals was to fix an issue where some parts of the model were see-through. The issue was that the faces were facing the wrong way during the creation of the model, and their normals needed to be flipped to be pointing outwards (blue color on the image).
As for scaling, all that had to be done was to rescale the bones to be scale 1 for the model itself to properly export as the correct size. However, one additional change was made by moving the world origin point so that it's roughly in the middle of the model, to ensure that when importing it, the rules for its placement would remain the same as with the original orb models.
Additional buttons were added to be able to switch between the simplistic orb models and the new dinosaur models.
Part of the original movement code was fixed so that the models would not rotate based on the height location of the food (basically, that they only rotate and move towards the general location of the food, not the exact point).
Dinosaurs also change color the same way as the orbs, based on their speed, size, quality preference stats.
The animation controller is set up to initially check what each dinosaurs speed is before deciding if they should use walking or running. Whenever they run out of energy, they enter the generic stopped animation, from where they can re-enter the walking/running animation once a new round starts and they are still alive.
There are also separate multiplier variables added for both walking and running to modify the animation speed based on their actual speed, to make sure that they don't appear to be moving faster than the animation should imply.
Although this was mentioned during the beginning of the project, the link to the original project can be found here, which has now been updated:
Milestone 6 (22.05)
This time I reattempted the creation of spikes. Due to the way the model has now been made, they would now have to be a separate model that could be made multiple copies of, and then placed as children for various parts of the model.
Size determines how much the spikes move out of the dinosaur. The larger they are, the more the spikes pop out. 2 spikes were placed on the dinosaurs back, While one was placed on the nose, to give it more of a rhinoceros type look as it becomes larger.
The walking and running animation are now dependant on both the speed and size of the model, not just speed (higher size slows down, higher speed speeds up).
The best way to demonstrate this is by showing a video on the result. The spikes can also be seen coming out of the model as it becomes larger. Video showing animation speed changing based on size.
Dinousaurs now get an initial random color for their pattern, which is used to determine initial "families" and if one would become more dominant.
A bug had reemerged from the old project where a dinousaur can't eat food. This was due to the food being inside the model hitbox and therefore it doesn't get triggered.
It turned out that the limit on how close a dinosaur can get to the food depends on their size, or more specifically, the range limit will always be the middle of the dinosaur compared to the food location. Since the dinosaur grows in size, so does the center of the dinosaur.
To fix this, the old code used to fix the original issue was modified, so that now the distance needed is changed based on size. This also gave an opportunity to optimize the code further to completely remove any OnTriggerEnter function, which has been added in the section of things to potentially do before the final presentation.
What to consider before the final presentation
- Optimize the code further. There is already a distance based measuring helper that could replace OnTriggerEnter on foods so that they don't have to trigger when other dinosaurs touch them.
- Done, has given significant general improvements with slightly larger amounts of dinousaurs.
- Another optimization would be for a Dictionary to hold food in it, not a list.
- Done, More stable after each round has started and can go for sizes that struggled before. Also fixed a bug that was accidentally made with the previous point, which caused all food to give equal amounts of energy.
- From this though, While I don't have time left for this improvement, the next thing to do would be to implement object pooling. This way, every round starts faster and more stable, since objects would no longer get destroyed and recreated, just disabled and reenabled. If that would be done, then eventually, the next bottleneck would be the size scaring tactic that large dinosaurs have.