Difficulty with shader, No matching function for call to texture2DRect(sampler2DRect, vec2, float)


#1

I am working with code found on shadertoy to replicate CRT monitor scanlines. There are a number of them, but this is the slimmest one I found:
FixingPixelArtKernel
Another one (a bit more complicated) FixingPixelArt

In these shaders there is a function Fetch which calls another function ToLinear, converting sRGB to Linear.

// sRGB to Linear.
 // Assuing using sRGB typed textures this should not be needed.
 float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);}
 vec3 ToLinear(vec3 c){return vec3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));}
 

 vec3 Fetch(vec2 pos,vec2 off){
     pos=floor(pos*res+off)/res;
     if(max(abs(pos.x-0.5),abs(pos.y-0.5))>0.5)return vec3(0.0,0.0,0.0);
     return Test(ToLinear(texture2DRect(tex0,vec2(pos.x,-pos.y),-16.0).rgb));
 }

The original code had ‘ToLinear(texture2D(’ instead of ‘ToLinear(texture2DRect’

my problem is that I am consistently getting this error:
No matching function for call to texture2DRect(sampler2DRect, vec2, float)

I haven’t been able to find a solution online that makes sense.

The image being used in the shader is an FBO created full-screen every frame from a 3d scene, so I can’t use sampler2D.


Best shader to use with openFrameworks to create CRT scanlines
#2

Hi,

Yes, there no ‘float bias’ argument for texture2DRect, only texture2D.

I don’t understand why you can’t work with sampler2D. Since what you want is post-process effect, you just need to render your scene to an FBO and use that texture to apply the effect.

You DO need to work with normalized coords. If you share a bit of code, maybe I can give a more direct response.


#3

Thank you very much. I managed to find how to set the FBO in the setup so it can be used as a texture2D within a shader instead of having to be texture2DRect

 ofDisableArbTex();
    thisFbo.allocate(camWidth, camHeight, GL_RGBA);
ofEnableArbTex();

I am trying to get the shader code to work by integrating it within the multi-texture shader example but don’t feel confident to share it just yet. It would be ‘sloppy’. Thank you for pointing me in the right track. Hopefully I will have something to share soon.


#4

okay, this is based off of this shader toy shader:

https://www.shadertoy.com/view/XsjSzR#

it should pixelize an image (not necessary for my needs) and then show with the bars, and then with the fake phosphorus mask one would get on a CRT.

The included code is derived from the Multiple Texture shader example, as I thought it would be easier than rolling my own. Unfortunately there is a weird slant/tilt/offset on the shader which is probably due to some of the calculations internally to the shader toy code which normalizes the coordinates.

I am unsure how to use the proper ‘power of two’ dimensions for the texture2D.

Start with the multiTexture shader example in openframeworks, and use this code:
ofApp.h

 #pragma once

#define WEBCAM

#include "ofMain.h"

class ofApp : public ofBaseApp{
public:

void setup();
void update();
void draw();

void keyPressed  (int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);


void setShaderUniforms();

ofShader shader;

ofShader thisShader;

ofImage image;
ofImage imageMask;
ofVideoPlayer movie;
ofVideoGrabber camera;

ofFbo fbo;
ofFbo maskFbo;

ofFbo thisFbo;
int imageCounter;
};

This is the ofApp.cpp (use the space bar to step through the available images for scanlines) I have included the shader in the code to make it easier. I am not sure how to fix the slant of the output, nor the lack of proper pixelation.

#include "ofApp.h"
#define STRINGIFY(A) #A


//--------------------------------------------------------------
void ofApp::setup(){

#ifdef TARGET_OPENGLES
    shader.load("shadersES2/shader");
#else
    if(ofIsGLProgrammableRenderer()){
        shader.load("shadersGL3/shader");
    }else{
        shader.load("shadersGL2/shader");
    }
#endif
    
    string shaderProgram = STRINGIFY(
        uniform sampler2D tex0;

        uniform float iGlobalTime;
        vec2 iResolution;

        uniform vec2 textureSize;
        uniform int frameNum;

         //
         // PUBLIC DOMAIN CRT STYLED SCAN-LINE SHADER
         //
         //   by Timothy Lottes
         //
         // This is more along the style of a really good CGA arcade monitor.
         // With RGB inputs instead of NTSC.
         // The shadow mask example has the mask rotated 90 degrees for less chromatic aberration.
         //
         // Left it unoptimized to show the theory behind the algorithm.
         //
         // It is an example what I personally would want as a display option for pixel art games.
         // Please take and use, change, or whatever.
         //
         
         // Emulated input resolution.
    #if 0
         // Fix resolution to set amount.
         vec2 res=vec2(320.0/1.0,160.0/1.0);
    #else
         // Optimize for resize.
         vec2 res=iResolution.xy/6.0;
    #endif
         
         // Hardness of scanline.
         //  -8.0 = soft
         // -16.0 = medium
         float hardScan=-8.0;
         
         // Hardness of pixels in scanline.
         // -2.0 = soft
         // -4.0 = hard
         float hardPix=-3.0;
         
         // Display warp.
         // 0.0 = none
         // 1.0/8.0 = extreme
         vec2 warp=vec2(1.0/32.0,1.0/24.0);
         
         // Amount of shadow mask.
         float maskDark=0.5;
         float maskLight=1.5;
                                     
         //------------------------------------------------------------------------
         
         // sRGB to Linear.
         // Assuing using sRGB typed textures this should not be needed.
         float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);}
         vec3 ToLinear(vec3 c){return vec3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));}
         
         // Linear to sRGB.
         // Assuing using sRGB typed textures this should not be needed.
         float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);}
         vec3 ToSrgb(vec3 c){return vec3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));}
         
         // Nearest emulated sample given floating point position and texel offset.
         // Also zero's off screen.
         vec3 Fetch(vec2 pos,vec2 off){
             pos=floor(pos*res+off)/res;
             if(max(abs(pos.x-0.5),abs(pos.y-0.5))>0.5)return vec3(0.0,0.0,0.0);
             return ToLinear(texture2D(tex0,pos.xy,-16.0).rgb);}
         
         // Distance in emulated pixels to nearest texel.
         vec2 Dist(vec2 pos){pos=pos*res;return -((pos-floor(pos))-vec2(0.5));}
         
         // 1D Gaussian.
         float Gaus(float pos,float scale){return exp2(scale*pos*pos);}
         
         // 3-tap Gaussian filter along horz line.
         vec3 Horz3(vec2 pos,float off){
             vec3 b=Fetch(pos,vec2(-1.0,off));
             vec3 c=Fetch(pos,vec2( 0.0,off));
             vec3 d=Fetch(pos,vec2( 1.0,off));
             float dst=Dist(pos).x;
             // Convert distance to weight.
             float scale=hardPix;
             float wb=Gaus(dst-1.0,scale);
             float wc=Gaus(dst+0.0,scale);
             float wd=Gaus(dst+1.0,scale);
             // Return filtered sample.
             return (b*wb+c*wc+d*wd)/(wb+wc+wd);}
         
         // 5-tap Gaussian filter along horz line.
         vec3 Horz5(vec2 pos,float off){
             vec3 a=Fetch(pos,vec2(-2.0,off));
             vec3 b=Fetch(pos,vec2(-1.0,off));
             vec3 c=Fetch(pos,vec2( 0.0,off));
             vec3 d=Fetch(pos,vec2( 1.0,off));
             vec3 e=Fetch(pos,vec2( 2.0,off));
             float dst=Dist(pos).x;
             // Convert distance to weight.
             float scale=hardPix;
             float wa=Gaus(dst-2.0,scale);
             float wb=Gaus(dst-1.0,scale);
             float wc=Gaus(dst+0.0,scale);
             float wd=Gaus(dst+1.0,scale);
             float we=Gaus(dst+2.0,scale);
             // Return filtered sample.
             return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we);}
         
         // Return scanline weight.
         float Scan(vec2 pos,float off){
             float dst=Dist(pos).y;
             return Gaus(dst+off,hardScan);}
         
         // Allow nearest three lines to effect pixel.
         vec3 Tri(vec2 pos){
             vec3 a=Horz3(pos,-1.0);
             vec3 b=Horz5(pos, 0.0);
             vec3 c=Horz3(pos, 1.0);
             float wa=Scan(pos,-1.0);
             float wb=Scan(pos, 0.0);
             float wc=Scan(pos, 1.0);
             return a*wa+b*wb+c*wc;}
         
         // Distortion of scanlines, and end of screen alpha.
         vec2 Warp(vec2 pos){
             pos=pos*2.0-1.0;    
             pos*=vec2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y);
             return pos*0.5+0.5;}
         
         // Shadow mask.
         vec3 Mask(vec2 pos){
             pos.x+=pos.y*3.0;
             vec3 mask=vec3(maskDark,maskDark,maskDark);
             pos.x=fract(pos.x/6.0);
             if(pos.x<0.333)mask.r=maskLight;
             else if(pos.x<0.666)mask.g=maskLight;
             else mask.b=maskLight;
             return mask;}    
         
         // Draw dividing bars.
         float Bar(float pos,float bar){pos-=bar;return pos*pos<4.0?0.0:1.0;}
         
         // Entry.
         void main( void ){
             
             
             vec2 pos = gl_TexCoord[0].st/iResolution;
             
             pos.y = 1.0-pos.y;
             pos *= iResolution;
             vec4 original  = texture2D(tex0, pos);
             
             // Unmodified.
             if(pos.x<iResolution.x*0.333){
                 original.rgb=Fetch(pos.xy/iResolution.xy+vec2(0.333,0.0),vec2(0.0,0.0));}
             else{
                 vec2 pos=Warp(pos.xy/iResolution.xy+vec2(-0.333,0.0));
                 
                 if(pos.x<iResolution.x*0.666){
                     hardScan=-12.0;
                     maskDark=maskLight=1.0;
                     pos=Warp(pos.xy/iResolution.xy);
                 }
                 original.rgb=Tri(pos)*Mask(pos.xy);
                 
             }
             original.a=1.0;
             
             ///uncommenting this results in a darkened output
             /*
             original.rgb*=
                     Bar(pos.x,iResolution.x*0.333)*
                     Bar(pos.x,iResolution.x*0.666);
             */
             
             
             gl_FragColor.rgb=ToSrgb(original.rgb);
             
            /* uncomment to test if shader is working. * /
             pos = gl_TexCoord[0].st;
              original  = texture2D(tex0, pos);
             if(pos.x<iResolution.x*0.333){
                 original.rgb=Fetch(pos.xy+vec2(0.333,0.0),vec2(0.0,0.0));
             }
              vec4 color = vec4 (1.0-original.r, 1.0-original.g, 1.0-original.b, 1.0);
              gl_FragColor = color;
            */
         }
         

    );
    
    thisShader.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderProgram);
    thisShader.linkProgram();
    
    int camWidth = 320;
    int camHeight = 240;
    
    camera.setVerbose(false);
    camera.initGrabber(camWidth, camHeight);
    
    movie.load("movie.mov");
    movie.play();
    
    image.load("img.jpg");
    imageMask.load("mask.jpg");
    
    fbo.allocate(camWidth, camHeight);
    
    maskFbo.allocate(camWidth, camHeight, GL_RGB);
    
    ofDisableArbTex();
        thisFbo.allocate(camWidth, camHeight, GL_RGBA);
    ofEnableArbTex();
    
    imageCounter = 0;
    
}

