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

  1. Entry pointSampleGame/Program.csstatic void Main(string[] args).
  2. Main instantiates SampleGame (in SampleGame/SampleGame.csproj) which: Loads the .obj model via ObjLoader.Load("monkey.obj") (3dEngine/StaticClass/ObjLoader.cs). Creates a Camera (3dEngine/Implementation/Camera.cs) implementing ICamera. Registers a DisplaysManagerAsync (3dEngine/Implementation/DisplaysManager.cs) that owns a ConsoleScreenAsync (3dEngine/Implementation/ConsoleScreenAsync.cs). Starts NetworkManager (3dEngine/Network/NetworkManager.cs) which opens a TCP listener and registers packet types (ChatPacket.cs, TransformPacket.cs).
  3. The main loop lives in SampleGame/Program.cswhile (!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)RenderAsync in ConsoleScreenAsync.cs spreads pixel work with Parallel.For, computes ray‑scene intersections, lighting, and writes to the console buffer.
  4. Network flowNetworkManager receives raw bytes, hands them to PacketManager.Deserialize (3dEngine/Network/PacketManager.cs), which uses type‑hash IDs to invoke the appropriate handler (e.g., ChatPacket updates UI via UIManager.cs). Outbound packets are serialized the same way and sent over the same TCP socket.
  5. OutputConsoleScreenAsync writes the final buffer using Console.Write calls; duplicated buffer‑flush logic appears across Screen.cs, ConsoleScreenAsync.cs, DisplayManagerAsync.cs, and the IDisplaysManagerAsync interface (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.cs contain 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, and IDisplaysManagerAsync.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 (LICENSE GPL‑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.