Shaders are pretty hot.



I love how this rolls at 900fps on my crap nvidia gt 210. Brushing up on linear algebra is going to make me a god.

I am really blown away by how great this makes everything look, and how effortless it is. I love not having to compile once I get my C all settled.

nice!

if you’re enjoying the ‘don’t have to recompile’ thing, you might be interested in the fact that you can reload your shaders during runtime. so if you say shader.load() again while the code is running, it will update the shader.

if you’re just testing non-interactive glsl, and you’re running osx, check out the “OpenGL Shader Builder” that comes with xcode. it’s for live coding all kinds of shaders.

1 Like

this is also great fun : http://www.iquilezles.org/apps/shadertoy/

I actually woke up early today to test the live reloading of shaders. My interactive VJ software just got the number of lines of code it contains run through a sqrt() function.

I had been trying to shoehorn OpenCL and CUDA into OF trying to get the functionality of shaders.

Hi,

That’s nice. Do you care about sharing those shaders ?

Sebastien

I made a really rudimentary particle system and used that as a source for positions to do distance calculations and trig functions on the distance calculations

very ugly code, if my house looked like this code I would not have a woman over… do not judge.

  
  
#version 120  
precision highp float;  
  
#define NUMBER_OF_BOIDS 3  
  
uniform float time;  
uniform vec2 resolution;  
uniform vec2 mouse;  
uniform float pX[NUMBER_OF_BOIDS];  
uniform float pY[NUMBER_OF_BOIDS];  
uniform float vX[NUMBER_OF_BOIDS];  
uniform float vY[NUMBER_OF_BOIDS];  
  
void main(){  
  
	float rColor = 0.0;  
	float gColor = 0.0;  
	float bColor = 0.0;  
  
	//we grab the x and y and store them in an int  
	int xVal = int(gl_FragCoord.x);  
	int yVal = int(gl_FragCoord.y);  
  
    for (int i = 0; i < NUMBER_OF_BOIDS; i++)  
    {  
  
        float distanceX = pX[i] - xVal;  
        float distanceY = pY[i] - yVal;  
  
        float dist = sqrt(pow(distanceX, 2) + pow(distanceY,2));  
  
        float veloVec = sqrt(pow(vX[i],2) + pow(vY[i],2));  
  
	if(veloVec > 1)  
	{  
  
		bColor += sin(dist * (0.1 * sin(time * 0.1)));  
	        gColor += sin(time * 0.1) * (cos(bColor * 2));  
		rColor += sin(veloVec) * sin(time) * mod(bColor, gColor);  
	}	  
	  
    }  
  
	gl_FragColor = vec4(rColor, gColor, bColor, 1.0);  
	//gl_FragColor = vec4(rColor, gColor, bColor, 1.0);  
  
}  
  

  
  
  
		float pX[NUMBER_OF_BOIDS], pY[NUMBER_OF_BOIDS];  
		float vX[NUMBER_OF_BOIDS], vY[NUMBER_OF_BOIDS];  
  
//--------------------------------------------------------------  
void testApp::setup(){  
  
    ofSeedRandom();  
  
	ofSetLogLevel(OF_LOG_VERBOSE);  
	ofBackground(0,0,0);  
	ofSetVerticalSync(true);  
	//ofSetFrameRate(900);  
	ofEnableAlphaBlending();  
  
	shader.load("shaders/forceExpression.vert","shaders/forceExpression.frag");  
  
	doShader = true;  
  
	for (int i = 0; i < NUMBER_OF_BOIDS; i++)  
	{  
	    pX[i] = ofRandomWidth();  
	    pY[i] = ofRandomHeight();  
	    vX[i] = 0;  
	    vY[i] = 0;  
	}  
  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
  
    float maxVelocity = 10.5;  
    float repelRadius = 100.0;  
  
    // boid stuff  
    for (int i = 0; i < NUMBER_OF_BOIDS; i++)  
    {  
  
        vX[i] += ofNoise(pX[i], pY[i], vY[i]);  
        vY[i] += ofNoise(pY[i], pX[i], vX[i]);  
  
        vX[i] -= ofNoise(pY[i], pX[i], vY[i]);  
        vY[i] -= ofNoise(pX[i], pY[i], vX[i]);  
  
	vX[i] = ofClamp(vX[i], -maxVelocity, maxVelocity);  
	vY[i] = ofClamp(vY[i], -maxVelocity, maxVelocity);  
  
        vX[i] *= 0.999;  
        vY[i] *= 0.999;  
  
  
  
    }  
  
    for (int i = 0; i < NUMBER_OF_BOIDS; i++)  
    {  
  
        pX[i] += vX[i];  
        pY[i] += vY[i];  
  
        if (pX[i] > ofGetWidth()) { pX[i] = ofGetWidth() - (pX[i] - ofGetWidth()); vX[i] *= -1; }  
        if (pY[i] > ofGetHeight()) { pY[i] = ofGetHeight() - (pY[i] - ofGetHeight()); vY[i] *= -1;  }  
  
        if (pX[i] < 0) { pX[i] *= -1; vX[i] *= -1; }  
        if (pY[i] < 0) { pY[i] *= -1; vY[i] *= -1; }  
    }  
  
  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
  
  
	if( doShader ){  
		shader.begin();  
  
			shader.setUniform1f("time", ofGetElapsedTimef());  
			shader.setUniform2f("resolution", ofGetWidth(), ofGetHeight() );  
			shader.setUniform2f("mouse", mouseX, ofGetHeight()- mouseY );  
			shader.setUniform1fv("pX", pX, NUMBER_OF_BOIDS);  
			shader.setUniform1fv("pY", pY, NUMBER_OF_BOIDS);  
			shader.setUniform1fv("vX", vX, NUMBER_OF_BOIDS);  
			shader.setUniform1fv("vY", vY, NUMBER_OF_BOIDS);  
  
	}  
  
		ofSetColor(0,0,0);  
                ofRect(0,0,ofGetWidth(), ofGetHeight());  
  
	if( doShader ){  
		shader.end();  
	}  
  
	//ofSaveFrame();  
}  
  
  

