Tutorial:Making Planets

From Kerbal Space Program Wiki
Revision as of 07:32, 7 June 2024 by Fgeg (talk | contribs)
Jump to: navigation, search

Creating Your Own Planets

This tutorial is designed for those with a relentless, creative spirit. Those seeking a way to vent said creativity will be delighted to learn that, with the Kopernicus plugin's existence, it is now possible to modify the planetary system in Kerbal Space Program, allowing for new planets to be added and existing planets to be modified or removed entirely.

Specifications

  • Length: 15-60 minutes
  • Difficulty: Advanced
  • For Version: 1.12.X

Requirements

  • Kopernicus
  • KittopiaTech
  • A text editor. Notepad can do the job, but Notepad++ is highly recommended.
  • [Optional] Image Editing Software

Config Files

The first step when making planets is knowing the basics of config files. Let's start by creating one! Create a folder inside of your "GameData" directory and name it whatever you want, then make a new text file within it.

Once you have settled on a nice saving location, write the name of your planet and remove the .txt as we will not be saving in this format. Add .cfg behind it, and select All Files in the drop-down menu following Save as type

For this tutorial, we will be making a planet called Tutora. So, in this case, we would write Tutora.cfg. The file name is actually not that important, but it's recommended to name config files properly so that you know just from the name what it contains.

Now we should have a .cfg file. Let's get to editing it!

Firstly, there are two kinds of config entries that you must memorize. The first is called a 'Config Node'. These appear as follows:

Orbit { ... }

As you can see, the name of the node is followed up by an opening bracket, which is in turn followed up by the node's contents, then lastly - and this is very, very important - the closing bracket. (Notepad++ automatically highlights opening and closing bracket pairs, which is why it is pretty much industry standard when making planets.)

The other kind of config entry is called a 'Config Value', and these appear as follows:

semiMajorAxis = 19000000

As you can see, a config value is always in the format of 'X = Y', where X is the name of the Config Value and Y is the data assigned to it. Y can be many different kinds of data, for example a line of text (a 'string', as it is called in programming languages), a whole number (also known as an integer), or a number with decimals (also known as a 'float' or a 'double', depending on the situation).

Making planets is largely the product of simply placing the correctly named nodes in the right locations, and supplying the right config values with the right data.

Module Manager Syntax

Contrary to what some might expect, we are not actually writing a piece of code for Kopernicus. Rather, Kopernicus internally has a config file, which we will be altering - and this is very important - indirectly. We will be using the 'Module Manager' plugin to patch Kopernicus' config file instead. This way, users can add and remove planet packs at will without having to go into the config files and swapping things out manually.

Although writing configs largely comes down to Nodes and Values, there are several handy commands that you can leave in your code for ModuleManager to use.

Let's go over a few.

@Orbit { ... }

The @ operator means 'edit'. In the above example, instead of declaring a node named 'Orbit', we are instead telling Module Manager to patch an already existing Orbit node. Note that this will not randomly edit an Orbit node - only one in the exact same location, in another file. (IE the parent nodes of the node marked for editing must match those of the target node in terms of name)

!Orbit {}

The ! operator differs in use. In the above example, we tell Module Manager to remove the Orbit node. We do not need to specify anything in the brackets, just add them to inform Module Manager that we are targeting a NODE, not a VALUE. Another case for the ! operator is conditioning:

@Kopernicus:NEEDS[!OPM] { .. }

Above, you can see that we edit the 'Kopernicus' node. However, we have added the 'NEEDS' condition to it. The above code, when translated to English, basically means:

Edit the config node Kopernicus with the below changes, BUT only do so if the tag named OPM is NOT present.

Note that 'not' is written in capital letters. This is because I would like to draw your attention to that word. Rather, the fact that, if we were to remove the ! operator from the above code example, we would have to remove the 'NOT' word in the translation. Ergo:

NEEDS[OPM] = only patch when the tag 'OPM' is present
NEEDS[!OPM] = only patch when the tag 'OPM' is NOT present

