bryanedds / Nu

Repository hosting the open-source Nu Game Engine and related projects.
MIT License
1.14k stars 156 forks source link

Augmenting Nu with 3d capabilities. #354

Open bryanedds opened 2 years ago

bryanedds commented 2 years ago

A while back, I started working on this in the 3d branch - https://github.com/bryanedds/Nu/tree/3d

So far I've mostly just 3d-ified the Transform type and converted the 2d portion of the engine. Since everything has gone so well so far, I wanted to take a moment and talk about the features I am planning for 3d.

Planned Features (while all planned features may not be available immediately, all of the data structuring and engine scaffolding will be in place to support them) -

I'm hoping to constrain my implementation to just <= OpenGL 4.1 for direct Mac support, but if I need a greater version to implement a critical features, we'll have to consider other options for supporting Mac (I understand there is an OpenGL-in-terms-of-Metal layer...)

Anticipated Features (not planned per se, and the engine will not necessarily have the data structuring and scaffolding to easily slide them in, but they are almost certainly necessary for someone) -

bryanedds commented 2 years ago

A vital item is the ability to import from Unity and / or Unreal. Implementing a USD import process for Nu is one possibility -

https://docs.unrealengine.com/4.26/en-US/WorkingWithContent/USDinUE4/

https://github.com/unity3d-jp/USDForUnity

Related to assimp and USD -

https://github.com/assimp/assimp/issues/1332

bryanedds commented 2 years ago

Looks like there's some .NET USD bindings here -

https://github.com/unity3d-jp/USDForUnity/blob/master/USDForUnity/Assets/UTJ/USDForUnity/Scripts/usdi.cs

Along with the example code for dealing with Unity, this could be a great start!

bryanedds commented 2 years ago

Newer repo here -

https://github.com/Unity-Technologies/usd-unity-sdk

bryanedds commented 2 years ago

Mesh Distance Fields can buy several advanced rendering features - https://docs.unrealengine.com/5.0/en-US/mesh-distance-fields-in-unreal-engine/

Their expense might be worth it since I've heard they could be used in place of cascaded shadow maps. // TODO: verify this.

bryanedds commented 2 years ago

Compile all shaders in a package when hint-loaded?

bryanedds commented 2 years ago

How will we do mesh picking in the editor? Triangle picking? EDIT: Yes, triangle picking from the metadata pipeline.

bryanedds commented 2 years ago

Unfortunately, it appears that mixing SDL rendering with OGL rendering is unsupported. This means I will probably have to start by rewriting the 2d renderer in OGL.

First, I need to design the 2d renderer. I am thinking that I will have a finite number of material parameters for any 2d renderable. That way sprite sorting / batching can be a static process. Unlike 3d rendering, 2d render messages are not composed of materials, but will stay pretty much the same API. It will be implemented with painter's algorithm rather than using z testing since, due to transparencies, we have to keep the sorting algorithm anyway. Like the 3d renderer - or perhaps even moreso - there will only be one rendering model for 2d. While I may add features to the one 2d material over time, I won't provide a way for users to extend it with additional parameters. Nor am I immediately going to provide any pre or post-processing 2d API. Again, that could be added later without restructuring the API.

This leaves a lot of power and features on the table for 2d rendering, but the fact that I have to whip this out in a week or two in order to meet my deadlines helps disambiguate that decision.

Fortunately, it does seem the sdl_ttf will work with opengl, so I won't have to figure out another way to render text - https://stackoverflow.com/questions/5289447/using-sdl-ttf-with-opengl.

bryanedds commented 2 years ago

Even with such a simple 2d rendering model, there's still a couple interesting things I can do basically for free (in terms of implementation cost). 2d normal maps, for example, as well as specular maps (tho that would require a light source render message). Pre and post passes actually would be basically free in terms of implementation. An Elevation buffer could also allow for some interesting effects.

Also, I need to design how the 2d and 3d images come together if 2d is going to have pre and post passes. I would need a destination alpha channel on the target 2d buffer and then render the target 2d buffer on top of the 3d buffer.

With an elevation buffer, some forms of 2d shadowing would be possible, but I dontt think general enough to implement.

bryanedds commented 2 years ago

