jump to navigation

Smoothing and changing point sizes in WebGL May 6, 2010

Posted by Andor Saga in Open Source, Processing.js, webgl.
trackback

If you have a WebGL-enabled browser you can check out my demo.

If you want to download a WebGL browser, you can get either Minefield, Webkit or Chromium.

So, while working on the Processing.JS project, I ran into an interesting bug. The Processing language provides a way to change the size of 3D points. Processing is Java-based and uses OpenGL to do the rendering. Processing.JS is a JavaScript port of the language and since WebGL is used to render points, all 3D functions eventually call some form of WebGL command.

So if you’re also writing a WebGL script which changes point sizes, keep reading.

To change the size of points you would typically do two things. First you’ll need to enable VERTEX_PROGRAM_POINT_SIZE.

ctx.enable(ctx.VERTEX_PROGRAM_POINT_SIZE);

Next, you need to set the point size. This is done in the vertex shader. You’ll probably want to do this with a uniform or attribute variable to allow different sizes.

attribute vec3 Vertex;
uniform mat4 MVP;
uniform float pointSize;

void main(void){
  gl_PointSize = pointSize;
  gl_Position = MVP * vec4(Vertex, 1.0);
}

This works in WebKit, but if you try it in Minefield, it will fail. Your points will be stuck to the size of 1 pixel. The way around this is to use the literal value of VERTEX_PROGRAM_POINT_SIZE, which is defined in OpenGL as 0x8642. Using the literal is probably a better way to ensure cross-compatibility. You may even want to define your own JavaScript variable for this.

Your cross-browser compatible code that enables point size changes becomes:

ctx.enable(0x8642); 

Done! Unless you want your points smoothed (rendered as circles rather than squares). Again, Minefield has issues with this. Instead of calling:

ctx.enable(ctx.POINT_SMOOTH);

You’ll need to call:

ctx.enable(0x0B10);

Interestingly Webkit renders smoothed points by default whereas Minefield renders non-smoothed points by default. Also, Minefield renders shimmering outlines on smoothed points while Webkit doesn’t. Try the demo and you’ll see.

Advertisements

Comments»

1. Tweets that mention Smoothing and changing point sizes in WebGL « Andor Salga -- Topsy.com - May 7, 2010

[…] This post was mentioned on Twitter by Paul Brunt, Andor Salga and Andor Salga, rita turkowski. rita turkowski said: http://asalga.wordpress.com/2010/05/06/smoothing-and-changing-point-sizes-in-webgl/ […]

2. WebGL around the net, 7 May 2010 | Learning WebGL - May 7, 2010

[…] Andor Salga has created a nice particle demo with Processing.js and has discovered that not only do you need to put gl.enable(0x8642) in your initialisation code […]

3. Nicolas - September 1, 2010

Excellent article, thanks for the tips 🙂

BTW, the code of the demo is not compiling in minefield 4.0b5pre: (Mozilla/5.0 (Windows NT 5.1; rv:2.0b5pre) Gecko/20100830 Firefox/4.0b5pre)

The errors I’m getting are:

Error: uncaught exception: ERROR: 0:1: ‘gl_FrontColor’ : undeclared identifier
ERROR: 0:1: ‘assign’ : cannot convert from ‘uniform mediump 4-component vector of float’ to ‘float’
ERROR: 2 compilation errors. No code generated.

4. Andor Salga - September 2, 2010

Hi Nicolas,
Since this article Minefield no longer allows this hack for smoothing. I suspect other browsers are following suite. So you no longer need those ‘enable’ calls.

The errors you’re seeing are due to out of date shaders. You’ll need to change your vertex shader to look something like this:

attribute vec3 aVertex;
uniform mat4 MVP;
uniform float pointSize;
varying vec4 frontColor;
attribute vec4 aColor;

void main(void){
  frontColor = aColor;
  gl_PointSize = pointSize;
  gl_Position = MVP * vec4(aVertex, 1.0);
}

And your fragment shader should look like:

#ifdef GL_ES
precision highp float;
#endif

varying vec4 frontColor;

void main(void){
  gl_FragColor = frontColor;
}

Hope that helps!

Andy - June 25, 2012

Here is the code as above but bugs fixed, so it works in Processing, if anyone wants to try it out in the program:


import processing.opengl.*;

class Particle{
float xPos, yPos, zPos;
float xVel, yVel, zVel;
float age;
float lifeTime;
float opacity;
float size;

Particle(){
xPos = 0;
yPos = 0;
zPos = 0;
xVel = 1.4;
yVel = 1.2;
zVel = 2.0;
age = 0;
lifeTime = 0;
opacity = 255;
size = 20;
}

float getAge(){return age;}
float getLifeTime(){return lifeTime;}
float getX(){return xPos;}
float getY(){return yPos;}
float getZ(){return zPos;}

void setAge(int a){age = a;}

void setX(float x){xPos = x;}
void setY(float y){yPos = y;}
void setZ(float z){zPos = z;}

void setXVelocity(float x){xVel = x;}
void setYVelocity(float y){yVel = y;}
void setZVelocity(float z){zVel = z;}

void setLifeTime(float l){lifeTime = l;}

void reset(){
opacity = 255;
size = 20;
}

void update(){
age += 0.1; //fix

yVel += 0.1;

xPos += xVel;
yPos += yVel;
zPos += zVel;

opacity = 255 - 250*(age/lifeTime);
size = 20 - 20*(age/lifeTime);
}

void draw(){
strokeWeight(size);
stroke(opacity-50, 0, 255-opacity,opacity/3);
point(xPos,yPos,zPos);
}
}

int NUM_PARTICLES = 500;

class ParticleSystem{
ArrayList p;

ParticleSystem(){
p = new ArrayList();
for(int i = 0; i < NUM_PARTICLES; i++){
Particle particle = new Particle();
p.add(particle);
resetParticle(i);
}
}

void resetParticle(int i){
Particle p1 = (Particle)p.get(i);
p1.reset();
p1.setX(mouseX);
p1.setY(mouseY);
p1.setZ(0);
p1.setXVelocity(random(0,2));
p1.setYVelocity(random(0,2));
p1.setLifeTime(random(1,15));
p1.setAge(0);
}

void update(){
for(int i=0; i p1.getLifeTime()){
resetParticle(i);
}
}
}

void draw(){
for(int i=0; i < NUM_PARTICLES; i++){
Particle p1 = (Particle)p.get(i);
p1.draw();
}
}
}

ParticleSystem psys;

void setup(){
size(500,500,OPENGL);
psys = new ParticleSystem();
}

void draw(){
background(0);
stroke(255);
psys.update();
psys.draw();
}


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: