Texturing with Geometry Shader

I am trying to build a Geometry shader that takes points as inputs and displays a textured plane for each point

Here is a one-file version of what I am working with:

main.cpp

#include "ofMain.h"

#define STRINGIFY(x) #x

class ofApp : public ofBaseApp
{
    
public:
    
    ofShader shader;
    ofEasyCam camera;
    ofVboMesh mesh;
    ofPlanePrimitive plane;
    ofTexture texture;
    ofFbo fbo;
    void setup()
    {
       // ofDisableArbTex();
        ofEnableAlphaBlending();
        //ofEnableNormalizedTexCoords();
        

        ofFbo::Settings settings;
        settings.width = 256;
        settings.height = 256;
        
        settings.textureTarget = GL_TEXTURE_RECTANGLE_ARB;			// GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB
        settings.internalformat = GL_RGBA;			// GL_RGBA, GL_RGBA16F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB etc.
        //settings.depthStencilInternalFormat = GL_DEPTH_STENCIL; 	// GL_DEPTH_COMPONENT(16/24/32)
        //settings.wrapModeHorizontal = GL_REPEAT;		// GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER etc.
        //settings.wrapModeVertical = GL_REPEAT;		// GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER etc.
        //settings.minFilter = GL_REPEAT;				// GL_NEAREST, GL_LINEAR etc.
        //settings.maxFilter = GL_REPEAT;				// GL_NEAREST, GL_LINEAR etc.
        settings.numSamples=0;				// number of samples for multisampling (set 0 to disable)

        fbo.allocate(settings);
        fbo.begin();
        ofClear(0);
        int step = 32;
        int numRows, numCols;
        numRows = numCols = fbo.getWidth() / step;
        ofColor color1 = ofColor::white;
        ofColor color2= ofColor::black;

        ofColor lastColor = color1;
        
        for (int y = 0; y < numRows; y++)
        {
            for (int x = 0; x < numCols; x++)
            {
                ofSetColor(lastColor);
                ofDrawRectangle(x * step, y * step, step, step);
                if(lastColor == color1)
                {
                    lastColor = color2;
                }else
                {
                    lastColor = color1;
                }
                if (x + 1 == numCols && x % 2 != 0)
                {
                    if(lastColor == color1)
                    {
                        lastColor = color2;
                    }else
                    {
                        lastColor = color1;
                    }
                }
            }
        }
        
        fbo.end();
        texture = fbo.getTexture();

        
        string shaderHeader = "#version 330\n";
        string vertShaderSource = shaderHeader;
        string fragShaderSource = shaderHeader;
        string geomShaderSource = shaderHeader;
        vertShaderSource += STRINGIFY(
                                      // these are passed in from OF programmable renderer
                                      uniform mat4 modelViewProjectionMatrix;
                                      uniform mat4 modelViewMatrix;
                                      uniform mat4 projectionMatrix;
                                      uniform mat4 textureMatrix;
                                      uniform mat4 normalMatrix;
                                      
                                      in vec4  position;
                                      in vec2  texcoord;
                                      
                                      out VS_OUT {
                                          vec4 texCoordVaryingOut;
                                      }vs_out;
                                      
                                      void main()
                                      {
                                          //enabling this will cause shader to compile but fail even though unused?
                                          //vs_out.texCoordVaryingOut = texcoord.x;
                                          gl_Position = position;
                                          
                                      }
                                      );
        
        geomShaderSource += STRINGIFY(
                                      
                                      layout (points) in;
                                      layout (triangle_strip, max_vertices = 4) out;
                                      uniform mat4 modelViewProjectionMatrix;
                                      out vec4 outputColor;

                                      uniform sampler2DRect geomTexture;
                                      uniform float imgWidth;
                                      uniform float imgHeight;
                                      uniform vec4 globalColor;
                                      out vec2 geomTexCoordVarying;

                                      in VS_OUT {
                                          vec4 texCoordVaryingOut;
                                      } gs_in[];
 
                                      void main()
                                      {
                                          //= gs_in[0].texCoordVaryingOut;
                                          vec4 position =  gl_in[0].gl_Position;
                                          float size = 10.0f;
                                          
                                          vec2 t1 = vec2(0.0f, 0.0f);
                                          vec2 t2 = vec2(imgWidth, 0.0f);
                                          vec2 t3 = vec2(imgWidth, imgHeight);
                                          vec2 t4 = vec2(0.0f, imgHeight);
                                          
                                          vec4 outputPosition;
                                          vec4 tPos;
                                          vec4 localPosition = vec4(-size, -size, 0.0f, 0.0f);    // 1:bottom-left
                                          outputPosition = position + localPosition;
                                          tPos = modelViewProjectionMatrix *outputPosition;
                                          gl_Position = tPos;
                                          geomTexCoordVarying = t3;
                                          outputColor = texture(geomTexture, geomTexCoordVarying)*globalColor;

                                          EmitVertex();
                                          
                                          localPosition =vec4( size, -size, 0.0f, 0.0f);    // 2:bottom-right
                                          outputPosition = position + localPosition;
                                          tPos = modelViewProjectionMatrix *outputPosition;
                                          gl_Position = tPos;
                                          geomTexCoordVarying = t4;
                                          outputColor = texture(geomTexture, geomTexCoordVarying)*globalColor;

                                          EmitVertex();
                                          
                                          localPosition =vec4(-size,  size, 0.0f, 0.0f);    // 3:top-left
                                          outputPosition = position + localPosition;	
                                          tPos = modelViewProjectionMatrix *outputPosition;
                                          gl_Position = tPos;
                                          geomTexCoordVarying = t1;
                                          outputColor = texture(geomTexture, geomTexCoordVarying)*globalColor;

                                          EmitVertex();
                                          
                                          localPosition =vec4( size,  size, 0.0f, 0.0f);    // 4:top-right
                                          outputPosition = position + localPosition;	
                                          tPos = modelViewProjectionMatrix *outputPosition;
                                          gl_Position = tPos;
                                          geomTexCoordVarying = t2;
                                          
                                          outputColor = texture(geomTexture, geomTexCoordVarying)*globalColor;
                                          EmitVertex();
                                          EndPrimitive();
                                      }
                                      );
        //3, 4, 1, 2
        fragShaderSource += STRINGIFY(

                                      in vec4 outputColor;
                                      out vec4 fragColor;
                                      uniform vec4 globalColor;
                                      uniform sampler2DRect geomTexture;
                                      
                                      in vec2 geomTexCoordVarying;
                                      
                                      void main (void)
                                      {
                                          //use the Geometry Shader outputColor
                                          //fragColor = outputColor;
                                          
                                          //ignore the Geometry Shader outputColor
                                          fragColor = texture(geomTexture, geomTexCoordVarying)*globalColor;
                                      }
                                      );
        
        
        
        shader.setupShaderFromSource(GL_VERTEX_SHADER, vertShaderSource);
        shader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragShaderSource);
        shader.setupShaderFromSource(GL_GEOMETRY_SHADER, geomShaderSource);
        shader.linkProgram();
        