And sharing the shader (most the flare, it’s beautiful ) :slight_smile: ?

  
  
#version 120  
precision highp float;  
  
uniform float time;  
uniform vec2 resolution;  
uniform vec2 mouse;  
  
void main(){  
  
	float rColor = 0.0;  
	float gColor = 0.0;  
	float bColor = 0.0;  
	  
	//we grab the x and y and store them in an int  
	int xVal = int(gl_FragCoord.x);  
	int yVal = int(gl_FragCoord.y);  
  
	float distanceX = (resolution.x/2.0) - xVal;  
	float distanceY = (resolution.y/2.0) - yVal;  
  
	float distance = sqrt(pow(distanceX, 2) + pow(distanceY,2));  
	  
	rColor = abs(sin(time) * (resolution.x / 2.0)) / distance;  
	gColor = abs(cos(time) * (resolution.y / 2.0)) / distance;  
	bColor = time * (rColor + gColor) / (distance);  
  
	distanceX = (mouse.x) - xVal;  
	distanceY = (mouse.y) - yVal;  
  
	distance = sqrt(pow(distanceX, 2) + pow(distanceY,2));  
  
	rColor -= abs(sin(time) * (mouse.x)) / distance;  
	gColor -= abs(cos(time) * (mouse.y)) / distance;  
	bColor -= time * (rColor + gColor) / (distance);  
  
	gl_FragColor = gl_Color + vec4(rColor, gColor, bColor, 1.0);  
	//gl_FragColor = vec4(rColor, gColor, bColor, 1.0);  
  
}  
  

This is really ugly code the word distance is a protected function but you can still declare it as a float.

Just a quick note to anyone who runs into trouble with that shader, this bit:

#version 120
precision highp float;

is for OpenGLES2 and WebGL. Some cards will ignore it, but some will error on it, and it doesn’t do anything on a non-GLES system anyways, so you can remove it if it errors out. Awesome work btw!

Good to know! I am clearly in “copy -> paste -> yay! -> tweak -> more!” …mode right now with shaders

droooolllll

looking pretty awesome, don’t forget to post the source!! :wink:

I’ve been meaning to get into shaders for a while now and I got inspired by memphistechno, see the attachment for the result! I’ve got some basic questions about this stuff though, maybe some of the guru’s around here can send me in the right direction.

Say I want to render a bunch of particles, like I did in the attached image. How I do this now is by declaring

  
uniform float blobX[NROFBLOBS];  
uniform float blobY[NROFBLOBS];  

in the fragment shader. On the CPU I keep 2 arrays for X and Y positions and I pass these using

  
        shader.setUniform1fv("blobX", x, NROFBLOBS);  
        shader.setUniform1fv("blobY", y, NROFBLOBS);  

right? This seems like a good approach: the shader knows about the positions of all the particles, we draw an ofRect in between the shader.begin() and shader.end() calls so the shader will be fed a fragment for every pixel on that rect, we calculate color values for every fragment according to the particle positions and all is well. But if I cranck up the number of blobs, the shader complaints about the number of uniforms used:

  
ERROR: Implementation limit of 4096 (e.g., number of built-in plus user defined active uniforms components) exceeded, fragment shader uses 8000 total uniforms.  
  

It seems an array of uniforms with a length of 1000 actually counts as 1000 uniforms and I am only allowed to use 4096 uniforms. That’s a problem! I tried using an ofImage with a height of 1, upload it to the GPU as a sampler2DRect and do texture lookups using texture2DRect( texture, index ) but the resolution of the data is way too low; only 255. If I use this for a position of an animating particle it’s not looking smooth at all. It is possible to render about 1000 particles though, after that the framerate drops. Is there a better approach when doing this? Is it possible to use vertex data supplied with glVertex calls for such a system? If I do it like this:

  
  
shader.begin();  
glBegin(GL_POINTS);  
glVertex2f(0,0);  
glVertex2f(100,0);  
glVertex2f(100,100);  
glEnd();  
shader.end();  
  

how can I render to for example an ofRect? Lots of questions here… :slight_smile:

I hope someone can help me out or point me towards some books/online resources for this kind of stuff. Thanks a lot!

That really looks amazing.
I am quite frustrated because I don’t even know how to get your code running!
I guess I have to check all that shader things out.

Many thanks for sharing with everybody!

[quote=“daanvanhasselt, post:13, topic:7263”]
I’ve got some basic questions about this stuff though, maybe some of the guru’s around here can send me in the right direction.[/quote]I too have these exact questions, I’m going to make a thread about it in advanced.

Actually a “uniform float” is 4 components on a lot of cards and yours is apparently one of them. I’m no guru you have 1000 points that you want to draw, which kind of sounds like a point sprite situation. There’s a bunch of tutorials on using Point Sprites and I have some code where I used them in an OF project laying around that I can post up here later.

Another approach that might work (not sure) is to again draw each of your blobs with a point (GL_POINT) use varying to pass data from the vert to the frag.

Here’s the vert, just give our x and y

  
  
  
varying vec2 fake_frag_coord;  
  
void main()  
{  
  
	gl_FrontColor = gl_Color;  
	gl_TexCoord[0] = gl_MultiTexCoord0;  
  
	vec2 screen;  
	screen.x = 480.;  
	screen.y = 320.;  
  
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  
	fake_frag_coord = (gl_ModelViewMatrix * gl_Vertex).xy * screen;  
  
	fake_frag_coord.x = fake_frag_coord.x + 240.;  
	fake_frag_coord.y = fake_frag_coord.y + 180.;  
  
}  
  

here’s the frag, we get the x and y and can use it to figure out how bright things should be w/the distance function:

  
  
  
uniform sampler2D tex;  
  
varying vec2 fake_frag_coord;  
  
void main()  
{  
	vec4 col;  
	col.z = distance(fake_frag_coord, gl_FragCoord.xy) / 640.;  
	col.w = 1.;  
	gl_FragColor = col;  
}  
  
  

For 640/480 stuff swap out your screen width. I’m not completely sure that will work, but it should at least give you some ideas.

Hi Joshua and thanks for the reply. I can’t get it to work though, the fake_frag_coord doesn’t seem to get through like I expect it to.

Vertex shader:

  
  
uniform vec2 resolution;  
varying vec2 fake_frag_coord;  
  
void main(){  
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  
    gl_FrontColor = gl_Color;  
      
    fake_frag_coord = (gl_ModelViewMatrix * gl_Vertex).xy;          // [-1, 1]  
    fake_frag_coord += 1.0f;                                        // [0, 2]  
    fake_frag_coord *= resolution / 2.0f;                           // [0, resolution]  
}  
  

Fragment shader:

  
  
uniform vec2 resolution;  
varying vec2 fake_frag_coord;    
  
void main(){  
	int xVal = int(gl_FragCoord.x);  
	int yVal = int(gl_FragCoord.y);  
      
    if(xVal == fake_frag_coord.x && yVal == fake_frag_coord.y){  
        gl_FragColor = vec4(1);  
    }  
    else{  
        gl_FragColor = vec4(1, 0, 0, 1);  
    }  
}  
  

And in testApp::draw()

  
  
    shader.begin();  
    shader.setUniform2f("resolution", (float)ofGetWidth(), (float)ofGetHeight() );  
    glPointSize(4);  
    glBegin(GL_POINTS);  
    glVertex2f(100, 100);  
    glVertex2f(200, 200);  
    glVertex2f(300, 300);  
    glVertex2f(400, 400);  
    glVertex2f(500, 500);  
    glVertex2f(600, 600);  
    glEnd();  
      
    ofRect(0,0,ofGetWidth(), ofGetHeight());  
    shader.end();  
  

All I get is a completely red screen, while I expect to get white pixels at 6 positions. If I don’t draw the ofRect but only the GLPOINTS, I get 6 red points, while I expect them to be white. What am I doing wrong?

Thanks,
Daan

UPDATE
If I set fake_frag_coord to some vec2 in the vertex shader (frake_frag_coord = vec2(500,500):wink: I get exactly one white pixel at 500,500. So it seems the problem lies in getting from glVertex2f(x, y) to fake_frag_coord…

Yeah, that’s what I got stuck at too. There’s some stuff on stackoverflow about doing that conversion but I couldn’t get it to work. I’ll take another stab at it tonight when I have some more time.

maybe i’m misunderstanding the problem, but if you’re drawing in 2d and have an orthogonal camera or a default OF camera, then gl_FragCoord.st = gl_Vertex.xy.

i haven’t noticed anyone using gl_Vertex directly. in other words, maybe try:

  
  
fake_frag_coord = gl_Vertex.xy;  
  

in the vertex shader?

I was hopeful for that, but it also doesn’t quite work, not sure why. I’m thinking something like this might work:

  
fake_frag_coord = viewport.xy + viewport.wh * (1 + gl_Position.xy / gl_Position.w)/2  

Kyle, I was reading this: http://stackoverflow.com/questions/1288174/how-to-calculate-gl-fragcoord-in-glsl maybe you can glean something from it that I missed?