So you want to add your own aircraft to Exosky? No worries – it’s been designed to be as easy as possible! Follow the tutorial below. Some notes;
- Jets are not technically supported. You can use them but you won’t get any engine noise. In a future update I’ll add custom sound and jet support.
- If you have any issues, hop on the Discord and ask me directly (Elevons)!
- Right now errors fail silently. In future versions I hope to open up the same debug tools I have to the community to make debugging easier.
- Unfortunately levels are not yet moddable, but I am researching ways to open them up too.
- All aircraft currently use the same “drone simulation pod” cockpit. Multi-cockpit support will be added in a later release.
- Eventually I would love to add some in-game mod support so files don’t have to be transferred manually. We’ll see if the game gets popular enough to warrant it!
We’ll be making this aircraft – the Verville-Packard R-1. It is the winner of the first Pulitzer Trophy Race.
How to Install a Mod
Step One
Navigate to the install folder. In Steam you can right-click on the game in your library and go to Manage -> Browse local files.
Step Two
Within the install folder, navigate to Exosky\Exosky_Data\StreamingAssets. For aircraft modifications, copy/paste the aircraft folder into the Aircraft Directory.
If an aircraft comes with a propeller folder (it will only have a data.json in it), that gets copied into the Propellers folder.
So for the sample mod:
Aircraft: Exosky\Assets\StreamingAssets\Aircraft\Verville-Packard R-1
Propeller: Exosky\Assets\StreamingAssets\Propellers\VPR1
Step Three
Atmospheres can be modified, but this is not officially supported. Just don’t change the folder names and you will be able to swap out the atmospheres in each level by changing the properties in their JSON files.
Creating an Aircraft
Before You Start
You will have two models; a visual model and an aerodynamics model. The visual model can be anything you want; the aerodynamics model is just used to generate the aircraft JSON. We’re going to start with the visual model first.
Also, we will be performing some rotations on every aspect of the model to align it with Unity’s coordinate system; please wait until after we do this before creating any ambient animations (rotating lights, anything else you want).
Download and install the Blender plugin. Download the zip, go to Edit -> Preferences -> Add Ons -> Install and double click the zip file (don’t unzip it).
Part One: Set Up the Visual Model
Step One
Orient your aircraft with the nose pointing towards the bottom of your screen when you view the aircraft from above.
Step Two
Build a collision mesh. It does not need to be very accurate as it will get converted to a convex mesh anyway. But it does need to have the same proportions of the aircraft for moment of inertia calculations.
Step Three
Separate out your control surfaces, prop and prop blur (if applicable). These mesh elements should all be in separate objects.
Step Four
Align each object’s origin with the hinge line for each control surface. Each control surface that does not share a hinge line should have their own mesh object. If your control surface will move together (like two horizontal tails for example) then they should be part of the same object.
You did it right if you select the mesh object, change your transform to “Local” mode and the surface rotates properly.
Step Four
Next, we’ll align it with Unity’s coordinate system.
Parent everything (except the collision mesh) to a single object. Then, select this object and apply it’s rotations (Object -> Apply -> Rotation).
Apply a +90° rotation to the root object and the collision mesh. Then, apply the rotation again.
Finally, apply a -90° rotation to the root object but not the collision mesh. The aircraft is now ready for export and you can do any ambient animations here.
NOTE: Sometimes you need to apply this rotation to all the sub-objects as well. Sometimes you don’t. It changes depending on hierarchy, orientation, etc. It’s best to start with just the root object and go from there.
Part Two: Set Up the Aerodynamic Model
Start
Install the Exosky Aircraft Builder plugin:
- Edit -> Preferences -> Add Ons -> Install -> Double click on ZIP file.
Add an Exosky Aircraft Definition (Add -> Exosky -> Aircraft Definition).
Click on the Data Properties Panel.
You can fill out the different sections by following the order below.
Aircraft Header
Mod Name: A package of assets (for example, “Air Racers of the 1930s”).
Creator: Your name.
Aircraft Name: The name of the aircraft to be displayed in-game. IMPORTANT: This must be the same as the folder name.
Max Health: Should be generally set to 1.
Max Temp/Pressure: Ignore these, they are not yet implemented.
Mass: Weight of aircraft. (No commas)
Energy Capacity: A good starting range is 20,000+. (No commas – should be: 20000)
Recommended Atmosphere/Description: Text strings that support rich text formatting. (<b>, \n for a new line, etc.).
Fuselage
Make a copy of your visual model and delete everything except the fuselage. Use the eyedrop tool and click on that object. This will calculate the frontal area and fineness ratio based on the model. If your model is very dense, use an proxy mesh as otherwise it will be very slow.
Center of Gravity
Position where appropriate. I like to model with my aircraft centered around it’s CG but this is not required.
Cameras
Position a camera externally and internally.
Internal Camera: Where the pilot views from; will not show anything of the external model.
Exterior Camera: Used to position both free look and fixed chase.
Protip: Open a Blender window and set it’s view to the camera you are working on to get a preview of what it will look like in game. In-game default FOV is 60°.
Propulsion
You can add as many thrusters as you want to an aircraft, but individual control of them has not been implemented.
Max Thrust: You can ignore this, it is only used for “Jet” aircraft which are not fully implmented.
Propulsion Type: “Propeller” is default. You can set it to “Jet” but you will not have engine sounds. Propeller includes effects like torque and P-Factor. Jet is just pure thrust and will use the Max Thrust value.
Propulsion Name: You can leave it as-is or use one of the existing propellers in the game (use a folder name from Streaming Assets\…\Propellers). You can also make your own (see Making a Propeller).
Model Name: The name of the propeller object, shown at low RPM. Case sensitive.
Blur Model Name: The name of the blur object, shown at higher RPM. Case sensitive.
Throttle acceleration: How quickly this thruster responds to throttle inputs. Snappy response is 0.8+.
Rocket Group
Rocket Group: The rocket group contains different thrust points, with the thrust spread out over all of them (total thrust divided by the number of thrust points). Add as many thrust points as you would like.
Thrust (Newtons): How much thrust the rocket has; 50,000+ is a good starting point.
Burn Time: How long the rockets will burn for.
Activation Charges: How many times you can fire the rockets.
Flares
Flares will fire in the direction of the arrow. You can add as many flare emitter points as you’d like, but be mindful of performance implications.
Duration (Seconds): How long each flare charge will last.
Activation Charges: How many times you can fire the flares.
Flying surfaces are the core of the flight model and they’re really easy to make because they are literally just geometry! The Exosky Aircraft Tool will use your mesh to create a lift point at the proper location. Then these points and their normals will get saved to the JSON file. Aerodynamic forces are applied at each lift point based on the calculated dimensions of the mesh face that they are associated with.
Note: You can move the lift points manually if you wish; their values are recorded at the time of export.
Flying Surfaces
Clicking “Add a Wing” will add a mesh plane to the scene with a few special property flags.
NACA 4 Digit Airfoil: Enter any 4 digit airfoil here and the software will extrapolate it’s properties. 2412 is a good general airfoil, 2410 is good for control surfaces. You can use any online tool like this one to generate an airfoil and see what it looks like.
Click “Select Wing” to move to the next step.
Creating a Flying Surface
Flying surfaces can be named whatever you want; so at this point feel free to rename it to something like “Top Wing” or “Horizontal Tail” to help organization.
Edit the wing mesh object and shape it to match your visual model.
Sine things to keep in mind:
- There’s no hard rule about wing organization – you can have multiple separate surfaces in a single wing object or separate each wing out into separate wings. On export, all that matters is the position of the lift points and their properties.
- More faces per wing will create a more detailed simulation of lift across the wing, though I have not noticed a huge difference past 4 or 5.
- Note that the wing mesh is just like any other mesh object except it has a “is_wing” object property. You can model like normal; just make sure it is made out of quads and is a single poly thickness.
- Faces only count in the forward/backward direction. Dividing them across the X axis will not add more detail to the simulation.
- Segment out the section that will have the control surface – this will become it’s own lift point and it’s important that it’s accurate.
- You can use a mirror modifier but it must be applied before generating lift points.
- Surfaces don’t have to be square, we just use their position and area to calculate the lift point. Do try to keep them as rectilinear as possible though.
- If you have two vertical tails (like an F-15 or F-18), their lift point normals should point in the same direction.
Once you have created all your wings, it’s time to start defining them for the simulation to read by creating lift points.
Creating Lift Points
Make sure your wing object is selected for the next step and all modifiers are applied. Under object data properties, click “Calculate Lift Points”. This will create one lift point per face; which is why it’s important that you put an edge loop on the edges of the control surfaces.
Defining Control Surfaces
Select all the lift points corresponding to a single control surface. Under Object Properties you will find details under “Custom Properties”.
Area: This is calculated, modifying it will produce unexpected results.
Chord Length: This is calculated, modifying it will produce unexpected results.
Control Surface Model: This is the model that will be rotated when control inputs are applied. Make sure that left and right surfaces are separated; the game will rotate them correctly. This is a case sensitive field.
Control Surface Percentage: This is the chordwise percentage (front to back) that your control surface takes up. It is from 0 to 1.
Control Surface Type: The following options are available (non case-sensitive):
-
- None
- Aileron
- Elevator
- Canard
- Rudder
- Flipped Rudder (for rudders on the nose)
- Flap (currently unused)
Is Control Surface: Check this box.
Is Liftpoint: Leave this box checked
Max Deflection: This is in degrees and should be positive.
Min Deflection: This is also in degrees and should be negative.
Part Three: Exporting
Before You Start
Create a folder in Exosky_Data\StreamingAssets\Aircraft with the EXACT SAME NAME as “Aircraft Name” in the Aircraft Header.
Step One
To export the aerodynamic data, open the Aircraft Header on the Aircraft Definition. Click “Export Aircraft”. Navigate to the folder you created for the aircraft and type in “data.json”. Hit Export Aircraft to save.
Step Two
To export the visual model, select all the elements you wish to export. Go to File -> Export -> GLTF 2.0. Save this to the folder you created with the following settings:
Name: model.glb
Include: Limit to Selected Objects
Transform: +Y Up (this is default)
Data: All default
Animation: If you have ambient animations, change Animation Mode to Active Actions Merged. You do not have to bake the animations before export.
Hit Export GLTF 2.0.
Step Three
Select the collision mesh you made. Export it to the same folder with the following settings.
Name: collision_model.glb
Include: Limit to Selected Objects
Transform: +Y Up (this is default)
Data: All default
Animation: Uncheck.
Hit Export GLTF 2.0.
Step Four
You will need a display image for the model. Place a PNG called “image.png” in the folder. It must be 1024 x 512.
Final
You should now have a folder that has the exact same name as the aircraft as defined in the aircraft header. Inside that folder you should have:
- model.glb (visual model)
- collision_model.glb (collision mesh)
- data.json (performance data)
- image.png (display image in aircraft selection)
If you chose to use a custom propeller you also must have that propeller in the Propellers folder. If you left it at default propeller then disregard this.
Propeller is Rotating around the wrong axis: Check your rotations in Blender before you exported the visual model. Make sure the propeller is either 0,0,0 or -90, 0, 0.
Control Surface is moving around the wrong axis: See above.
Control Surfaces are not animated: Make sure you have chosen the right name for the lift point’s control surface model – it is case sensitive.
Level does not load when aircraft selected: Make sure your aircraft name and your folder name match exactly. Make sure that all the data in the aircraft definition has been filled out. Make sure that if you are using a custom propeller, that propeller exists.
Left Rudder makes aircraft go right/Right Rudder makes aircraft go left: Flip the normals of the wing surface and regenerate the lift points.
Aircraft does not fly at all (drops instantly): Make sure you have calculated lift points before exporting.
Part Four (Optional): Custom Propellers
Step One
Custom propellers are treated as wings. To create a Propeller Definition, go to Add -> Exosky -> Create Propeller. This will create a Propeller object with a Wing as a child and selected by default.
To start, let’s select the propeller parent object (the circle empty). The circle is a visual reference, so feel free to increase it’s size by going to the Object Data Properties tab and change the Size property. This will have no bearing on the export, again it is just for reference in the editor.
Propellers must be positioned at world origin before export (otherwise the offset is applied when they are positioned in the sim), but you can move it around while you are working on it.
Step Two
Modify the settings on the Propeller object.
Propeller Name: This must be the same as the folder this propeller resides in and any aircraft that uses it must also use the same name.
NACA 4 Digit Airfoil: This is the same as a regular wing. You can leave it at default (2412) if you don’t want to change it.
Wing Count: This is how many blades the propeller has. We will only be modeling one of them, but you can define the amount here.
Sample Count: Sample count is the fidelity of the simulation; too high can have serious performance issues. 2 to 6 is usually fine. Not to get too technical, but we don’t actually rotate these wings; we instance them and apply a local force to each blade. The number of instances is the number of propellers times the sample count.
Step Three
Model the propeller by modeling only one of the blades.
Both pusher and puller aircraft’s propellers rotate clockwise. I have found good results when the resulting lift points are pointing forwards at either 45 degrees down (puller) or up (pusher). To be honest, modeling a propeller is as much an art as it is a science, so play with it to get good results. Propellers on opposite sides of an aircraft will automatically counter-rotate to cancel out P-Factor.
Step Four
Select the wing, go to Object Data Properties and select “Calculate Lift Points”.
Then select the Propeller Definition and export the resulting data to Exosky_Data\StreamingAssets\Propellers\YourPropellerName\data.json. Remember that YourPropellerName has to match the Propeller Data’s “Propeller Name” exactly.
To use the propeller, just use it’s Propeller Name on any Thruster you create for an aircraft.
Increasing Throttle Decreases Speed: Propeller lift points are pointing in the wrong direction.
Nothing Loads: Check that your folder name, propeller name and referenced propeller name all match.