ofNoise is eating my CPU

Hey!

For an installation I want to merge a couple of images interactively with the use of noise for distortion and masks.
I got it working fine but whenever I use higher resolution noise maps the fps goes down drastically… I minimized my project to just the noise to see if that’s the problem and it is… I was wondering if there’s a more efficient way in doing this than drawing a couple of noise textures…

For now I can get up to 23 fps with 3 different 640,480 noisemaps, but this needs to be HD projections and I still need to add an interactive layer.

All suggestions are welcome!!

Here I you can see the mask I use to fill in the images

Hi!

Do it on the GPU, I’ve got an example here that’ll help you get started:

Thanks! I’ll try it out

These examples give a way to detailed noise for my purpose. I found that by drawing the smaller noises in enlarged in fbo’s it could get rit of the pixelness. But somehow I can only get it to work with 2 layers… Maybe anyone can figure out why?

Excuse my mess of a code, I know some vectors would make it more clear.

Here’s the shader:

#version 150

uniform sampler2DRect noise1;
uniform sampler2DRect noise2;
uniform sampler2DRect afb2;
uniform sampler2DRect afb;
uniform sampler2DRect afb3;
uniform sampler2DRect noise3;
uniform sampler2DRect afb4;
uniform sampler2DRect noise4;

in vec2 texCoordVarying;
in float layer;
out vec4 outputColor;

void main()
{
    vec4 noise = texture(noise1,texCoordVarying);
    vec4 img;
    if (layer == 1) {
        img = texture(afb,texCoordVarying);
        noise = texture(noise1,texCoordVarying);
    } else if (layer==2){
        img = texture(afb2,texCoordVarying);
        noise = texture(noise2,texCoordVarying);
    } else if (layer==3){
        img = texture(afb3,texCoordVarying);
        noise = texture(noise3,texCoordVarying);
    }
    else {
        img = texture(afb4,texCoordVarying);
        noise = texture(noise4,texCoordVarying);
        
    }
    vec4 color = vec4(0,0,0,0);

    color = mix(color, img*noise, 1);
    
    outputColor = color;
}

And the vertex shader:

 #version 150

// these are from the programmable pipeline system
uniform mat4 modelViewProjectionMatrix;
in vec4 position;
in vec2 texcoord;

// this is how we receive the texture
uniform sampler2DRect noise1;
uniform sampler2DRect noise2;
uniform sampler2DRect noise3;
uniform sampler2DRect noise4;
out vec2 texCoordVarying;
out float layer;
void main()
{
    // get the position of the vertex relative to the modelViewProjectionMatrix
    vec4 modifiedPosition = modelViewProjectionMatrix * position;
    
    // we need to scale up the values we get from the texture
    float scale = 80;
    
    // here we get the red channel value from the texture
    // to use it as vertical displacement
    float displ1 = texture(noise1, texcoord).r;
    float displ2 = texture(noise2, texcoord).r;
    float displ3 = texture(noise3, texcoord).r;
    float displ4 = texture(noise4, texcoord).r;

    if (displ1>displ2 && displ1>displ3 && displ1>displ4){
        
        layer = 1;
        modifiedPosition.y += displ1 * scale;
        
    } else if (displ2>displ3 && displ2>displ1 && displ2>displ4){
        
        layer = 2;
        modifiedPosition.y += displ2 * scale;
        
        }
    else if (displ3>displ4 && displ3>displ3 && displ3>displ2){
        
        layer = 3;
        modifiedPosition.y += displ3 * scale;
        
    }
    else {
        layer = 4;
        modifiedPosition.y += displ4 * scale;
        
    }
        gl_Position = modifiedPosition;
    texCoordVarying = texcoord;
}

And the APP:

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofEnableDepthTest();
#ifdef TARGET_OPENGLES
	shader.load("shadersES2/shader");
#else
	if(ofIsGLProgrammableRenderer()){
		shader.load("shadersGL3/shader");
	}else{
		shader.load("shadersGL2/shader");
	}
#endif
    fbo.allocate(1280, 720);
    fbo.begin();
    ofClear(0);
    fbo.end();

    fbo2.allocate(1280, 720);
    fbo2.begin();
    ofClear(0);
    fbo2.end();
    
    fbo3.allocate(1280, 720);
    fbo3.begin();
    ofClear(0);
    fbo3.end();
    
    fbo4.allocate(1280, 720);
    fbo4.begin();
    ofClear(0);
    fbo4.end();
    
    afb.load("1.jpg");
    afb2.load("2.jpg");
    afb3.load("3.jpg");
    afb4.load("4.jpg");
    
    img.allocate(1280/4, 720/4, OF_IMAGE_GRAYSCALE);
    img2.allocate(1280/4, 720/4, OF_IMAGE_GRAYSCALE);
    img3.allocate(1280/4, 720/4, OF_IMAGE_GRAYSCALE);
    img4.allocate(1280/4, 720/4, OF_IMAGE_GRAYSCALE);
    plane.set(1280, 800, 1200, 800);
    plane.mapTexCoordsFromTexture(fbo.getTextureReference());
}