While I can't necessarily allow the user to extend the 2d material interface, I could allow them to replace it and the rendering process itself with a 2d equivalent for https://github.com/bryanedds/Nu/blob/c3f908cba821f3407c574757cc78f9482df2c957/Nu/Nu/Render3d.fs#L48

bryanedds commented 2 years ago

Approximate render pass order -

shadow map -> geometry -> decals -> lighting -> screen space reflection -> tone mapping -> fxaa

bryanedds commented 2 years ago

For several reasons, mostly due to lack of tooling support, USD files aren't likely going to be our target scene format, but rather FBX. Unity FBX does a pretty good job. Just take the objects you want to export, put them under a single GameObject, then use GameObject -> Export to FBX... (presuming you have Unity's FBX Exporter plug-in installed).

bryanedds commented 2 years ago

FBX export from Unity is great and all, but the immediate question is how to attach user-defined data to an object and retrieve it in Nu. I'm guessing we can build an little custom exporter in term of Unity's FBX exporter API adds a UserProperty string field of a custom UserProperty component like so -

            // Import the scene to make sure file is valid
            using (FbxExporter exporter = FbxExporter.Create(fbxManager, "myExporter"))
            using (FbxImporter importer = FbxImporter.Create(fbxManager, "myImporter"))
            {
                // export the scene to a temp file...
                exporter.Initialize("TempFile.fbx", -1, fbxManager.GetIOSettings());
                var sceneTemp = FbxScene.Create(fbxManager, "SceneTemp");
                exporter.Export(sceneTemp);

                // re-import the scene to an FBX object we can manipulate...
                importer.Initialize("TempFile.fbx", -1, fbxManager.GetIOSettings());
                var sceneFinal = FbxScene.Create(fbxManager, "SceneFinal");
                importer.Import(sceneFinal);

                // search through scene, correlating nodes with game object that have a UserProperty component,
                // then add user property like so -
                var node = null as FbxNode;
                var userProperty = FbxProperty.Create(node, Globals.FbxStringDT, "UserProperty");
                userProperty.Set(userPropertyComponent.UserProperty);

                // then finally, export the scene to a non-temp file.
                exporter.Export(sceneFinal);
            }

...then we should be able to load it from Assimp via -

node.Metadata.["UserProperty"].Data :?> string

bryanedds commented 2 years ago

A few asset packs for testing the renderer - https://assetstore.unity.com/packages/3d/environments/urban/atmospheric-house-modular-192712 https://assetstore.unity.com/packages/3d/environments/urban/hq-abandoned-school-modular-106665 https://assetstore.unity.com/packages/3d/environments/urban/qa-police-station-162515

bryanedds commented 2 years ago

For the metadata pipeline, I might allow users to specify a .meta file for each asset like Unity, but unlike Unity, .meta files are completely optional. The user-defined .meta files are then fed into the metadata pipeline process, resulting in either a single monolithic metadata output file in the bin folder or one .meta file per asset in the bin folder. The important thing is to make .meta files not being a huge PITA like in Unity.

bryanedds commented 1 year ago

I have so far only found one seemingly usable Physx wrapper, but it seems questionable as to how cross-platform it will be -

https://github.com/stilldesign/PhysX.Net/blob/master/PhysX.Net/PhysX.Net/Source/StdAfx.h#L25-L26

bryanedds commented 1 year ago

Bullet physics used instead of Physx.

bryanedds commented 11 months ago

We should consider shadow caching as an optimization feature.

bryanedds commented 11 months ago

We could also consider giving lights contact shadows if ESM makes things look too floaty.

bryanedds commented 4 months ago

We probably need to prioritize the following features, only one of which are on the current roadmap -

bryanedds commented 2 months ago

There are .NET bindings for an OpenGL-based fork of FSR2 -

https://github.com/BoyBaykiller/FidelityFX-FSR2-CSharpBindings/

(OpenGL-based fork of FSR2 here - tho there seem to be some unresolved performance problems...)

https://github.com/JuanDiegoMontoya/FidelityFX-FSR2-OpenGL/

Tho ideally FSR3 would be better to use than FSR2. However, it may not be worth taking a dependency on either one and so we might instead implement a TAA ourselves.