[4] Goals and Limits of the Project


Goals and Limits of the Project

Certainly, developing a 3D engine is a complex endeavor. It is crucial to set realistic goals to maintain motivation and have a target that can be achieved. Therefore, the goals and limits of the new project are firmly defined and can be expanded later, but for now, they are set.

The use of the engine should, as with previous versions, enable easy handling. Rendering primitives should be straightforward. It should be possible to use lighting and textures. Positioning, rotating, and scaling of 3D objects should be implemented, and basic knowledge in C should suffice to work with the engine. What I cannot implement are additional functionalities such as physics simulation, particle effects, or network support.

Initialization Process is the First Step

The initialization process is the first step in implementing my 3D engine. It involves making the best possible adapter selection, in other words, the graphics card. Now, some may say there is only one graphics card in the system... Why do I need to choose?

Well, it's because the graphics card also plays a role in supported resolutions or graphics features. It can be important – no, it is important – to know what the graphics card can do. Therefore, the first step is to determine which graphics card is in the system, the number of connected monitors, and their capabilities regarding resolution and refresh rate.

A fundamental understanding of how we could proceed is crucial. That's why I've already given some thought to how to do this in DirectX11.

First, we need to initialize DirectX to access the graphics hardware. This involves creating a device context and establishing a swap chain for outputting to the screen.

Using the DirectX API, we can then query various information about the graphics card, such as its name, manufacturer, and capabilities. We can use functions like D3D11CreateDevice and IDXGIFactory::EnumAdapters to determine these details.

An important step is also checking the supported features. Here, we can query the supported feature levels provided by ID3D11Device::CheckFeatureSupport.

To find out the actual capabilities of the graphics card, we need to determine the supported resolutions and refresh rates. This is done by using functions like IDXGIOutput::GetDisplayModeList to retrieve a list of supported display modes for each connected monitor.

Based on this information, we can finally tailor our 3D engine to the hardware to achieve the best possible performance. This includes selecting appropriate resources such as texture resolutions and adjusting rendering options according to the capabilities of the graphics card.

Well, that's certainly a start, but it would be somewhat monotonous to just program without any creativity. The question is, how do we organize all this best?

My approach was to store all this information in lists. Nested lists, to be precise. A list for the adapters. Each adapter has multiple connection options, so monitors. Each monitor, in turn, offers different resolutions, and each resolution has its own refresh rates.

I'm not sure if everyone realizes that it won't be easy. It requires a certain approach to keep everything organized and structured, and even after implementing all this, you still don't see anything on the screen.

For me personally, this is one of the greatest challenges: you type in heaps of code, invest a considerable amount of time, and yet the screen remains blank – not a single pixel appears.


Ziele und Grenzen des Projekts

Was eine 3D Engine jedoch sicherlich auch ist, ist, dass sie aufwendig zu entwickeln ist. Es ist sehr wichtig, sich realistische Ziele zu setzen, um die Motivation aufrechtzuerhalten und ein Ziel zu haben, das auch erreicht werden kann. Deshalb sind die Ziele und Grenzen des neuen Projekts fest definiert und können später erweitert werden, aber vorerst stehen sie fest.

Die Nutzung der Engine soll, wie bei den Vorgängerversionen, eine einfache Handhabung ermöglichen. Das Rendern von Primitiven sollte einfach sein. Es sollte möglich sein, Licht und Texturen zu verwenden. Positionieren, Rotieren und Skalieren von 3D-Objekten sollten umgesetzt werden, und einfache Kenntnisse in C sollten ausreichen, um mit der Engine arbeiten zu können. Was ich nicht umsetzen kann sind zusätzliche Funktionalitäten wie Physiksimulation, Partikeleffekte oder Netzwerkunterstützung.

Initialisierungsprozess ist der erste Schritt

Der Initialisierungsprozess ist der erste Schritt bei der Implementierung meiner 3D-Engine. Dabei geht es darum, die bestmögliche Adapterauswahl zu treffen, also vereinfacht gesagt, die Grafikkarte. Nun werden einige sagen, es gibt doch nur eine Grafikkarte im System... Warum muss ich da noch groß wählen?

Nun, es ist so, dass die Grafikkarte auch eine Rolle bei den unterstützten Auflösungen oder Grafikfunktionen spielt. Es kann wichtig sein – nein, es ist wichtig – zu wissen, was die Grafikkarte kann. Aus diesem Grund ist der erste Schritt, festzustellen, welche Grafikkarte sich im System befindet, die Anzahl der angeschlossenen Monitore und deren Fähigkeiten hinsichtlich Auflösung und Bildwiederholfrequenz.

Ein grundlegendes Verständnis davon, wie wir vorgehen könnten, ist entscheidend. Aus diesem Grund machte ich mir schon mal im Vorfeld Gedanken darüber wie man das in DirectX11 macht. 

Zunächst müssen wir DirectX initialisieren, um auf die Grafikhardware zugreifen zu können. Das bedeutet, einen Gerätekontext zu erstellen und einen Swap-Chains für die Ausgabe auf dem Bildschirm zu etablieren.

Mit Hilfe der DirectX-API können wir dann verschiedene Informationen über die Grafikkarte abfragen, wie ihren Namen, Hersteller und ihre Fähigkeiten. Wir können Funktionen wie D3D11CreateDevice und IDXGIFactory::EnumAdapters verwenden, um diese Details zu ermitteln.

Ein wichtiger Schritt ist auch die Überprüfung der unterstützten Funktionen. Hier können wir die unterstützten Feature-Level abfragen, die von ID3D11Device::CheckFeatureSupport bereitgestellt werden.

Um die tatsächlichen Fähigkeiten der Grafikkarte herauszufinden, müssen wir die unterstützten Auflösungen und Bildwiederholfrequenzen ermitteln. Dies erfolgt durch die Verwendung von Funktionen wie IDXGIOutput::GetDisplayModeList, um eine Liste der unterstützten Anzeigemodi für jeden angeschlossenen Monitor abzurufen.

Basierend auf diesen Informationen können wir schließlich unsere 3D-Engine an die Hardware anpassen, um die bestmögliche Leistung zu erzielen. Dazu gehört die Auswahl geeigneter Ressourcen wie Texturauflösungen und die Anpassung von Rendering-Optionen entsprechend den Fähigkeiten der Grafikkarte.

Nun, das ist sicherlich ein Anfang, aber es wäre doch etwas eintönig, einfach so drauflos zu programmieren. Wir sollten unserem Code etwas mehr Fantasie einhauchen. Die Frage ist, wie organisieren wir das alles am besten?

Mein Ansatz war, all diese Informationen in Listen zu speichern. Verschachtelte Listen, um genau zu sein. Eine Liste für die Adapter. Jeder Adapter hat mehrere Anschlussmöglichkeiten, also Monitore. Jeder Monitor wiederum bietet verschiedene Auflösungen, und jede Auflösung hat ihre eigenen Bildwiederholfrequenzen.

Ich bin mir nicht sicher, ob jedem klar wird, dass es nicht einfach sein wird. Es erfordert eine gewisse Herangehensweise, um alles organisiert und strukturiert zu halten und nach dem man das alles implementiert hat, sieht man immer noch Nichts auf dem Bildschirm. 

Für mich persönlich ist dies eine der größten Herausforderungen: Man tippt Unmengen an Code ein, investiert eine beträchtliche Zeit, und dennoch bleibt der Bildschirm leer – kein einziger Pixel erscheint.

Leave a comment

Log in with itch.io to leave a comment.