The Problem
Developers who want to explore 3‑D rendering concepts without pulling in heavyweight graphics APIs must still write a lot of boilerplate (vector math, ray‑intersection, input handling, networking). That effort is duplicated across tutorials and small demos, making it hard to focus on the core algorithms.
What This Does
Neo3dEngine is a self‑contained, CPU‑only 3‑D engine that runs inside a system console. The core renderer lives in 3dEngine/Implementation/ConsoleScreenAsync.cs and 3dEngine/Implementation/DisplayManagerAsync.cs, which drive a pixel‑buffer, map brightness to a character gradient, and output via the console API.
Geometry is defined in 3dEngine/Shape/*.cs (e.g., Sphere.cs, Triangle.cs) and intersected by the Ray struct in 3dEngine/Structure/Ray.cs using the Möller‑Trumbore algorithm. Lighting, shadow rays and attenuation are calculated in 3dEngine/AbstractClass/Light.cs and 3dEngine/AbstractClass/Scene.cs.
An .obj loader (ObjLoader.cs) parses model files (e.g., SampleGame/monkey.obj). Input abstraction lives under 3dEngine/Inputs/ with platform‑specific providers (User32InputProvider.cs, LibX11InputProvider.cs, DotNetInputProvider.cs). Multiplayer is handled by 3dEngine/Network/NetworkManager.cs and packet helpers.
The sample application in SampleGame/Program.cs wires all pieces together, creates a scene, starts the render loop and opens a TCP chat channel.
How It Is Wired
- Entry point –
SampleGame/Program.cs→static void Main(string[] args). MaininstantiatesSampleGame(inSampleGame/SampleGame.csproj) which: Loads the.objmodel viaObjLoader.Load("monkey.obj")(3dEngine/StaticClass/ObjLoader.cs). Creates aCamera(3dEngine/Implementation/Camera.cs) implementingICamera. Registers aDisplaysManagerAsync(3dEngine/Implementation/DisplaysManager.cs) that owns aConsoleScreenAsync(3dEngine/Implementation/ConsoleScreenAsync.cs). StartsNetworkManager(3dEngine/Network/NetworkManager.cs) which opens a TCP listener and registers packet types (ChatPacket.cs,TransformPacket.cs).- The main loop lives in
SampleGame/Program.cs→while (!cancellationToken.IsCancellationRequested). Each iteration calls:inputProvider.Poll()(3dEngine/Inputs/Input.cs) – deep‑nested logic (max indent 8).scene.Update(delta)(3dEngine/AbstractClass/Scene.cs). *displayManager.RenderAsync(scene, camera)–RenderAsyncinConsoleScreenAsync.csspreads pixel work withParallel.For, computes ray‑scene intersections, lighting, and writes to the console buffer. - Network flow –
NetworkManagerreceives raw bytes, hands them toPacketManager.Deserialize(3dEngine/Network/PacketManager.cs), which uses type‑hash IDs to invoke the appropriate handler (e.g.,ChatPacketupdates UI viaUIManager.cs). Outbound packets are serialized the same way and sent over the same TCP socket. - Output –
ConsoleScreenAsyncwrites the final buffer usingConsole.Writecalls; duplicated buffer‑flush logic appears acrossScreen.cs,ConsoleScreenAsync.cs,DisplayManagerAsync.cs, and theIDisplaysManagerAsyncinterface (33 identical 6‑line blocks).
No circular module dependencies were detected; the import graph is flat (0 internal edges). The widest blast radius is the rendering pipeline (ConsoleScreenAsync.cs), because any change there touches the buffer logic, parallel loop, lighting calculations, and the duplicated helper blocks.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/Neo3dEngine
cd Neo3dEngine
# Build with .NET 8 SDK
dotnet build 3dEngine.sln
# Run the sample console game
dotnet run --project SampleGame/SampleGame.csproj
No additional configuration files or environment variables are required. The engine auto‑detects console size on start‑up (logic in GameTime.cs and Screen.cs).
If you need a different input provider, replace the concrete class instantiated in SampleGame/Program.cs (e.g., switch User32InputProvider to LibX11InputProvider).
Real‑World Use
A teaching assistant could embed the engine in a lab assignment: students replace the ObjLoader call with their own geometry, modify Light parameters, and observe the effect in real time without installing OpenGL or DirectX. The TCP chat module can be repurposed to synchronize simple state (e.g., player positions) across multiple console windows for a low‑overhead multiplayer demo.
Code Health & Issues
- HIGH – Cognitive load – Files
LibX11InputProvider.cs,Input.cs,ObjLoader.cscontain nesting depth of 8, making the control flow difficult to follow. - HIGH – Duplicated code – Identical 6‑line blocks appear in
Screen.cs,ConsoleScreenAsync.cs,DisplayManagerAsync.cs, andIDisplaysManagerAsync.cs(33 repetitions). - HIGH – No test suite – 42 source files, zero test files.
- HIGH – No CI pipeline – No GitHub Actions or other automation defined.
- Repo hygiene – License present (
LICENSEGPL‑3.0); no Dockerfile, lockfile, or committed secrets.
The Bottom Line
Neo3dEngine delivers a complete, console‑only 3‑D pipeline that is valuable for education and rapid prototyping of ray‑tracing concepts. The codebase is functional but suffers from deep nesting, duplicated helpers, and a lack of automated testing/CI, which raises maintenance risk for production‑level use. It is best suited for learning environments or proof‑of‑concept projects where the trade‑off of simplicity versus robustness is acceptable.