But what are these 'tags' that I have mentioned thrice thus far? Tags can be targeted by Module Manager conditions, and can be declared in many ways: - Folders directly inside the GameData folder of your KSP directory can be targeted as a tag. - Tags can be declared with the :FOR[X] condition, where X is the name of the tag

And that brings us to the next condition: FOR.

@Kopernicus:FOR[Bob] { ... }

FOR on it's own does not do anything, it is merely a marker for other conditions, namely BEFORE, AFTER and NEEDS. Let's call the config file containing the above node 'File A'. In that case, making config edits with conditions will have the following effects:

BEFORE[Bob] = The patch is applied before the patch declared in File A (which is marked as 'FOR[Bob]', remember!) is applied.
NEEDS[Bob] = The patch is only applied if File A (or another file declaring the tag Bob through the use of FOR) is present.
NEEDS[!Bob] = The patch is only applied if the tag 'Bob' is not declared anywhere.
AFTER[Bob] = The patch is applied after the patch declared in File A (or any other file declaring the tag Bob through the use of FOR)

And lastly, a more advanced condition, especially handy when editing a specific node of which there are multiple.

!Atmo:HAS[#name[Duna]]{} (Taken from here with lots of thanks.)

As you can see, we are removing the config node named 'Atmo', but we have the HAS condition preventing the deletion of every single node named 'Atmo'. The HAS condition limits the effect of a patch to config nodes that meet the declared condition. In the above example, each Atmo node is checked if it contains a Config Value named 'name', with an assigned value of 'Duna'.

Planetary Nodes

Before we start making planets, let's go over the config structure.

The first thing that we want to do is edit the Kopernicus Config Node. So let's open up the config we made earlier. Remember that we will be making a planet called Tutora.

@Kopernicus:FOR[Tutora] { }

The observant among you have noticed that we are declaring this config with the tag 'Tutora'. This means that we can specify a loading order for config files (should we need this later) by marking patches with AFTER, BEFORE, and NEEDS.

Every celestial body has its data stored in a node called 'Body'. There can be multiple Body nodes per config, but only one planet per Body node.

Let's add the Body node to the above start.

@Kopernicus:FOR[Tutora] {

   Body
   {
       name = Tutora
   }

}

I have also added the 'name' Config Value real quick. The 'name' Config value declares the name that the celestial body will wear, both internally and in-game (unless otherwise specified).

Inside the Body node of Tutora, we can add a variety of Config Nodes. Let's go over a few.

Debug {} Debug stores data for debugging planets, for example whether or not we want Kopernicus to generate a cache file.

Properties {} Properties stores most of our planet's physical properties (mass, radius, gravitational acceleration, rotation period, whether or not our planet is tidally locked, et cetera) as well as some miscellaneous items such as the in-game description, the science multipliers, and the timewarp altitude limiters.

Orbit {} Orbit stores the data related to the planet's placement within the Kerbal universe, or rather, the path that it will follow through said universe.

Template {} Template allows you to clone a stock planet. If you choose a template, anything you declare in your config will be applied as a patch to a copy of that template's config file. Note: you are not altering the stock planet itself, rather Kopernicus clones it and applies the data you specified to that clone. Using a template is highly recommended. In the Template node, you can also do some rather interesting things, such as removing PQSMods from the template planet (we'll go over what in the world PQSMods are later), removing the ocean of the clone, or removing the atmosphere of the cloned planet.

Atmosphere {} Atmosphere stores all of the information regarding a planet's atmosphere. Not just the altitude limiter, but also physical and chemical properties such as the adiabatic index (used for calculating the speed of sound), the molar mass (used for calculating the density), the temperature-height profile, and many other things.

Ocean {} The Ocean node stores all data regarding a planet's oceans. If a planet's configuration does not contain an Ocean node, it will not have oceans.

ScaledVersion {} Because keeping an entire planet loaded is rather taxing, KSP cleverly unloads the planet should the camera go too far from the planet, and instead will load in a relatively low-poly representation. Through ScaledVersion we can edit this representation. Essentially, ScaledVersion is in charge of making our planet look good from afar (such as in the Map View)

PQS {} PQS stands for Procedural Quad Sphere, and is the kind of terrain KSP uses for its planetary surfaces. The PQS node contains all of the data regarding our planet's actual terrain. It is therefore, in essence, the counterpart to ScaledVersion. Note that non-terrestrial objects such as Jool and the Sun lack the PQS node and thus a Quad Sphere, which is why they have no solid surface.

Making a Gas Giant

Now that we have the above cleared up regarding Config Nodes, we can select the Config Nodes that we will be needing, as well as a template.

Let's use Jool.

@Kopernicus:FOR[Tutora] {

   Body
   {
       name = Tutora
       Debug //We want to add some changes here.
       {
           exportMesh = false //Setting this to false means that no cache file is generated.
           //Since a gasplanet has no solid surface, we don't need the cache file, as there is no PQS to store there.
           update = true //We do want the planet to be updated though.
       }
       Template
       {
           name = Jool
           //Besides picking a template there isn't anything else to do here. We don't need to remove anything else.
       }
       Properties
       {
           description = This stores the text that will be visible in-game in the info tab.
           radius = 4000000 //This CfgValue stores the radius of the planet (average distance from surface to center), 6000km = 1 Jool radii. 4000km = 2/3 Jool radii.
           geeASL = 0.63    //With geeASL you can define the gravitational acceleration at the surface, expressed in g's (IE the amount of times Earth's gravity. 9.81 m*s^-2 = 1g)
       }
       Orbit
       {
           semiMajorAxis = 5000000000 //Nothing too fancy. We basically clone Jool's orbit but with a different average distance.
       }
       Atmosphere //Let's access the atmosphere
       {
           ambientColor = 0.7,0.5,0.1,1 //Ambient color provides a slight tint to any craft inside the atmosphere, with the tint intensity increasing with depth
           lightColor = 0.37,0.47,0.62,1 //Light color is somewhat strange, for some reason the lower the intensity of a color, the more prominent that color is.
           //Pro tip: adjust lightColor in-game with KittopiaTech.
       }
       ScaledVersion //Gas planets are only the scaledspace mesh
       {
           Material //The Material subnode is where we actually alter the appearance of the ScaledSpace mesh
           {
               texture = Tutorial/PluginData/Tutora_c.dds //Here we assign a new texture to the sphere.
           }
       }
   }

}

I would like to draw your attention to the line texture = Tutorial/PluginData/Tutora_c.dds, because there is a reason why the texture is placed in a folder called 'PluginData', why it is in the DirectDrawSurface format, and why the filetype extension is included in the filepath.

Saving a texture in a folder called PluginData prevents KSP from loading it. This is because KSP does not check in folders named PluginData for some odd, yet very convenient reason. Because KSP does not load the textures when they are in a folder called PluginData saving them there means that loading times are greatly reduced.

It is then that a built-in Kopernicus feature called On-Demand Loading comes into play. O.D.L only loads textures of planets in view, and unloads textures of planets that have been out of the camera's view for a while. This saves a lot of RAM memory. However, O.D.L only works when a texture is both:

1. Saved in a folder called PluginData. 2. Assigned with the filetype extension added (IE the texture filepath ends with the filetype, for example .png, or .dds)

Lastly, there is the fact that the texture is saved as a DirectDrawSurface file. The reason for this is that DDS is the filetype used by the GPU, other types such as PNG and JPEG have to be converted first. This means that saving and loading DDS textures is faster than other filetypes. It is therefore recommended to use DDS as much as possible. Adobe Photoshop can pretty much do this out of the box, and for GIMP there is a free plugin that allows for DDS texture saving.

Making a terrestrial world

Making a terrestrial planet differs from gasplanets in one major way - the Procedural Quad Sphere.

So, let's do a little code revamp to change Tutora into a terrestrial world.