//--------------------------------------------------------------
void ofApp::update(){
    camera.update();
    movie.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    
    //------------------------------------------- draw to mask fbo.
    maskFbo.begin();

        ofClear(255, 0, 0, 255);
        
        float imageMaskX = mouseX / (float)ofGetWidth();
        imageMaskX = ofClamp(imageMaskX, 0, 1);
        imageMaskX = -(imageMask.getWidth() - maskFbo.getWidth()) * imageMaskX;
        imageMask.draw(imageMaskX, 0);
    
    maskFbo.end();
    
    thisFbo.begin();
        ofClear(255,255,255, 0);
    if (imageCounter == 0){
        movie.draw(0,0,thisFbo.getWidth(),thisFbo.getHeight());
    } else if (imageCounter == 1){
        camera.draw(0,0,thisFbo.getWidth(),thisFbo.getHeight());
    } else if (imageCounter == 2){
        image.draw(0,0,thisFbo.getWidth(),thisFbo.getHeight());
    } else if (imageCounter == 3){
        maskFbo.draw(0,0,thisFbo.getWidth(),thisFbo.getHeight());
    }
    thisFbo.end();
    
    //------------------------------------------- draw to final fbo.
    fbo.begin();
        ofClear(0, 0, 0,255);
        
        shader.begin();
            shader.setUniformTexture("tex0", camera.getTexture(), 1);
            shader.setUniformTexture("tex1", image, 2);
            shader.setUniformTexture("tex2", movie.getTexture(), 3);
            shader.setUniformTexture("imageMask", maskFbo.getTexture(), 4);
            
            // we are drawing this fbo so it is used just as a frame.
            maskFbo.draw(0, 0);
            
        shader.end();
    fbo.end();
    
    //------------------------------------------- 
    ofSetColor(255);
    camera.draw(5,5,320,240);
    ofSetColor(ofColor::red);
    ofDrawBitmapString("RED", 5+30, 5+30);
    
    ofSetColor(255);
    image.draw(320+10,5,320,240);
    ofSetColor(ofColor::green);
    ofDrawBitmapString("GREEN", 320+10+30,5+30);
    
    ofSetColor(255);
    movie.draw(320*2+15,5,320,240);
    ofSetColor(ofColor::blue);
    ofDrawBitmapString("BLUE", 320*2+5+30,5+30);
    
    ofSetColor(255);
    maskFbo.draw(320+10,240+10,320,240);
    ofDrawBitmapString("RGB MASK", 320+10+30,240+10+30);
    
    ofPushMatrix();
        ofTranslate(5,240*2+15);
        fbo.draw(0,0,320,240);
        ofDrawBitmapString("Final FBO", 10,30);
    ofPopMatrix();
    
    
    ofPushMatrix();
        ofTranslate(320+10,240*2+15);
        thisFbo.draw(0,0,320,240);
        ofDrawBitmapString("thisFBO", 10,30);
    ofPopMatrix();
    
    ofSetColor(255);
    //ofDisableAlphaBlending();
    ofPushMatrix();
        ofTranslate(320*2+15,240+15);
        setShaderUniforms();
        if (imageCounter == 0){
            ofDrawBitmapString("Final thisFBO from movie", 10,250);
        } else if (imageCounter == 1){
            ofSetColor(0);
            ofDrawBitmapString("Final thisFBO from camera", 10,250);
            ofSetColor(255);
        } else if (imageCounter == 2){
            ofDrawBitmapString("Final thisFBO from image", 10,250);
        } else if (imageCounter == 3){
            ofDrawBitmapString("Final thisFBO from imageMask", 10,250);
        }
    
    ofPopMatrix();
    
}

