Part alignments and slider rails

Greetings all, I think it’s time for an update on what’s been happening for the past few weeks!  I got back up and running on a newly built PC after the old one gave up the ghost, and I’ve been working on task management stuff, making various improvements to the game, and fixing bugs.

Trello

During the down time while waiting for parts to arrive for my new PC, I couldn’t make much development progress, so I took the opportunity to get set up on Trello for task tracking.  All of my tasks are on there now, as well as feature requests and suggestions from the GearBlocks community.  Many of the tasks still need fleshing out more and perhaps breaking up into sub-tasks, but it’s a decent start.

image

The great thing about Trello is that it gives people the opportunity to comment and vote on tasks.  Currently it’s set up as invite only, so if you’d like access, email me at: sam@gearblocksgame.com

Part alignments

I’ve been making improvements to how part alignment works, specifically how alignment positions & orientations are defined and processed.

Previously, a part’s alignment grids could be specified from a local origin + width & depth values, saving the need to specify each alignment point individually.  Now, these grids have been extended to optionally have a height value, allowing for alignment “columns” to be more compactly represented (useful for axles for example).

Also, the alignment grid setup and search code has now been refactored to be simpler, easier to debug, and easier to extend.

All this was a prelude to the main change, which was to make part attachments (fixed, rotary bearing, etc.) refer to the alignment grids that they were created from.  An attachment now gets its orientation and allowed attachment types directly from the alignment grid, saving the need to store them separately.  The main reason for doing all this though was to address a problem with linear bearings which I’ll come to in a moment, but having access to the alignment grids this way has other advantages too, for example it allows for retrieving the alignment type when displaying attachment indicators (e.g. surface vs. interior could be shown differently).  This is something I’ll hopefully get to make use of in the future.

As attachments now index into their source alignment grids, I had to change the save format to store these indices.  I’ve implemented code to convert old saved games / constructions upon load so that their attachments reference valid alignment grids.

Sliding distances

When setting up the physics constraint for a linear bearing attachment, a sliding distance and anchor offset need to be calculated.  Previously this was done by simply using the bounds of the part, i.e. its outer dimension along the sliding direction.  However this only works for simple “convex” parts (e.g. blocks and axles), for anything more complex, the sliding distance may need to be less than the size of its bounds.

So to solve this, the sliding distance and offset for a linear bearing attachment is now calculated based on the dimensions of its source alignment grids, which it has access to due to the changes I mentioned earlier.

The slider rail parts are limited to 25 units in length, I don’t want to make them any bigger than this as I think it would be rather unmanageable to build with.  However, it seems reasonable to be able to create effectively longer slider rails by placing them end-to-end, so I made some modifications to allow parts to appear to slide from one rail to another.  To do this, I implemented code in the slider rail part behaviour to find its adjacent neighbours, and then calculate a new total sliding distance and offset for any linear bearing attachments associated with it.

Here’s an example of this in action:-

image

Other stuff

I’ve also been working on some other improvements.  For example, constructions are now spawned frozen and positioned on the ground in front of the player.  Previously one of the parts in the construction would have been selected by the player after spawning, resulting in the construction potentially being oriented weirdly, poking through the ground, player, etc.  This made spawning constructions awkward and confusing, and I think the new way is a lot better.

Player character free flight movement has been modified to have different acceleration and a higher top speed when holding shift.  This helps to quickly navigate larger distances around the map.

All of this, plus various bug fixes will be in the next demo update, which I’m hoping to release very soon!

Revisiting gear physics

Hey everyone, I hope you and your families are hanging in there during this crazy situation we’re all in at the moment.  It seems like the whole world has been turned upside down over the past month or so.  It’s hard to predict what the future will bring, or what the long term impacts will be, but I’ve been trying to stay focused as best I can by working on the game!

At some point soon I need to starting putting together trailer videos and other materials for GearBlocks, and for this I want to build some example creations to show off all the parts in the game.  So a while back I started building a 4WD off-road buggy with differentials, CV joints, suspension and so on, but that’s when I ran into a problem.

Heavy gears and weird physics

It’s an issue that someone pointed out to me quite a long time ago actually.  It’s this: when you have a 4WD vehicle with a long axle connecting the front and rear differentials via gears, at high speed the vehicle wants to rotate in one direction (i.e. steer left or right) much more easily than the other.  Its preferred direction depends on the direction of rotation of the long axle.  This is a very odd and unnatural behaviour, almost like a kind of gyroscopic effect, and is even more noticeable in the air (during a jump for example).  The problem can be reduced slightly by increasing the simulation update rate (and therefore physics accuracy) but this isn’t really practical as it slows performance too much.