@Kopernicus:FOR[Tutora] {

   Body
   {
       name = Tutora
       Debug //Now we want both to be true.
       {
           exportMesh = true
           update = true
       }
       Template
       {
           name = Dres
           removeAllPQSMods = true //This strips the template of its PQSMods, meaning that it is essentially a clean slate for us to work with.
       }
       Properties
       {
           description = This stores the text that will be visible in-game in the info tab.
           radius = 400000 //This CfgValue stores the radius of the planet (average distance from surface to center), 600km = 1 Kerbin radii. 400km = 2/3 Kerbin radii.
           geeASL = 0.63    //With geeASL you can define the gravitational acceleration at the surface, expressed in g's (IE the amount of times Earth's gravity. 9.81 m*s^-2 = 1g)
       }
       Orbit
       {
           semiMajorAxis = 5000000000 //Nothing too fancy. We basically clone Dres' orbit but with a different average distance.
       }
       //Dres does not have an atmosphere, so let's remove the atmosphere node for now.
       //Note: you can add an atmosphere to a vacuum template, that's not an issue at all.
       PQS //We access the quad sphere module
       {
           Mods //We access the PQSMods - the mods are what shape the surface
           {
               VertexSimplexHeightAbsolute
               {
                   deformity = 250 //The amount of meters that this noise mod should affect the terrain
                   frequency = 25 //The greater this number, the smaller the noise is
                   octaves = 3 //The greater this number, the prettier the result, but also the more costly it is
                   persistence = 0.3 //This subdivides the noise a little bit. Be careful with setting this value
                   seed = 28396 //Just enter a random number here
                   enabled = true //Should this mod be taken into consideration when building the terrain?
                   order = 10 //The order in which this mod is applied. The lower the 'order', the sooner the mod is applied.
               }
               VertexSimplexNoiseColor
               {
                   blend = 1 //Between 0-1, the amount of control this color mod has over the terrain
                   colorStart = 0.4,0.4,0.4,1 //Color A
                   colorEnd = 0.8,0.6,0.2,1 //Color B
                   //The below values generate a Simplex noise that linearly interpolates between colors A and B.
                   frequency = 6
                   octaves = 8
                   persistence = 0.3
                   seed = 90135
                   enabled = true
                   order = 500
               }
           }
       }
   }

}

Although the planet generated with the below code may not look that aesthetically pleasing, it will in fact work, which is the point I'm trying to demonstrate here. Planets do not require maps to work, and neither do they need maps to look good, as demonstrated by this planet pack.

So for the main part, editing planets comes down to knowledge of PQSMods, or image editor skills.

Config Value List

Below is an extensive list of values for each Config Node

Legend

  • string A string of text
  • path A filepath (usually with the filetype extension)
  • integer A whole number
  • float A number with decimals
  • bool Either 'true' or 'false'
  • vector4 A 4-vector value. It is commonly used in colors as R,G,B,A
  • vector2 2 floats linked together like this: X,Y

Body {} Placement: the Body node goes inside the @Kopernicus {} node.

  • name - string - Controls the name of the planet.
  • cacheFile - path - Controls the location where Kopernicus generates a cache file for this planet. X should be a filepath ending in a name, with the .bin extension added at the end.
  • flightGlobalsIndex - integer - FlightGlobalsIndex is used for the orbit of crafts in the save files. In a KSP safe file, what planet a craft is orbiting is identified by the FlightGlobalsIndex. It is recommended that you set this to a value (which has to be a unique number, a number not shared by any planet in any planet pack), or leave it out entirely, in which case Kopernicus will assign it a F.G.I depending on the order of the planet in the solar system, from the Sun outward. Leaving it out is best for compatibility with other planet packs, but this means that adding a non-indexed planet to an already-in-progress save file could make crafts shift orbits.

