Tutorial 8 – Particle Systems; Deferred Particle Rendering

Tutorial 8 demonstriert die Animation von Partikelsystemen sowie die Partikeldarstellung unter Verwendung von Geometry Instancing im Rahmen des Post-Processings (Deferred Particle Rendering).










Vorteil gegenüber der klassischen Partikeldarstellung:

Für die Realisierung der diversen Post-Processing-Effekte werden unter anderem auch die Tiefenwerte der 3D-Szene aus Sicht der Kamera benötigt.
Dank dieser Tiefenwerte lassen sich transparente Objekte wie Partikel problemlos nachträglich (in einem zweiten Renderdurchgang) in die Szene integrieren – durch einfache Tiefenvergleiche lässt sich feststellen, an welchen Stellen die Partikel durch die nicht transparente Szenengeometrie verdeckt werden.




Schritt 1: Initialisierungsarbeiten

// Physiksystem initialisieren:
PhysicalSimulationParameter = new CPhysicalSimulationParameter;
PhysicalSimulationParameter->Init_PhysicalSimulationParameter(
                             "../Physics/SimulationParameter.txt");

// Partikel-Grafikmanager initialisieren:
ParticleGraphicsManager = new CParticleGraphicsManager;
ParticleGraphicsManager->Init_ParticleGraphicsManager(
                         "../Particles/Particles.txt",
                         "../Particles/Textures/",
                         "../Particles/Meshes/", 2000);

// Partikel-Shader laden.
Um die Anzahl der Draw Calls zu minimieren,
// werden die Partikel unter Verwendung von Geometry Instancing gerendert.
ParticleShader = new CGLSLShader;

// g_MaxParticleInstances speichert die Anzahl der Partikel, die pro
// Draw Call gerendert werden sollen.
// Der verwendete Wert wird aus der Datei Particles.txt ausgelesen.
if(g_MaxParticleInstances == 16)
    ParticleShader->Init_UserDefined_Shader(
              "Shader/Particle_16Instances.vert", "Shader/Particle.frag",
              Format_CSimpleTexturedVertex);
else if(g_MaxParticleInstances == 32)
    ParticleShader->Init_UserDefined_Shader(
              "Shader/Particle_32Instances.vert", "Shader/Particle.frag",
              Format_CSimpleTexturedVertex);
[...]

else if(g_MaxParticleInstances == 512)
    ParticleShader->Init_UserDefined_Shader(
              "Shader/Particle_512Instances.vert", "Shader/Particle.frag",
              Format_CSimpleTexturedVertex);

// Uniform-Buffer-Objekt für das Partikel-Geometry-Instancing
// initialisieren:
ParticleGraphicsManager->Init_ParticleInstanceManager(ParticleShader);
ParticleGraphicsManager->Bind_ParticleDataUniformBuffer(1);
ParticleGraphicsManager->Bind_ParticleDataUniformBlock(ParticleShader);

// Partikelsysteme initialisieren.
Die Beschreibung der Systeme findet sich
// in der Datei Particles.txt:
TestCompoundParticleSystem1 = new CCompoundParticleSystem;
TestCompoundParticleSystem1->Init_CompoundParticleSystem(
                             ParticleGraphicsManager, 0, 100.0f);

TestCompoundParticleSystem2 = new CCompoundParticleSystem;
TestCompoundParticleSystem2->Init_CompoundParticleSystem(
                             ParticleGraphicsManager, 1, 100.0f);

ParticleTrailDirection = D3DXVECTOR3(1.0f, 1.0f, -1.0f);
D3DXVec3Normalize(&ParticleTrailDirection, &ParticleTrailDirection);


Schritt 2: Partikelsysteme aktivieren/deaktivieren

// falls notwendig, Partikelsystem aktivieren:
// Der Aufruf der Activate_CompoundParticleSystem-Methode wirkt sich nur
// auf nicht aktivierte Partikelsystem aus!!
TestCompoundParticleSystem1->Activate_CompoundParticleSystem(
                             &TestModel_WorldSpacePosition,
                             &g_NullVector);

TestCompoundParticleSystem2->Activate_CompoundParticleSystem(
                             &TestModel_WorldSpacePosition,
                             &ParticleTrailDirection);


// Partikelsysteme deaktivieren:
TestCompoundParticleSystem1->Deactivate_CompoundParticleSystem();
TestCompoundParticleSystem2->Deactivate_CompoundParticleSystem();


Schritt 3: Partikelsysteme updaten

// Für die Partikelsimulation genügt eine Schrittlänge, die der FrameTime
// entspricht!!
Der Schrittweiten-Wert (timeStep), welcher der
// nachfolgenden Funktion übergeben wird,
findet bei der Partikelsimulation
// daher keine Berücksichtigung!!!
PhysicalSimulationParameter->Calculate_NumTimeSteps(g_FrameTime,
                                                    0.25f*g_FrameTime);

