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);
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);
// 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();
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();
// 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);
// 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.