EnthusiastGuy / MonoGame-Pixel-Planets

A MonoGame port of a great pixel planet generator from Deep-Fold
MIT License
59 stars 7 forks source link

MonoGame Pixel Planets

Originally created by Deep-Fold, ported by Enthusiast Guy

  1. Showcase

https://www.youtube.com/watch?v=wnwpnkBD6OQ

  1. About

1.1. This document history

13.03.2021

1.2. Personal note

This project is somewhat branched off this one right here: https://github.com/Deep-Fold/PixelPlanets The author, Deep-Fold is the original wizard of all this, and large amounts of hails should go his way. Please visit his itch.io project page here: https://deep-fold.itch.io/pixel-planet-generator

I'm the Enthusiast Guy, responsible for this port to Monogame. You can find me on YouTube: https://www.youtube.com/channel/UCs3I6aDQ6Hj7m6_9l0HBgQA

I've stumbled upon this crazy cool gem just a few days before writing this. I have my own game project that I'm working on, and it so happened that I needed planets for some parts of my game. The original project is written with Godot (https://godotengine.org), however my own game project is written quite extensively in MonoGame. The shaders Deep-Fold wrote are in GLSL language (https://en.wikipedia.org/wiki/OpenGL_Shading_Language) while monogame uses HLSL (https://en.wikipedia.org/wiki/High-Level_Shading_Language). Basically think of them as OpenGL vs DirectX. Because Monogame's ancestor is XNA written by Microsoft for XBox360, you can see why it would not use OpenGL shaders.

I have never worked with shaders before this, but I had hoped that this wonderful project can somehow be converted to the HLSL that monogame supports, and in fact, it did as this very project stands whitness for.

Following Deep-Fold's nice guidance in this new chapter of shaders, I was able to port this, while honestly not fully understanding the whole math behind it. For the moment, at least.

1.3. Further development/support

I do intend to bring this one to a stable form, as accurate as possible and I'll provide moderate support if any bugs are reported, however, please consider that my main work is concentrated elsewhere and I may not have time for substantial features. Moreover, I believe this should remain a rather simple project. Feel free to fork it, though, and let me know what you did with it. ;)

1.4. Use/LICENSE

The original author released his work under MIT license and specifically mentioned we can do anything we want with it, under any circumstances, while, (not obligatory) a mention of his name would be nice. The same conditions are valid here. So:

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

  1. Project

Important. This project is NOT an example in code tidyness. Please don't assume it is. I took a lot of shortcuts to get to the desired result, as the central piece of this is the actual shaders, not the code architecture.

2.1. Structure

2.1.1. Entry point

The entry point of the application is the PixelPlanets.cs class. It contains the most important methods:

Update() and Draw().

Ideally Update should prepare everything in a state and Draw just to simply draw. I probably not respected that thoroughly, but make sure you do if you use MonoGame to build your game.

The State.cs class contains the state of most things in this app. It also contains the persisted data that is saveable to state.json with F1.

2.1.2. Shaders

As of version 1.2.0.17, the whole project has been migrated from MonoGame 3.7 to 3.8. This somehow introduced a problem in the shaders manifesting when attempting to compile the shaders: "unable to unroll loop, loop does not appear to terminate in a timely manner" After a bit of investigation it seems that the solution was to change one single line in planet_utils.fx: from

define PS_SHADERMODEL ps_4_0_level_9_1

to

define PS_SHADERMODEL ps_4_0

as per the documentation available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-models?redirectedfrom=MSDN (see the shader profiles there) it seems that initially I was using Shader model 2. Now, by simply changing that line, the shader model has been changed to 4.0, thus removing the initial issue. Clearly, devices that don't support shader model 4 can no longer run this code. Attempting to change to 3.0 was met with: "Pixel shader must be SM 4.0 level 9.1 or higher".

You'll find the shaders in the Content/ShadersV2 directory. All the shaders drawing planets/stars use a common shader included in all of them at the beginning, called "planet_utils.fx". That holds the common math used all over. Each shader has some "parameters" which means it accepts variables from the calling program and uses them further. Those params are not static, they look something like:

float time = 0.0;

This indicates that MonoGame is able to send values to them like this:

shader.Parameters["time"].SetValue(yourFloatValueHere); // See Shaders.cs for that

Many shaders consist of some layer methods that are used in the MainPS method. MainPS receives a VertexShaderInput input parameter that holds the TextureCoordinates that mean the actual XY of the current pixel Then, other layer methods are called with those coordinates to render gradually the land, lakes and clouds, whatever may be the case, and then they are returned from the MainPS once again as the final color for the respective XY pixel.

2.1.3. Debugging shaders

Arm yourself with patience. To compile a shader, you need to run Content.mgcb from your project/Content folder. That, should ideally launch the MonoGame Pipeline Tool. If, instead of that, you open a text file, then right click on Content.mgcb, select Open With and in the window that opens, find "MonoGame Pipeline Tool". Select it, click on Make Default and then OK.

Right click on a shader in ShadersV2 and select Rebuild. That will rebuild only the selected shader. If the build output shows the build with green, it means it compiled correctly all code in there. If not, then you need to debug.

First annoying thing (and it's partly my fault) is that because I introduced the #include, the line numbers no longer correspond as they should when they show you an error. They show a number higher then where the actual problem is. That is really annoying, but a workaround is to copy ALL methods from the "planet_utils.fx" in your working shader and get rid of the #include temporarily. Once you fix the problem(s) you can restore the structure.

While it may be inconvenient to do this, please resist writing permanent duplicate code. Trust me, in the long term it will backfire.

Keep in mind that shaders are pre-optimized by the engine. This means that if you comment a piece of code, the engine will aggressively go up the execution line and obliderate anything connected to the code you commented, considering that code should no longer exist. This includes parameters, so you CAN get an error when trying to pass a parameter not used, because it is NO LONGER exposed.

While in GLSL you may declare a vec2 like this: vec2(.5), which means actually vec2(.5, .5), you can't get away with this in HLSL. You need to explicitly declare float2(.5, .5), otherwise you'll get an error.

2.1.4. Packages

This project uses Newtonsoft json to serialize/deserialize the state data.

  1. Version history

1.2.0.17 - march 13'th 2021

0.2.0.17 - march 3'rd 2021 - The very first published version. It is an alpha version, meaning not all features are yet connected, and some are downright missing (for now).

Features:

Userinterface

Known issues:

Planed features/work