It turns out that this weird behaviour is so noticeable because the gears all have really big masses (20kg each).  When you have a gear on each end of a long axle (e.g. running front to rear of a 4WD vehicle), it has a large polar moment of inertia.  I’m not entirely sure why, but this fact, combined with the high RPM of the axle is what seems to be making the problem so bad.  I found that if I give the gears smaller, more appropriate mass values, the unwanted behaviour is significantly reduced.

Why do the gears have such high masses in the first place?  Well, it’s a workaround to prevent the gear teeth from slipping from one physics constraint to the next.  In the physics simulation, if you have two rigidbodies constrained together, generally speaking the more equal their masses, the better that constraint will solve (with less “stretchiness”).  Giving the gears a large mass was a hack to try and balance them with the combined mass of all the parts in the rest of a typical construction.

I’ve always hated this hack, apart from anything else it makes constructions with a lot of gears weigh a huge amount!  So I’ve been working on a way to make the gear constraints more resilient, allowing the gears to have more reasonable masses, while still preventing gears slipping.

Searching for an anchor

Previously, when two gears were engaged, for each gear the closest constraint anchor position to the other gear would be found.  The problem is, on any particular gear each possible anchor position is quite close to its neighbours, making it easy to slip from one to the next if the constraint doesn’t solve very well (i.e. if it “stretches”).  However, I realised there’s a better approach, here’s how it works.

Starting with the simplest case – two gears with an equal number of teeth.  As before, for the first gear in an engaged pair, the closest anchor position to the second gear is found.  Then, taking the index of the first anchor and negating it will give the anchor index for the second gear, as it can be assumed to match only one possible anchor on that second gear, as shown below.

image

By directly mapping the first gear’s anchor index onto the second gear makes it almost impossible for the gears to slip.  The physics constraint would have to stretch so much that the gears rotate one whole revolution opposite to one another, very unlikely to happen!

To make this work with a pair of gears with an unequal number of teeth is a little trickier.  The largest common factor of the two gear’s numbers of teeth has to be considered when mapping the first gear’s anchor index onto the second.  This means that there is no longer only one possible anchor on the second gear, for example here’s a situation with three possibilities (a, b, or c).

image

It means that, of these three possible anchor positions, the closest to the first gear must be found.  However, they’re still far enough apart that slipping from one to the next is highly unlikely.

Finally, I had to account for the relative orientation of two gears when they first become engaged.  So an anchor index offset is calculated at the point of engagement, that is subsequently applied when mapping an anchor index from one gear to another.

Other gears, and pulleys

Once I had this all working for gear wheels, I then applied the same principle to rack and worm gears.  Previously, if for example you crashed a vehicle with rack and pinion steering, it was very common for the rack gear to slip, causing the steering to be offset.  You’d have to freeze and unfreeze the construction to fix it.  Now this annoyance is much less likely to happen!

I also re-implemented the constraint anchor search code for pulleys to work in a similar way to the gears, bringing the same benefits to the pulleys.

Tuning the masses

I’m now in the process of tuning the gear masses.  For stability under high torque loads, I’m finding I still need to give them masses higher than they would naturally have (albeit not as high as before), particularly for the smaller gears.  It takes a lot of testing, but hopefully soon I’ll be able to settle on some reasonable masses for the gears that work well in most situations.

All told, this has been a lot of work (that I wasn’t planning to have to do), but I think the results are well worth it!

Player physics improvements, rendering optimisations

In this update I’ll briefly go over what I worked on last week.  This week so far has been focused on bug fixes and preparing for another demo release which should be coming very soon!

Take a seat

Previously, when a player activated a seat, they would be “locked” into the seat by their transform being re-parented to the seat part’s transform, and their Collider / Rigidbody disabled.

This meant that the player would suddenly seem to have no mass, having no weight exerted on the seat.

So instead, I now keep the player’s physics active, and lock them into the seat using a ConfigurableJoint between the player’s Rigidbody and the seat part’s parent Rigidbody.

This means that the player’s mass now dynamically affects the construction they’re seated in.  Also, by setting up the ConfigurableJoint appropriately it allows for some sprung-damped “give” between the seat and player, as you can see below.

image

It does of course mean however that constructions now have a little more overall mass and a slightly different CoG when players are riding in them, much as in real life.

Highlighting render optimisation

When a part (or a whole construction) is frozen, selected, etc. it is highlighted with a glowing outline.  To achieve this the part’s meshes are drawn in a “mask” render pass that accumulates the outlines of all the highlighted objects.  However, up ‘til now, even parts / constructions that weren’t currently being highlighted would still be drawn in this pass (having no visual effect and not necessary).

So now I’ve modified things so that it no longer draws parts in the highlighting mask render pass unless they are actually currently being highlighted.

I also tweaked the mask render shader to fade the highlighting out over distance, and set the camera far clip plane to cull objects beyond the “fully faded out” distance.

These changes save on draw calls, and give a slight rendering performance improvement when viewing constructions with a large number of parts.

Unity upgrade brings performance gains

Now that I’ve removed the old RakNet networking stuff, I’ve been unblocked from upgrading to later versions of Unity, and so that’s what I’ve been working on over the past couple of weeks.

Unity 2018.4

First I upgraded from 2017.4 to Unity 2018.4, this brought some significant improvements:-

  • PhysX upgraded to 3.4, I found this to be a big performance improvement, especially for constructions with a large number of rigidbodies / constraints.
  • Non allocating collision contacts.  By enabling “Reuse Collision Callbacks”, and using the new Collision.GetContacts() API in OnCollisionEnter / OnCollisionStay, this eliminates GC allocs and improves physics performance too.
  • Graphics jobs no longer marked as “experimental”, so I enabled this, it should take some load off the main render thread.
  • Terrain instanced rendering, fewer draw calls for rendering the terrain mesh.
  • .NET 4.x no longer experimental, so I switched over to this from version 3.5.
  • IL2CPP scripting back-end for standalone builds, compiles to native binary, should improve performance and is more secure than shipping IL assemblies.

Unity 2019.3

Then moving on to 2019.3, which included a PhysX upgrade to version 4.1, this didn’t seem to provide any additional performance gains out of the box, but it does introduce some intriguing possibilities:-

  • New temporal Gauss Seidel solver (see below).
  • Automatic box broad-phase pruning, I tried this and didn’t notice any performance improvement, but I need to do some more tests to be sure.

Temporal solver

This new solver is supposed to improve stability for jointed rigidbodies with large mass ratios.  I was hoping that it would eliminate or at least reduce the need for “fake” masses.  For example, the gears right now all have the same (quite large) mass regardless of their size, to prevent them slipping, and it would be nice to give them real masses instead.

Unfortunately in my experiments this didn’t work out, in fact even leaving the gears with their fake masses, they wouldn’t run smoothly at all.  It was almost as if the constraints between them were now too stiff, so instead of locking them together I tried using a limit with a small distance, to introduce some “backlash” to relax things slightly.  This definitely helped but was still not completely smooth.

Sadly though, there were many other problems too, such as CV joints glitching out like crazy under even small torque loads, and wheels sinking through the ground.  Not to mention spring dampers being way too strong (I guess everything would need re-tuning).

So I decided to leave this for now and stick with the old projected solver.  There is a potential massive performance gain to be had with the temporal solver however, due to its faster convergence.  I found that to achieve the same approximate constraint “stiffness”, it seems to only need the number of solver steps to be scaled linearly with the sim fixed time step, rather than with the square of the time step like the old projected solver.

I think this new solver will be worth revisiting again if I have time at some point in the future.

Performance results

One of you talented folks sent me this awesome snow groomer creation!  It’s quite physics heavy due to the tank tracks (a large number of rigidbodies, constraints, and collision contacts), so I’ve been using it as a test case to do some before and after performance comparisons.

image

I also compared with “Continuous Contact Detection” under the gameplay settings both on and off.  Turning this off disables OnCollisionStay, which makes a big performance difference when there are a large number of collision contacts (the only downside being you get no sliding sound effects).

Here are some results (running on my dev machine at 1920×1080 full-screen) with the snow groomer:-

  • 2017.4 / PhysX 3.3, OnCollisionStay enabled: <10 fps.
  • 2017.4 / PhysX 3.3, OnCollisionStay disabled: <10 to 23 fps.
  • 2019.3 / PhysX 4.1, OnCollisionStay enabled: 14 to 21 fps.
  • 2019.3 / PhysX 4.1, OnCollisionStay disabled: 30 to 40 fps.

Note that there’s a range on these numbers because performance varies depending on how things are moving, how many collisions are happening, etc.

Player physics

Over the past few weeks I fixed a bunch of bugs, and then turned my attention to player physics and movement control.

Problems with using CharacterController

Since the very earliest days of the game’s development I’ve been using a CharacterController for the player along with a “character motor” script (adapted from a Unity sample) to control it using the CharacterController’s Move() function.  The character motor would apply forward / back, strafing, and jumping movement, acceleration due to gravity, and if the player was standing on a moving object it would make them move with it.

This setup worked reasonably well, but the CharacterController doesn’t provide proper interactions with Rigidbodies in the world.  The player is treated as a static immovable object when things collide with them.  The player can’t push objects around, and they can’t be pushed by objects either.  It just looks wrong when for example a vehicle hits the player at high speed and they don’t move at all.

Also, the character motor implementation had a bug where, if the player collided with a Rigidbody, they would occasionally get thrown across to the other side of the map.  Most often this happened when exiting a seat, very annoying!  I suspect this issue was related to the code that moved the player when standing on something, but I’m not 100% sure.

