How to bind a texture to ofVbo correctly

I want to bind a texture to a quad through using ofMesh and ofVbo. But I can’t get the texture but black quad. I have searched some answers, but I still can’t figure it out. Here is my code below:

ofVbo vbo;
ofMesh myMesh;
ofShader shader;
ofImage backgroundImage;

void ofApp::setup(){
	shader.load("shader");

	backgroundImage.loadImage("A.jpg");

	myMesh.addVertex(ofVec3f(-1.0, 1.0, 0.0));
	myMesh.addTexCoord(ofVec2f(0.0, 1.0));

	myMesh.addVertex(ofVec3f(1.0, 1.0, 0.0));
	myMesh.addTexCoord(ofVec2f(1.0, 1.0));

	myMesh.addVertex(ofVec3f(-1.0, -1.0, 0.0));
	myMesh.addTexCoord(ofVec2f(0.0, 0.0));

	myMesh.addVertex(ofVec3f(1.0, 1.0, 0.0));
	myMesh.addTexCoord(ofVec2f(1.0, 1.0));

	myMesh.addVertex(ofVec3f(-1.0, -1.0, 0.0));
	myMesh.addTexCoord(ofVec2f(0.0, 0.0));

	myMesh.addVertex(ofVec3f(1.0, -1.0, 0.0));
	myMesh.addTexCoord(ofVec2f(1.0, 0.0));

	vbo.setMesh(myMesh, GL_STATIC_DRAW);
}

//--------------------------------------------------------------
void ofApp::draw(){
	ofSetColor(255);

	shader.begin();
	backgroundImage.getTextureReference().bind();
	shader.setUniformTexture("sample", backgroundImage.getTextureReference(), 1);
	vbo.draw(GL_TRIANGLES, 0, 6);
	shader.end();
	backgroundImage.getTextureReference().unbind();
}

and my vertex shaders:

// these come from the programmable pipeline
//uniform mat4 modelViewProjectionMatrix;

in vec4 position;
in vec2 texcoord;

// texture coordinates are sent to fragment shader
out vec2 texCoordVarying;

void main()
{
    texCoordVarying = texcoord;
    mat4 modelViewProjectionMatrix = mat4(1.0f);
    gl_Position = modelViewProjectionMatrix * position;
}

fragment shader:

 // these are our textures
uniform sampler2D sample;

// this comes from the vertex shader
in vec2 texCoordVarying;

// this is the output of the fragment shader
out vec4 outputColor;

void main()
{
    vec3 src = texture2D(sample, texCoordVarying).rgb;
    
    outputColor = vec4(src, 1.0);
}

Hi @jhx4979,

Looks like you are using normalized tex coords ( 0 - 1 ) vs. ARB tex coords ( 0 - image width ). If you want to use normalized tex coords and sampler2D (vs. sampler2DRect ) then call ofDisableArbTex() before loading any textures. This will cause images or textures that are loaded to be texture2D. And you will be able to use normalized tex coords.

Hi,

Thank you for your reply. But it seems like only using ofDisableArbTex() can’t solve the problem. I have found some topics may help, after knowing ofDisableAtbTex().


After all, this Arb Texture thing still makes me confuse, but I can draw the texture now.
Thank you again.

I still don’t know how to use texcoord and shader correctly with arbTex() or without arbTex(). Is there anyone could give me a simple example of how to use texcoord and vbo with shader correctly?

Hi @jhx4979,

I put together a simple example. I noticed that when you are setting the vertices that they are very close together, only a couple pixels apart. addVertex( 1.0, 1.0, 0.0 ), etc. I also changed the backgroundImage variable to be a texture; there is no need for bind / unbind. The shader code you are using requires the programmable renderer. Not sure if you are using it or not, but I have included the main.cpp for clarity in how to set it. Also notice the change from sampler2D to sampler2DRect in the frag shader. sampler2DRect is used for Arb textures. Arb textures are enabled by default in OpenFrameworks.

//main.cpp

#include "ofMain.h"
#include "ofApp.h"
#include "ofAppGLFWWindow.h"

//========================================================================
int main( ){
    
    ofGLFWWindowSettings settings;
// tell the window to use the programmable renderer //
    settings.setGLVersion(3, 2);
    settings.width = 1200;
    settings.height = 800;
    auto win = ofCreateWindow(settings);
    
    auto app = make_shared<ofApp>();
    
    ofRunApp( win, app );
    ofRunMainLoop();
}

ofApp.h

