Progress Update #21

 Procedural Generation Runtime Compliance


    Over this week I have made major progress on the packaging errors that effected the project; the majority of which had to do with the systems of generating procedural meshes and textures at runtime. The reason they weren't runtime compliant is that I was using functions and variables from the engine that were marked as WITH_EDITOR or WITH_EDITORONLY_DATA which are not allowed to be used in packaged builds of the game/ at runtime.


Procedural Meshes:

    With the main appeal of the game being the generation of planets I decided to start by fixing the mesh generation system. In the process of looking for a solution I came across two articles (article 1 article 2) on the subject of runtime procedural meshes written by an employee of Epic Games. The first article was the one that I spent most of my time on but they are both very detailed on their respective topics. 
    After multiple days of trying to implement solutions put forth by Ryan Schmidt, I decided that it wasn't in fact worth the investment to try for a static mesh and so settled for the engine's built in UProceduralMeshComponent (PMC). The PMC is what I initially started out with, so it didn't take long to get it back to a working state. Only this time I made some small improvements like using a single component to utilize the mesh section feature and reimplementing the face render mask to temporarily increase performance. 

    Now, the system is slightly faster than it was when it was creating the static mesh from the PMC, but I then rediscovered why I had wanted a static mesh instead; saving a procedural mesh component was slow as hell. It's so slow that it isn't reasonable to save any planet over a resolution of 16, which all of the planets in my testing level were.
    For this problem I have a short-term and a long-term solution. The short-term solution is to clear the PMC when saving, then regenerate it after the save has taken place, or the engine is restarted. This is less time consuming than saving the PMC itself but it still means regenerating all of the planets every time the game is reopened. This is where the long-term solution will eventually be implemented.
    The long-term solution is to save only the data critical to the mesh (e.g. vertices, triangles, uvs, normals, etc.) while still clearing the PMC. This way when the saving is done we don't have to fully recalculate the mesh, instead we can generate the mesh from those saved values thereby saving time in both saving and loading. 


Procedural Textures:

    I went down a similar route with textures as I did meshes. I did some googling, tried some stuff, couldn't get it to work, resulted back to the initial idea. The initial idea in this case being to apply color curves to an atlas then use the atlas as a texture parameter in the material. Just before I fully committed to reverting to the atlas idea I did one more, ultra-thorough, search to see if there was any other possible way to do dynamic textures. 
    I'm so glad I did because I ended up finding two resources that made the answer clearer than day. The first was an article on the legacy unreal wiki that concisely shows how to use UTexture2D::CreateTransient() and UTexture2D::UpdateTextureRegions() to make a dynamic transient texture at runtime. The second resource was a thread on the answerhub that essentially spells out exactly what you need to put into the UpdateTextureRegions() function to make it work properly.
    This answerhub thread was critical because I didn't know how to use the FUpdateTextureRegion2D that UpdateTextureRegions() calls for. This resulted in corrupt looking planets like this:


When after the fix they looked like this:


Here's what the final code looks like:


Niagara Component Error:

    In the last progress update I mentioned how when packaging the project I would get an error in the star's OnConstruction() method. The way I fixed this was by moving that chunk of code (the part that sets user variables in the Niagara emitter) to the BeginPlay() method instead. I'm guessing it was throwing an error because at the time of construction, the Niagara plugin isn't fully initialized? Don't know for sure, but there isn't really a difference in behavior depending on where the code is placed so I don't really mind.


UnrealEd Module & Conclusion:

    The last task I have to complete to make sure the packaged game will work is to get rid of the UnrealEd module in the public dependency modules. To my knowledge the module is only used in the project cleaner plugin. However, with textures and meshes being transient, I don't actually think I need it anymore. I don't know for sure though and I'll have to do some testing next week to see if that is the case. 

Comments

Popular posts from this blog

Polishing the Foundation

Progress Update #13

A New Chapter