Despite all these problems, I didn’t particularly want to add more work to my plate by throwing out this character motor code and starting again from scratch.  So I tried playing around in the OnControllerColliderHit() message to try and get the player to push stuff around, and in OnCollisionStay() I tried to make the player be pushed by objects that collide with them.  I couldn’t get this to work nicely though, I think it really is necessary for the player to have a Rigidbody to give proper physical interactions, anything else is always going to be a bit of a hack at best.

At this point I realised I needed to ditch the CharacterController and start from scratch after all, using a Rigidbody instead.

A physics based player

So now instead of a CharacterController, the player has a CapsuleCollider and a Rigidbody.  I implemented new code that replicates the original forward / back, strafing, and jumping behaviour, by applying a force to the player’s Rigidbody.  It uses a Physics.SphereCast() to detect contact with the ground and to find the Rigidbody that the player is standing on, if any.  If they are standing on a Rigidbody, its velocity is transferred to the player.  Also, the force used to move the player is applied in the opposite direction to the Rigidbody that they’re standing on, thus obeying Newton’s third law.

To sum up the features and benefits of this new approach:-

  • Correct player collisions with other Rigidbodies.
  • Player can push other Rigidbodies around.
  • Player can be pushed by other Rigidbodies.
  • Player can stand on a moving Rigidbody.
  • Obeys Newton’s third law when player accelerates while standing on a Rigidbody, this results in really cool “conservation of momentum” behaviour.
  • Player falls due to gravity automatically from having a Rigidbody, but even better, the player’s weight now pushes down on the Rigidbody that they’re standing on.
  • Eliminates the old “player thrown across to the other side of the map” bug.
  • Code is simpler and cleaner than the old character motor implementation.

Here are some examples of all this in action:-

image
image
image
image
image
image
image
image

As you can see this provides a level of interaction between the player and the constructions they build that simply wasn’t possible before, so I’m happy I bit the bullet and re-implemented things this way!

However it’s by no means perfect, and there are a few issues / missing features that will need addressing at some point, for example:-

  • I’d like to implement code to handle climbing steps, I think the player needs an extra force to push them up steps, as they tend to get stuck at the moment.
  • I also want to add something to make the player slide off ledges, as right now the player can stand more than half way off a ledge with their feet in the air, which looks weird.
  • The old character motor had code to make the player slide down steep slopes, not especially crucial but it would be good to get this working in the new implementation.

Linker tool, power, and more

Here’s a quick update on what I’ve been working on over the last month or so!

Linker tool

After a long hiatus from working on it, I finally went back and completed the linker tool.  The first attempt at this tool that I did a while back was hard-coded to work with the pulleys, so I had to generalise the implementation to support different link types.  A part can now have one or more link nodes that are associated with its part behaviour(s).  When the linker tool is active these link nodes can be highlighted by the player, which they can then click on and drag to another link node to create a link between them.

These are the different link types that I’ve done, or am planning to do:-

  • Pulley – used to route belt between pulleys, implementation now complete.
  • Power – used to link motors, batteries, solar panels, this is also now done (see “Electric Power” below).
  • Data – allows one part behaviour to query data from another linked part behaviour, an example could be a screen that can be linked to a motor to display its current RPM.
  • Control – allows one part behaviour to control another part behaviour, an simple example being a switch that can be linked to several motors, lights, etc. to turn them on / off together.

In this example you can see some pulley links and a power link being added between a motor and battery:-


As there are now different link types, I’ve made a few tweaks to make it
easier to manipulate them.  The indicators for each link type are
colour coded so that they can easily be distinguished from one another,
and there is now a linker tool UI that allows links of different types
to be shown or hidden.

Electric power

As I mentioned, I’ve now implemented “power” links so that motors, lights, and so on can be linked to batteries.  I implemented code in the motor and light part behaviours to calculate a power value that is then used to discharge energy from the linked battery / batteries.  Also, when braking, a motor will now regenerate energy back into its linked battery / batteries.

The battery part behaviour itself does very little other than tracking the battery’s current state of charge.

I’ve also added solar panels, these have a simple part behaviour that calculates a power value based on the panel’s surface area and its current angle relative to the sun.  This is then used to charge energy into its linked battery / batteries.

It’s fun to play around with this stuff in conjunction with the day / night cycle in the game, using solar panels to charge a battery during the day which then powers your lights at night:-

Knuckle joints

I’ve also just added a new type of hinge connector, what I’m calling a “knuckle joint”, where the parts connect in line with one another like this:-

I made two versions of the knuckle joint connector, one that can rotate through 180 degrees and another that is limited to 90 degrees.  Here’s an example of using the 90 degree version, as well as the ball and socket connectors I added ages ago, to make a ragdoll in the game:-