-
Notifications
You must be signed in to change notification settings - Fork 0
3D Particle Effects
Because of issues with perspective and depth, the 2D particle effects are not suitable for 3D applications. Additionally, the 3d particle effects take full advantage of movement through 3d space, allowing a wide variety of dynamic graphical effects.
Much like their 2D cousins, 3D particle effects can be edited with a GUI editor included in libgdx. The editor is called Flame, and is located in the non-core gdx-tools.jar. If you have a clone of the libgdx repo, you can run the editor by using the following command from the dist directory:
Linux/Mac:
java -cp gdx.jar:gdx-natives.jar:gdx-backend-lwjgl.jar:gdx-backend-lwjgl-natives.jar:extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.flame.FlameMain
Windows:
java -cp gdx.jar;gdx-natives.jar;gdx-backend-lwjgl.jar;gdx-backend-lwjgl-natives.jar;extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.flame.FlameMain
There are 3 different kinds of 3D particle effects:
- Billboards
- PointSprites
- ModelInstance
- ??TODO: ParticleController??
Billboards are sprites that always face the camera (the Decal class in libgdx is essentially a billboard)
PointSprites are simpler (more efficient, better performance) than billboards. They are colored points with no textures. The dust and explosion effects in the following video are done with PointSprites:
ModelInstances are familiar to you if you have done any 3D work in libgdx. They are instances of 3D models. Not surprisingly, this is the most taxing type of particle effect in terms of performance.
The easiest way to use 3D particle effects is by taking advantage of the ParticleSystem class, abstracting away various details and managing them for you. First we will create the batch of the type(s) we wish to use, then create the ParticleSystem. In this case, we are going to use PointSprites
For a more in depth look at how to use 3d particles programattically, take a look at the test class:
IMPORTANT: When you import the ParticleEffect class into your IDE, make sure you do not accidentally import the 2D effect ParticleEffect class. They share the same name, but have different import paths. You are looking for: com.badlogic.gdx.graphics.g3d.particles.ParticleEffect
// ParticleSystem is a singleton class, we get the instance instead of creating a new object:
ParticleSystem particleSystem = ParticleSystem.get();
PointSpriteParticleBatch pointSpriteBatch = new PointSpriteParticleBatch();
pointSpriteBatch.setCamera(cam);
particleSystem.add(pointSpriteBatch);
Now we need to load our particle effects that we have created using the Flame GUI editor. First, create a ParticleEffectLoadParameter to pass to the asset manager when loading. Then the assets may be loaded.
AssetManager assets = new AssetManager();
ParticleEffectLoader.ParticleEffectLoadParameter loadParam = new ParticleEffectLoader.ParticleEffectLoadParameter(particleSystem.getBatches());
ParticleEffectLoader loader = new ParticleEffectLoader(new InternalFileHandleResolver());
assets.setLoader(ParticleEffect.class, loader);
assets.load("particle/effect.pfx", ParticleEffect.class, loadParam);
assets.finishLoading()
ParticleEffect originalEffect = assets.get("particle/effect.pfx");
// we cannot use the originalEffect, we must make a copy each time we create new particle effect
ParticleEffect effect = originalEffect.copy();
effect.init();
effect.start(); // optional: particle will begin playing immediately
particleSystem.add(effect);
If you scroll back up and watch the 3D Tank Battle video, you will see that each tank has its own dust effects. That means each tank has it's own copy of the effect inside the system. You really don't want to make a new copy of the particle effect each time you create an object or graphical effect that needs it. Instead, you should use Pool the effects to avoid new object creation. You can read more about Pooling in this wiki or the libgdx Pool class documentation.
Here is an example of a Pool:
private static class PFXPool extends Pool<ParticleEffect> {
private ParticleEffect sourceEffect;
public PFXPool(ParticleEffect sourceEffect) {
this.sourceEffect = sourceEffect;
}
@Override
public void free(ParticleEffect pfx) {
pfx.reset();
super.free(pfx);
}
@Override
protected ParticleEffect newObject() {
return sourceEffect.copy();
}
}
Note that we reset the particle when it is freed, not during obtain. This avoids a NullPointerException that occurs because of how the ParticleSystem works.
A ParticleSystem must update and draw its own components, then be passed to a ModelBatch instance to be rendered to the scene.
private void renderParticleEffects() {
particleSystem.update(); // technically not necessary for rendering
particleSystem.begin();
particleSystem.draw();
particleSystem.end();
modelBatch.render(particleSystem);
}
You can also translate and rotate the effect. Depending on how your engine works you might want to use a specific matrix that is reset to identity on changes or only add the delta transformation/rotation.
private void renderParticleEffects() {
targetMatrix.idt();
targetMatrix.translate(targetPos);
effect.setTransform(targetMatrix);
particleSystem.update(); // technically not necessary for rendering
particleSystem.begin();
particleSystem.draw();
particleSystem.end();
modelBatch.render(particleSystem);
}
or
private void renderParticleEffects() {
effect.translate(deltaPos);
particleSystem.update(); // technically not necessary for rendering
particleSystem.begin();
particleSystem.draw();
particleSystem.end();
modelBatch.render(particleSystem);
}
It is a little bit more complicated to do this in the 3D Particle System:
Emitter emitter = pfx.getControllers().first().emitter;
if (emitter instanceof RegularEmitter) {
RegularEmitter reg = (RegularEmitter) emitter;
reg.setEmissionMode(RegularEmitter.EmissionMode.EnabledUntilCycleEnd);
}
You can find a full working example at (https://drive.google.com/file/d/0BwiuGlZ9rT-bRm9zQlJHbzFCWWs/edit?usp=sharing)
The main class is core/sbourges/game/gdxtest/GdxTest.java
-
Developer's Guide
- Introduction
- Setting up your Development Environment (Eclipse, Intellij IDEA, NetBeans)
- Creating, Running, Debugging and Packaging your Project
- Working from Source
- The Application Framework
- A Simple Game
- File Handling
- Networking
- Preferences
- Input Handling
- Memory Management
- Audio
-
Graphics
- Configuration & Querying Graphics ??
- Fullscreen & VSync
- Continuous & Non-Continuous Rendering
- Clearing the Screen
- Take a Screenshot
- Profiling
- Viewports
- OpenGL ES Support * Configuration & Querying OpenGL ?? * Direct Access ?? * Utility Classes * Rendering Shapes * Textures & TextureRegions * Meshes * Shaders * Frame Buffer Objects
- 2D Graphics * SpriteBatch, TextureRegions, and Sprites * 2D Animation * Clipping, with the use of ScissorStack * Orthographic camera * Mapping Touch Coordinates ?? * NinePatches * Bitmap Fonts * Distance field fonts * Color Markup Language * Using TextureAtlases * Pixmaps * Packing Atlases Offline * Packing Atlases at Runtime * 2D Particle Effects * Tile Maps * scene2d * scene2d.ui * Table * Skin
- 3D Graphics * Quick Start * Models * Material and environment * ModelBatch * ModelBuilder, MeshBuilder and MeshPartBuilder * 3D animations and skinning * Importing Blender models in LibGDX * 3D Particle Effects * Perspective Camera ?? * Picking ??
- Managing Your Assets
- Internationalization and Localization
- Utilities
-
Math Utilities
- Interpolation
- Vectors, Matrices, Quaternions
- Circles, Planes, Rays, etc.
- Path interface & Splines
- Bounding Volumes ??
- Intersection & Overlap Testing ??
- Tools
- Extensions
- Artificial Intelligence * Message Handling * State Machine
- gdx-freetype
-
Physics
* Box2D
* Bullet Physics * [Setup](../Bullet Wrapper - Setup) * [Using the wrapper](../Bullet Wrapper - Using the wrapper) * [Using models](../Bullet Wrapper - Using models) * [Contact callbacks](../Bullet Wrapper - Contact callbacks) * [Custom classes](../Bullet Wrapper - Custom classes) * [Debugging](../Bullet Wrapper - Debugging)
- Using libgdx with other JVM languages
- Third Party Services
- Articles