        plane.set(256, 256, 5, 5);
        mesh = ofVboMesh(plane.getMesh());
        mesh.setMode(OF_PRIMITIVE_POINTS);
        
    }
    
    void update()
    {
    }
    
    void draw()
    {
 
        
        ofPushStyle();
        camera.begin();
        texture.bind();
        
        shader.begin();
        ofSetColor(ofColor::red, 255);
        //shader.setUniformTexture("geomTexture", texture, 1);
        shader.setUniform1f("imgWidth", texture.getWidth());
        shader.setUniform1f("imgHeight", texture.getHeight());
        mesh.drawFaces();
        mesh.drawWireframe();
        shader.end();
        
        texture.unbind();
        mesh.drawWireframe();
        camera.end();
        ofPopStyle();
        
        texture.draw(0, 0);
    }
    
    void keyPressed (int key)
    {
        
    }
    
};


int main( ){
    ofSetLogLevel(OF_LOG_VERBOSE);
    ofGLFWWindowSettings settings;
    settings.setGLVersion(4, 1);
    settings.width = 1280;
    settings.height = 720;
    ofCreateWindow(settings);
    ofRunApp(new ofApp());
}

The current output above looks like this:

I’ve tried a few things but these seem to make it worse or the texture isn’t drawn at all

  • GL_TEXTURE_2D for the Texture
  • ofDisableArbTex
  • ofEnableNormalizedTexCoords