Properties {} Placement: the Properties node goes inside the Node {} node.

  • description - string - The text assigned to this Config Value shows up in-game in the info tab.
  • radius - integer - The radius of the planet in meters.
   Use one of these three to set the gravity of a planet:
  • geeASL - float - The surface gravity in G's.
  • mass - float - The mass of the planet in kilograms.
  • gravParameter - float - The gravitational parameter is the mass times the gravitational constant. (G = 6.6741*10^-11)
  • rotates - bool - If true, the planet rotates. If false, it does not rotate.
  • rotationPeriod - float - The rotation period of the planet in seconds
  • tidallyLocked - bool - If true, the planet's rotation period is set equal to the planet's orbital period. Essentially this will make an object always display the same face when viewed from its parent planet/sun, much like our moon does.
  • initialRotation - float - Can be used to offset the planet's rotation at t = 0 (the start of a new save file)
  • albedo - float - Albedo controls the amount of incoming radiation reflected by an object. Here is an article on the albedo-effect.
  • timewarpAltitudeLimits - 8 floats - The altitudes at which timewarp speeds are unlocked. This should have zero as the first number, followed by seven others, separated with a space. (Not a comma)
  • biomeMap - path - The filepath to the biome map of the planet
  • displayName - string - This value controls the external name of the planet, IE the name seen in-game. Internally it does not change the planet's name.

Biomes {} Placement: the Biomes node goes inside the Properties {} node. Note: There should be multiple Biome {} nodes inside the Biome {} node, each corresponding to a biome on the biomeMap. Here is the syntax for one such node.

Biome {}

  • name - string - This should be the display name of the biome you want to display.
  • value - float - You can use this to increase/decrease the science multipliers for this biome.
  • color - vector4 - Should be set to the color on the biome map representing this color.

ScaledVersion {}

  • type - string - This should be set to either "Atmospheric" or "Vacuum"
  • fadeStart - float - When the ScaledVersion starts to fade in.
  • fadeStart - float - When the ScaledVersion is fully faded in and opaque.

Material {}

  • color - vector4 - The color of your planet.
  • specColor - vector4 - The specular color of your planet.
  • shininess - float - How shiny the planet is.
  • texture - path - The color map.
  • mainTexScale - vector2 - The scale of the texture.
  • mainTexOffset - vector2 - The offset of the texture.
  • normals - path - The normal map.
  • bumpMapScale - vector2 - The scale of the normal map.
  • bumpMapOffset - vector2 - The offset of the normal map.
  • opacity - float - How opaque the ScaledVersion is.
  • localLightDirection - vector4 - The direction of light coming at the planet.
  • resourceMapScale - vector2 - The scale of the resource map.
  • resourceMapOffset - vector2 - The offset of the resource map.
    • NOTE - Anything below here relates to the atmosphere. If you are making a non-atmospheric planet, you do not need to include these.**
  • rimPower - float - How strong the atmospheric rim is.
  • rimBlend - float - How much the atmospheric rim blends.

Gradient {}

  • float - vector4 - Format: 0.0 = 1,1,1,1. The atmospheric gradient. First value has to be 0 and last has to be 1.
  • rimColorRampScale - vector2 - The rim's color ramp scale.
  • rimColorRampOffset - vector2 - The rim's color ramp offset.

} }

[Optional Step] Texturing

If you do not want your planet to be just a white sphere, texturing is very important.

Height Maps

A height map is basically a grayscale representation of the planet's topography. You only need height maps on terrestrial planets. The more white the pixel is, the higher it is. There are many ways to make a height map, however, once you are satisfied with your height map's look, apply a polar distortion on the planet, then convert it from polar. Then, flip the image and do the same thing for the other side. Keep it flipped upside down, because KSP renders the texture upside down in-game, so even if it looks upside down in the preview, it won't be ingame. Once you have made the height map, save it as a DTX5 dds file. It doesn't matter that much if you use mipmaps or not.

Normal Maps

Take your height map from earlier, or color map if you are making a gas giant. Apply a normal map filter on it and adjust the scale to your liking and save the normal map as a DTX5nm file instead. It will look red in the previews, however this is perfectly fine. However, do not, under any circumstances, use mipmaps for normal maps. Note that it is recommended to keep a low scale for the normal map of a gas giant of around 1.

Color Maps

A color map is what your planet will look like with color. There are many ways to do this, similar to a height map, and you need color maps on both terrestrial and gas giant planets. However, you should also save it as a DTX5 dds file. Leave mipmaps on/off depending on how you want it.

Applying the maps

In order to apply the maps, you need to change the config by adding a ScaledVersion and a PQS node, as shown above.