ofVbo vbo;
    ofMesh myMesh;
    ofShader shader;
    ofTexture backgroundImage;

// ofApp.cpp

//--------------------------------------------------------------
void ofApp::setup(){
    shader.load("texture");
    
    if(!ofLoadImage( backgroundImage, "ofscanner.png" )) {
        cout << "Unable to load image from ofscanner.png" << endl;
    }
    
// set to control the size of the output image vertices //
    float drawWidth = backgroundImage.getWidth()/2.;
    float drawHeight = backgroundImage.getHeight()/2.;
    
// vars used for setting tex coords. The image is an arb texture, meaning the tex coords need to be 0->image width and 0 -> image height.
    float texWidth = backgroundImage.getWidth();
    float texHeight = backgroundImage.getHeight();
    
    // top left
    myMesh.addVertex(ofVec3f(0, 0, 0.0));
    myMesh.addTexCoord(ofVec2f(0.0, 0.0));
    
    myMesh.addVertex(ofVec3f(drawWidth, 0.0, 0.0));
    myMesh.addTexCoord(ofVec2f(texWidth, 0.0));
    
    myMesh.addVertex(ofVec3f(0.0, drawHeight, 0.0));
    myMesh.addTexCoord(ofVec2f(0.0, texHeight));
    
    myMesh.addVertex(ofVec3f(drawWidth, 0.0, 0.0));
    myMesh.addTexCoord(ofVec2f(texWidth, 0.0));
    
    myMesh.addVertex(ofVec3f(drawWidth, drawHeight, 0.0));
    myMesh.addTexCoord(ofVec2f(texWidth, texHeight));
    
    myMesh.addVertex(ofVec3f(0.0, drawHeight, 0.0));
    myMesh.addTexCoord(ofVec2f(0.0, texHeight));
    
    vbo.setMesh(myMesh, GL_STATIC_DRAW);
}

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

}

//--------------------------------------------------------------
void ofApp::draw(){
    ofSetColor(255);
    
    shader.begin();
    shader.setUniformTexture("tex0", backgroundImage, 1);
    vbo.draw(GL_TRIANGLES, 0, 6);
    shader.end();
}

// vertex shader

#version 150

// these come from the programmable pipeline
in vec4 position;
in vec2 texcoord;

uniform mat4 modelViewProjectionMatrix;

// texture coordinates are sent to fragment shader
out vec2 texCoordVarying;

void main() {
	//set the pos to be that actual position rendered
	gl_Position = modelViewProjectionMatrix * position;
    texCoordVarying = texcoord;
}

// frag shader

#version 150

// these are our textures
uniform sampler2DRect tex0;

// this comes from the vertex shader
in vec2 texCoordVarying;

// this is the output of the fragment shader
out vec4 outputColor;

void main() {
    vec3 src = texture(tex0, texCoordVarying).rgb;
    outputColor = vec4(src, 1.0);
}

Hi,
Thank you very much for your reply, I learn lots of things from it.

The main question for me is that every OpenGL tutorial I found begins with vertex [-1, 1] and UV [0, 1]. So when I know the Arb Texture, I really feel confused. What’s more, I notice that you don’t set the value of modelViewProjectionMatrix, so I believe there is a default ViewProjectionMatrix in OpenFrameWork. Am I right? That is one more thing make me confused before, I used to set the ViewProjectionMatrix to a glm::Matrix4(1.0f).

Yes, most OpenGL tutorials use normalized vertex and texture coordinates. OF uses screen coordinates, the width and height of the window in pixels and defaults to ARB textures. You could use an OF camera and position it to achieve the vertex coordinates of -1 to 1 and call ofDisableArbTex() before loading textures to get UV[0,1]
OF sets some default shader values. They are listed at the top of ofGLProgrammableRenderer.cpp

static const string VIEW_MATRIX_UNIFORM="viewMatrix";
static const string MODELVIEW_MATRIX_UNIFORM="modelViewMatrix";
static const string PROJECTION_MATRIX_UNIFORM="projectionMatrix";
static const string MODELVIEW_PROJECTION_MATRIX_UNIFORM="modelViewProjectionMatrix";
static const string TEXTURE_MATRIX_UNIFORM="textureMatrix";
static const string COLOR_UNIFORM="globalColor";

static const string USE_TEXTURE_UNIFORM="usingTexture";
static const string USE_COLORS_UNIFORM="usingColors";
static const string BITMAP_STRING_UNIFORM="bitmapText";