Stranger things:
In order to pass something from the Vertex Shader to the Geometry Shader I am supposed to use an array. However if I try and do this the shader compiles but fails?

@hahakid ? :slight_smile:

if you are using texture 2d you should just pass 0…1 as texture coordinates so not:

vec2 t1 = vec2(0.0f, 0.0f);
vec2 t2 = vec2(imgWidth, 0.0f);
vec2 t3 = vec2(imgWidth, imgHeight);
vec2 t4 = vec2(0.0f, imgHeight);

but

vec2 t1 = vec2(0.0f, 0.0f);
vec2 t2 = vec2(1, 0.0f);
vec2 t3 = vec2(1, 1);
vec2 t4 = vec2(0.0f, 1);

also not sure what you want to do but it sounds like it would be easier/faster to use instanced drawing than a geometry shader

Thanks @arturo - however that just gives me a red box (as if it’s not textured and is just applying the globalColor)

I tried this with settings.textureTarget = GL_TEXTURE_RECTANGLE_ARB/GL_TEXTURE_2D and with/without ofDisableArbTex(), ofEnableNormalizedTexCoords()

I haven’t tried instanced drawing yet - I’m mostly just using this to try and understand the process.

With GL_TEXTURE_RECTANGLE_ARB, if I add outputPosition.xy to the geomTexCoordVarying

(e.g. geomTexCoordVarying = outputPosition.xy+t3;)

I get this

ok - wow - the issue was that

geomTexCoordVarying = t2; and geomTexCoordVarying = t1; needed to be swapped

:slight_smile: :gun:

updated code:

#include "ofMain.h"

#define STRINGIFY(x) #x

class ofApp : public ofBaseApp
{
    
public:
    