ParticleGraphicsManager->Reset_VisibleParticles();

TestCompoundParticleSystem1->Update_CompoundParticleSystem(NULL, NULL,
                             NULL, PhysicalSimulationParameter);

TestCompoundParticleSystem1->Calculate_ParticleCameraSpacePositions_
                             Check_Visibility_And_
                             Update_ParticleRenderProperties(
                             &g_CameraViewDirection, &g_CameraPosition);

TestCompoundParticleSystem1->Calculate_ShaderTransformationMatrices_
                             Of_VisibleParticles(&g_ViewProjectionMatrix,
                             true, true, true, true);

// Sofern Partikel kontinuierlich von einem Emitter  emittiert warden
// sollen (Particle Trails) und sich die Emittereigenschaften (Position und
// Ausrichtung) ändern, müssen diese der Update_CompoundParticleSystem()
// neu übergeben werden!!
TestCompoundParticleSystem2->Update_CompoundParticleSystem(
                             &TestModel_WorldSpacePosition,
                             &ParticleTrailDirection, NULL,
                             PhysicalSimulationParameter);

TestCompoundParticleSystem2->Calculate_ParticleCameraSpacePositions_
                            Check_Visibility_And_
                            Update_ParticleRenderProperties(
                            &g_CameraViewDirection, &g_CameraPosition);

TestCompoundParticleSystem2->Calculate_ShaderTransformationMatrices_
                             Of_VisibleParticles(&g_ViewProjectionMatrix,
                             true, true, true, true);

TestCompoundParticleSystem1->Update_RenderData(true, true, true);
TestCompoundParticleSystem2->Update_RenderData(true, true, true);

ParticleGraphicsManager->Prepare_Rendering();


Schritt 4: Partikelsysteme rendern

PostProcessingEffects->Continue_SceneRendering(RM_ScreenSpaceLighting);

// hier die nicht transparente Szenengeometrie rendern

PostProcessingEffects->Stop_SceneRendering();


// nicht transparente Szenengeometrie beleuchten:
PostProcessingEffects->Calculate_ScreenSpaceLighting(
                       &g_CameraViewDirection);

PostProcessingEffects->Begin_SecondarySceneRendering(
                       &g_BackgroundScreenColor);

// Partikel in die zweite Screen-Textur rendern (notwendig für die
// Darstellung der
Flimmer- und Unschärfe-Effekte):

ParticleGraphicsManager->Render_All_VisibleParticles(ParticleShader,
                PostProcessingEffects->SceneCameraSpacePosAndDepthTexture);

PostProcessingEffects->Stop_SecondarySceneRendering();

// Spezialeffekte (Flimmern und Unschärfe) berechnen:
PostProcessingEffects->Combine_Primary_And_Secondary_ScreenTextures(
             &D3DXVECTOR4(frnd(g_MinGlowDistortionX, g_MaxGlowDistortionX),
                          frnd(g_MinGlowDistortionY, g_MaxGlowDistortionY),
                          g_GlowDistortionInvWavelength,
                          g_GlowDistortionFrequency*GetTickCount()));

PostProcessingEffects->Render_PrimaryScreenQuad(g_HDRExposure,
                       g_HDRBrightnessMax, g_HDRBoomFactor,
                       g_HDRBlendRangeFactor, g_HDRInvIntensityFactor,
                       g_HDRMinLuminanceAdaption,
                       g_HDROverBlendingIntensity,
                       g_HDROverBlendingColorFactor,
                       g_HDROverBlendingOffset);

// In einem zweiten Renderdurchgang werden die transparenten Objekte
// dargestellt:
PostProcessingEffects->Prepare_SceneRendering(&g_BackgroundScreenColor);
PostProcessingEffects->Continue_SceneRendering(RM_SceneColorOnly);

ParticleGraphicsManager->Render_All_VisibleParticles(ParticleShader,
                PostProcessingEffects->SceneCameraSpacePosAndDepthTexture);

PostProcessingEffects->Stop_SceneRendering();

PostProcessingEffects->Calculate_SceneGlow(true,
                       g_HDRMinGlowingSamplingValue,
                       g_HDRBlendRangeFactor);
                       PostProcessingEffects->Calculate_Luminance();

PostProcessingEffects->Render_TransparentScreenQuad(false, true,
                       g_HDRExposure_TransparentObjects,
                       g_HDRBrightnessMax_TransparentObjects,
                       g_HDRBoomFactor_TransparentObjects,
                       g_HDRBlendRangeFactor_TransparentObjects,
                       g_HDRInvIntensityFactor_TransparentObjects,
                       g_HDRMinLuminanceAdaption_TransparentObjects,
                       g_HDROverBlendingIntensity_TransparentObjects,
                       g_HDROverBlendingColorFactor_TransparentObjects,
                       g_HDROverBlendingOffset_TransparentObjects);


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.