//--------------------------------------------------------------
void ofApp::update(){
//    float noiseScale = ofMap(mouseX, 0, ofGetWidth(), 0, 0.1);
    float noiseScale = 0.02;
    float noiseVel = ofGetElapsedTimef();
    
    unsigned char * pixels = img.getPixels();
    unsigned char * pixels2 = img2.getPixels();
    unsigned char * pixels3 = img3.getPixels();
    unsigned char * pixels4 = img4.getPixels();
    int w = img.getWidth();
    int h = img.getHeight();
    for(int y=0; y<h; y++) {
        for(int x=0; x<w; x++) {
            int i = y * w + x;
            float noiseVelue = ofNoise(x * noiseScale, y * noiseScale, noiseVel);
            pixels[i] = 255 * noiseVelue;
            noiseVelue = ofNoise(x * noiseScale, y * noiseScale, noiseVel+10);
            pixels2[i] = 255 * noiseVelue;
            noiseVelue = ofNoise(x * noiseScale, y * noiseScale, noiseVel+20);
            pixels3[i] = 255 * noiseVelue;
            noiseVelue = ofNoise(x * noiseScale, y * noiseScale, noiseVel+30);
            pixels3[i] = 255 * noiseVelue;
        }
    }
    img.update();
    img2.update();
    img3.update();
  img4.update();
    fbo.begin();
    ofClear(0);
    img.draw(0, 0, 1280, 720);
    fbo.end();
    fbo2.begin();
    ofClear(0);
    img2.draw(0, 0, 1280, 720);
    fbo2.end();
    fbo3.begin();
    ofClear(0);
    img3.draw(0, 0, 1280, 720);
    fbo3.end();
    fbo4.begin();
    ofClear(0);
    img4.draw(0, 0, 1280, 720);
    fbo4.end();
}

//--------------------------------------------------------------
void ofApp::draw(){
    shader.begin();
    shader.setUniformTexture("noise1", fbo.getTexture(), 1);
    shader.setUniformTexture("noise2", fbo2.getTexture(), 2);
    shader.setUniformTexture("afb", afb.getTexture(), 3);
    shader.setUniformTexture("afb2", afb2.getTexture(), 4);
    shader.setUniformTexture("afb3", afb3.getTexture(), 5);
    shader.setUniformTexture("noise3", fbo.getTexture(), 6);
    shader.setUniformTexture("afb4", afb4.getTexture(), 7);
    shader.setUniformTexture("noise4", fbo.getTexture(), 8);
    ofPushMatrix();
    
    float tx = ofGetWidth() / 2;
    float ty = ofGetHeight() / 2;
    ofTranslate(tx, ty);
    plane.drawFaces();
    
    ofPopMatrix();
    
    shader.end();
    
 
    ofSetColor(ofColor::white);
//    img.draw(0, 0,1280,720);
    ofDrawBitmapString("fps: " + ofToString(ofGetFrameRate()), 10, 10);

}

As you can see it only uses 2 images, by changing them in the shader I found that it the shader only passes layer=2 or layer=4, getting headaches figuring out why…argh

Hi,

I’m not quite sure I’m following what you are trying to do.

The link I sent you has some shader code for generating noise on the GPU on the fly, to make the noise it generates ‘less detailed’ you would change the frequency of the input, so for instance if you are using the texture coordinate as input, doing:

float result = snoise( texCoord );

Will be more detailed than:

float result = snoise( texCoord * 0.1 );

Check this example out:

Watch out as texture coordinates will be in pixels for sampler2DRect in which case you will need to divide by the screen width/height to get more usable numbers to plug into a noise function, they’re a but big otherwise.

This would let you avoid computing the noise on the CPU completely and will be plenty fast.

So if you wanted to grab 4 noise values to use in your shader you (provided you have included or just pasted in Noise3D.glslinc into the shader file ) could do something like:

//Assuming you have time passed in as a uniform float
float noiseTime = time * 0.3; // slow this dimension down a bit
vec3 noiseRead( texCoordVarying.xy, noiseTime );

// Add an offset to the read position or we'll get the same result as we're reading the noise in the same place
float noiseVal1 = snoise( noiseRead );
float noiseVal2 = snoise( noiseRead + vec3(1.12,73.28,9.12.23) ); 
float noiseVal3 = snoise( noiseRead + vec3(6.23,32.13,9.93.12) );
float noiseVal4 = snoise( noiseRead + vec3(8.98,92.72,9.32.31) );

Hope that helps!

/A

Thanks alot, exactly what I needed!