Tutorial 9 – Managed Rendering (Instancing)

Die Anzahl der benötigten Draw Calls (Renderaufrufe) hat entscheidenden Einfluss auf die Performance bei der Darstellung komplexer 3D-Szenen. Durch geschickten Einsatz von Geometry Instancing lässt sich diese Anzahl auf ein Minimum reduzieren. Die Tutorials 4 und 5 demonstrieren bereits den Einsatz dieser Technik.

Für einfache 3D-Objekte, die nur aus nur einem einzigen Modelteil (Mesh) bestehen, ist die Implementierung von Geometry Instancing recht einfach; für komplexere 3D-Objekte, die aus mehreren Modellteilen zusammengesetzt sind, wird das Ganze schon etwas schwieriger. In diesem Zusammenhang kommt nun der Rendering Manager zum Einsatz und übernimmt das Handling aller darzustellenden 3D-Objekte.
Um die Anzahl der notwendigen Draw Calls zu reduzieren, werden die Objekte nicht mehr nacheinander gerendert; stattdessen werden die einzelnen Modellteile (Submeshes) aller Instanzen, die das gleiche 3D-Modell verwenden, nacheinander mit nur einem einzigen Renderaufruf dargestellt:

Draw Call Schema für alle Instanzen, die das gleiche 3D-Modell verwenden:

  • Draw Call 1: Modelpart 1 (Instance 1, Instance 2, Instance 3, usw.)
  • Draw Call 2: Modelpart 2 (Instance 1, Instance 2, Instance 3, usw.)
  • Draw Call 3: Modelpart 3 (Instance 1, Instance 2, Instance 3, usw.)
  • usw. (für alle Teile eines 3D-Modells)



Schritt 1: Rendering Manager initialisieren

// Rendering Manager initialisieren:
RenderingManager = new CRenderingManager;

RenderingManager->Set_NumModelsMax(10);
RenderingManager->Set_NumSkeletalAnimatedModelsMax(10);

RenderingManager->Init_MeshInstanceManager(InstancedNormalMappingShader);
RenderingManager->Init_SkeletalAnimatedMeshInstanceManager(
                  InstancedSkeletalAnimatedNormalMappingShader, true);


Schritt 2: die darzustellenden 3D-Modelle an den Rendering Manager übergeben

// die zu rendernden 3D-Modelle übergeben (bis zu 64 Modell-Instanzen
// können pro Modell
an den Rendering Manager übergeben werden):
RenderingManager->Set_Model(TestModel1, 64);
RenderingManager->Set_Model(TestModel2, 64);
RenderingManager->Set_SkeletalAnimatedModel(SkeletalAnimatedTestModel1,
                                            64);


Schritt 3: verwendete Shader an den Rendering Manager binden

// Shader-Zugriff auf die in den Uniform-Buffer-Objekten gespeicherten
// Daten gewährleisten
RenderingManager->Bind_MeshDataUniformBuffer(0);
RenderingManager->Bind_MeshDataUniformBlock(InstancedNormalMappingShader);
RenderingManager->Bind_SkeletalAnimatedMeshDataUniformBuffers(1, 2, 3);
RenderingManager->Bind_SkeletalAnimatedMeshDataUniformBlocks(
                  InstancedSkeletalAnimatedNormalMappingShader, true);


Schritt 4: Rendering Manager für die Datenaufnahme vorbereiten

RenderingManager->Reset_All_ModelInstances();
RenderingManager->Reset_All_SkeletalAnimatedModelInstances();


Schritt 5: Modell-Instanzen an den Rendering Manager übergeben

RenderingManager->Set_ModelInstance_For_Rendering(&TestModelInstance[0]);
RenderingManager->Set_ModelInstance_For_Rendering(&TestModelInstance[1]);

[...]

RenderingManager->Set_SkeletalAnimatedModelInstance_For_Rendering(
                  &TestModelInstance[8]);
RenderingManager->Set_SkeletalAnimatedModelInstance_For_Rendering(
                  &TestModelInstance[9]);

[...]


Schritt 6: Renderfunktionen aufrufen

InstancedNormalMappingShader->Use_Shader();

Render_ManagedModels(&g_CameraPosition, &g_ViewProjectionMatrix,
                     RenderingManager, InstancedNormalMappingShader,
                     1.0f, 0);

InstancedNormalMappingShader->Stop_Using_Shader();


InstancedSkeletalAnimatedNormalMappingShader->Use_Shader();

Render_ManagedSkeletalAnimatedModels(&g_CameraPosition,
                     &g_ViewProjectionMatrix, RenderingManager,
                     InstancedSkeletalAnimatedNormalMappingShader, 0.1f, 0,
                     SkeletalAnimatedBody->JointTotalTransformationMatrix,
                     SkeletalAnimatedBody->NumJoints);

InstancedSkeletalAnimatedNormalMappingShader->Stop_Using_Shader();



Hinweise zum Erstellen eines neuen Projekts:

  • Kopieren Sie den Ordner GraphicsAndPhysicsFrameworkImports ins Projektverzeichnis
  • Kopieren sie alle dll-Dateien sowie die Konfigurationsdatei ResolutionAndRendering.txt aus besagtem Ordner ins gleiche Verzeichnis, in dem sich auch die exe-Datei befindet (in unseren Programmbeispielen ist dies das Bin-Verzeichnis)
  • Binden Sie die folgenden Dateien in Ihr Projekt ein: GraphicsAndPhysics_Framework_Imports.h, GraphicsAndPhysics_Framework_Imports.lib, glew32.lib, glew32s.lib, glut32.lib. Die Glew- und Glut-Bibliotheken ermöglichen die Nutzung der aktuellen OpenGL-Spezifikationen unabhängig vom Framework.