void ofApp::setShaderUniforms(){
    float resolution[] = {static_cast<float>(ofGetWidth()),static_cast<float>(ofGetHeight())};
    float time = ofGetElapsedTimef();
    float mouser[] = {static_cast<float>(mouseX), static_cast<float>(mouseY)};
    
    float texOffset[] = {1,1};
    ofEnableNormalizedTexCoords();
    //thisFbo.getTexture().bind();
    thisShader.begin();
    
        thisShader.setUniformTexture("tex0", thisFbo.getTexture(), 0);
        //thisShader.setUniformTexture("noiseTexture", noiseTexture.getTexture(), 0);
        //pass the time, resolution, and source buffer as uniforms to the shader
        thisShader.setUniform1f("iGlobalTime", ofGetElapsedTimef());
        thisShader.setUniform3f("iResolution", ofGetWidth(), ofGetHeight(), 0.0);
        
        thisShader.setUniform2fv("mouse", mouser);
        
        thisFbo.draw(0,0, 320,240);
        
        
    thisShader.end();
    //thisFbo.getTexture().unbind();
    ofDisableNormalizedTexCoords();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if (key == ' '){
        imageCounter++;
        if (imageCounter>3) imageCounter = 0;
        
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){ 

}

If you can help me with this, that would be great. I really want to use this CRT-esque in my project… hopefully others would find it useful as well.


ofShader: how to only load fragment shader? (not vertex)