GAME JOBS
Contents
Tutorial: Simple, High-Performance Particles for Mobile
 
 
Printer-Friendly VersionPrinter-Friendly Version
 
Latest Jobs
spacer View All     Post a Job     RSS spacer
 
June 6, 2013
 
Red Storm Entertainment, a Ubisoft Studio
Assistant/Associate Producer
 
Wargaming.net
Build Engineer
 
Gameloft - New York
Programmer
 
Wargaming.net
Build Engineer
 
Virdyne Technologies
Unity Programmer
 
Wargaming.net
Dev-Ops Engineer
spacer
Latest Blogs
spacer View All     Post     RSS spacer
 
June 6, 2013
 
Free to Play: A Call for Games Lacking Challenge
 
Cracking the Touchscreen Code [1]
 
10 Business Law and Tax Law Steps to Improve the Chance of Crowdfunding Success
 
Deep Plaid Games, one year later
 
The Competition of Sportsmanship in Online Games
spacer
About
spacer Editor-In-Chief:
Kris Graft
Blog Director:
Christian Nutt
Senior Contributing Editor:
Brandon Sheffield
News Editors:
Mike Rose, Kris Ligman
Editors-At-Large:
Leigh Alexander, Chris Morris
Advertising:
Jennifer Sulik
Recruitment:
Gina Gross
Education:
Gillian Crowley
 
Contact Gamasutra
 
Report a Problem
 
Submit News
 
Comment Guidelines
 
Blogging Guidelines
Sponsor
Features
  Tutorial: Simple, High-Performance Particles for Mobile
by Itay Duvdevani [Production, Interview, Console/PC]
4 comments Share on Twitter Share on Facebook RSS
 
 
May 20, 2013 Article Start Previous Page 2 of 4 Next
 

Blend Modes

For our effects to look right, we need to use the appropriate blend mode. I'll focus on OpenGL, but everything stated here holds for DirectX or any other low-level 3D API.

The last stage of the OpenGL 1 pipeline is to combine the current color at the pixel buffer with the color of the incoming fragment. The examples for glBlendFunc in OpenGL ES 1.1 docs states that:



Transparency is best implemented using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) with primitives sorted from farthest to nearest.

This is unfortunate, as compositing images with this blend mode is limited and error prone. (Working naïvely with this blend mode might cause dark halos around objects)

Consider a pixel represented by: (Rs,Gs,Bs,As) which we would like to blend with the existing pixel: (Rd,Gd,Bd,Ad) where each pixel component is in the [0,1] range.

OpenGL suggests the following blending: (using the red channel as an example)

Rout = As*Rs + (1-As)*Rd

Notice that all components are always lower than or equals to one -- We cannot lighten the scene, only darken it. This blending mode is good for occluding (see the world through pink glasses), but cannot be used to lighten a scene.

To illuminate (use a flashlight over something for example), we might have chosen to do:

glBlendFunc(GL_SRC_ALPHA, GL_ONE)

That blends as follows:

Rout = As*Rs + Rd

Where we only add light to scene and control the amount of light added with the source's alpha channel. However, again, as all components are always non-negative we can only lighten the scene, disallowing occlusion.

To accommodate for both needs, Porter & Duff in a 1984 paper (Computer Graphics Volume 18, Number 3 July 1984 pp 253-259) suggest using:

Rout = Rs + (1-As)*Rd

or:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

That allows us achieve both occlusion and illumination:

  • Occlusion is achieved by premultiplying the RGB channels with the alpha channel: Rs=Rs*As for every pixel in the original texture. This makes the above method identical to the method suggested in the OpenGL docs, and saves a runtime multiplication.
  • Illumination is achieved by not premultiplying the texture, and using the alpha channel as the amount of light to add to the scene

A picture is worth a thousand words. In the following example both particles are rendered with the same alpha channel (shown on the right) in the same blend mode (mentioned at the bottom). Notice how we're able to achieve smooth occlusion on the right particle, while being able to lighten the background on the circumference of the left particle:

If I would have had to guess why OpenGL authors chose the less useful blending equation as their example, I would guess that it's because most (if not all) graphic editors don't premultiply alpha, and this is the correct way to achieve the expected particle (on the right). 

 
Article Start Previous Page 2 of 4 Next
 
Top Stories

image
Keeping the simulation dream alive
image
Q&A: With Neverwinter inbound, Cryptic founds Seattle studio
image
A 15-year-old critique of the game industry that's still relevant today
image
Advanced audio streaming in Unity
Comments

Nick Ralabate
profile image
What exactly do you mean by each particle's ADD mask? I stared at the example image for a minute, and the edges look about the same softness to me.

Itay Duvdevani
profile image
This can be confusion - I'll try to explain better.

What I meant is that in the ignition stage we've softened the edged of the RGB channel not because we've premultiplied it with the alpha channel (which is all black) - but because we don't want our addition mask to be "sharp".

If we were to set the addition mask (RGB channel) to a single color, we would get a sharp transition on the flame's edge, instead of a soft one - this is different than the third (smoke) particle, which is premultiplied - in the ignition we want to "add less and less" around the edges while in the smoke we want normal occlusion blending.

Tom Hughes
profile image
Super interesting tutorial! I'm going to try it out as soon as I get home from work

Romain Guy
profile image
Just a quick note about Android: the behavior you ran into with premultiplied textures is because all bitmaps are always loaded premultiplied by the platform. It is definitely a problem for games, and not only for the reasons you mentioned here (if you use the 4 ARGB channels and need the RGB data to remain intact – say if you're storing normals for instance –). It's something I would like to fix at some point though. In the meantime, sorry about the inconvenience :)


none
 
Comment:
 




UBM Tech