    ofShader shader;
    ofEasyCam camera;
    ofVboMesh mesh;
    ofPlanePrimitive plane;
    ofTexture texture;
    ofFbo fbo;
    void setup()
    {
        ofEnableAlphaBlending();


        ofFbo::Settings settings;
        settings.width = 256;
        settings.height = 256;
        
        settings.textureTarget = GL_TEXTURE_RECTANGLE_ARB;
        settings.internalformat = GL_RGBA;

        fbo.allocate(settings);
        fbo.begin();
        ofClear(0);
        int step = 32;
        int numRows, numCols;
        numRows = numCols = fbo.getWidth() / step;
        ofColor color1 = ofColor::white;
        ofColor color2= ofColor::black;

        ofColor lastColor = color1;
        
        for (int y = 0; y < numRows; y++)
        {
            for (int x = 0; x < numCols; x++)
            {
                ofSetColor(lastColor);
                ofDrawRectangle(x * step, y * step, step, step);
                if(lastColor == color1)
                {
                    lastColor = color2;
                }else
                {
                    lastColor = color1;
                }
                if (x + 1 == numCols && x % 2 != 0)
                {
                    if(lastColor == color1)
                    {
                        lastColor = color2;
                    }else
                    {
                        lastColor = color1;
                    }
                }
            }
        }
        
        fbo.end();
        texture = fbo.getTexture();

        
        string shaderHeader = "#version 330\n";
        string vertShaderSource = shaderHeader;
        string fragShaderSource = shaderHeader;
        string geomShaderSource = shaderHeader;
        vertShaderSource += STRINGIFY(
                                      // these are passed in from OF programmable renderer
                                      uniform mat4 modelViewProjectionMatrix;
                       
                                      
                                      in vec4  position;
                                      in vec2  texcoord;
                                      
                                      void main()
                                      {
                                          gl_Position = position;
                                          
                                      }
                                      );
        
        geomShaderSource += STRINGIFY(
                                      
                                      layout (points) in;
                                      layout (triangle_strip, max_vertices = 4) out;
                                      uniform mat4 modelViewProjectionMatrix;

                                      uniform sampler2DRect geomTexture;
                                      uniform float imgWidth;
                                      uniform float imgHeight;
                                      uniform float size;
                                      uniform vec4 globalColor;
                                      out vec2 geomTexCoordVarying;
                                      vec4 position;
                                      void createVertex(vec4 localPosition, vec2 tPos)
                                      {
                                          vec4 outputPosition;
                                          outputPosition = position + localPosition;
                                          gl_Position = modelViewProjectionMatrix * outputPosition;
                                          geomTexCoordVarying = tPos;
                                          EmitVertex();
                                      }
                                      void main()
                                      {
                                          position =  gl_in[0].gl_Position;
                                          vec2 t1 = vec2(0.0f, 0.0f);
                                          vec2 t2 = vec2(imgWidth, 0.0f);
                                          vec2 t3 = vec2(imgWidth, imgHeight);
                                          vec2 t4 = vec2(0.0f, imgHeight);
                                          
                                          createVertex(vec4(-size, -size, 0.0f, 0.0f), t3);
                                          createVertex(vec4( size, -size, 0.0f, 0.0f), t4);
                                          createVertex(vec4( -size, size, 0.0f, 0.0f), t2);
                                          createVertex(vec4( size, size, 0.0f, 0.0f), t1);
                                          EndPrimitive();
                                      }
                                      );
        //3, 4, 2, 1
        fragShaderSource += STRINGIFY(

                                      out vec4 fragColor;
                                      uniform vec4 globalColor;
                                      uniform sampler2DRect geomTexture;
                                      
                                      in vec2 geomTexCoordVarying;
                                      
                                      void main (void)
                                      {
                                       
                                          fragColor = texture(geomTexture, geomTexCoordVarying)*globalColor;
                                      }
                                      );
        
        
        
        shader.setupShaderFromSource(GL_VERTEX_SHADER, vertShaderSource);
        shader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragShaderSource);
        shader.setupShaderFromSource(GL_GEOMETRY_SHADER, geomShaderSource);
        shader.linkProgram();
        
        plane.set(256, 256, 5, 5);
        mesh = ofVboMesh(plane.getMesh());
        mesh.setMode(OF_PRIMITIVE_POINTS);
        
    }
    
    void update()
    {
    }
    
    void draw()
    {
 
        
        ofPushStyle();
        camera.begin();
        texture.bind();
        
        shader.begin();
        ofSetColor(ofColor::red, 255);
        
        float size = ofGetFrameNum()%100;
        shader.setUniform1f("size", 10);
        
        shader.setUniform1f("imgWidth", texture.getWidth());
        shader.setUniform1f("imgHeight", texture.getHeight());
        mesh.drawFaces();
        mesh.drawWireframe();
        shader.end();
        
        texture.unbind();
        mesh.drawWireframe();
        camera.end();
        ofPopStyle();
        
        texture.draw(0, 0);
    }
    
    void keyPressed (int key)
    {
        
    }
    
};


int main( ){
    ofSetLogLevel(OF_LOG_VERBOSE);
    ofGLFWWindowSettings settings;
    settings.setGLVersion(4, 1);
    settings.width = 1280;
    settings.height = 720;
    ofCreateWindow(settings);
    ofRunApp(new ofApp());
}
1 Like