Passing texture to shader in OpenGL - c++

I'm working on some examples, and I was trying to pass a texture to a shader.
To build a VAO, I have this piece of code:
void PlaneShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), _coordinates, GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), _indexes, GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("floor.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
This is how I load the shader attributes:
void PlaneShaderProgram::LoadAttributeVariables()
{
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
void PlaneShaderProgram::LoadUniformVariables()
{
// OpenGL Matrices
GLuint ModelViewProjection_location = glGetUniformLocation(GetProgramID(), "mvpMatrix");
glUniformMatrix4fv(ModelViewProjection_location, 1, GL_FALSE, glm::value_ptr(_ModelViewProjection));
// Floor texture
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, _texture);
// GLint Texture_location = glGetUniformLocation(GetProgramID(), "texture");
// glUniform1i(Texture_location, 0);
}
And my LoatTexture:
GLuint ProgramManager::LoadTexture(const char* imagepath)
{
unsigned char * data = LoadBMP(imagepath, &width, &height);
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
Finally, my draw function, which is called in the OpenGL main loop, is the following:
void PlaneShaderProgram::DrawPlane(const glm::mat4 &Projection, const glm::mat4 &ModelView)
{
_ModelViewProjection = Projection * ModelView;
_ModelView = ModelView;
Bind();
glBindVertexArray(_vao);
LoadUniformVariables();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
UnBind();
}
What I didn't get is that even if I didn't set the uniform texture (commented in the code) used by my shader, the plane is still draw using the texture. This makes no sense for me. Once the shader requires a sample2D, I think this shouldn't work and return some error.
Vertex Shader:
uniform mat4 mvpMatrix;
in vec4 vPosition;
smooth out vec2 uvCoord;
void main()
{
uvCoord = vPosition.xz;
gl_Position = mvpMatrix * vPosition;
}
Frag Shader:
uniform sampler2D texture;
in vec2 uvCoord;
out vec4 fragColor;
void main()
{
fragColor.rgb = texture(texture, uvCoord).rgb;
};
Am I missing something? Somehow this works I don't understand why, but I really like to.

The sampler data types in GLSL reference the texture unit, not a texture object. By default, uniforms will be initialized to 0, so if you don't set the sampler uniforms, they will sample from texture unit 0 (which is also the default unit). In your ProgramManager::LoadTexture() method, you bind the newly created texture, and very likely you are still using GL_TEXTURE0 as the currently active texture unit. You never seem to unbind it, so it is still bound at the time of the draw call, and the shader can access it.

Related

Model disappear when adding a new texture opengl

I tried to load the same model(modeled in 3Ds max) in opengl, but with different textures. The problem is, that when I try to bind the Texture with glBindTexture after I have acitvated the texture, then it disappears. Before I changed the textures in 3Ds max, it always has show me the model in black color (just in opengl). But I havenĀ“t even assign black color to my model. My image "model-image.png" also contains all textures, that I have assign to my object. So am I missing something?
Thanks for your help in advance.
void initDrawing()
{
glEnable(GL_DEPTH_TEST);
program = glCreateProgram();
std::string shaderV = Utilities::loadFile("shader.vert");
std::string shaderF = Utilities::loadFile("shader.frag");
program = Utilities::compileShader(shaderV, shaderF);
Utilities::loadObj("model.obj", obj);
Utilities::loadPNG("model-image.png", diffuse);
glEnable(GL_TEXTURE_2D);
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &vPosition);
glBindBuffer(GL_ARRAY_BUFFER, vPosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4)*obj.vertices.size(), &obj.vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vPosition);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
GLuint vCoordinates;
glGenBuffers(1, &vCoordinates);
glBindBuffer(GL_ARRAY_BUFFER, vCoordinates);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2)*obj.textureCoordinates.size(), &obj.textureCoordinates[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vCoordinates);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glGenTextures(2, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, diffuse.width, diffuse.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
&diffuse.colors[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUseProgram(program);
ModelView = glGetUniformLocation(program, "ModelView");
Projection = glGetUniformLocation(program, "Projection");
Diffuse = glGetUniformLocation(program, "Diffuse");
}
void display()
{
// background color
const GLfloat color[] = { 0.5, 0.5, 0.5, 1 };
glClear(GL_DEPTH_BUFFER_BIT);
glClearBufferfv(GL_COLOR, 0, color);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
modelView = view * model;
glUniformMatrix4fv(ModelView, 1, GL_FALSE, glm::value_ptr(modelView));
glUniformMatrix4fv(Projection, 1, GL_FALSE, glm::value_ptr(projection));
glUniform1i(Diffuse, 0);
glDrawArrays(GL_TRIANGLES, 0, obj.vertices.size());
glutSwapBuffers();
}
My Shader:
fragment shader:
uniform sampler2D Diffuse;
in vec2 fUV;
out vec3 color;
//main for the color
void main(void)
{
color = texture(Diffuse, fUV).rgb;
}
vertex Shader:
layout (location = 0) in vec4 vPosition;
layout (location = 2) in vec2 vCoordinates;
uniform mat4 ModelView;
uniform mat4 Projection;
out vec2 fUV;
void main(void)
{
gl_Position = Projection * ModelView * vPosition;
fUV = vCoordinates;
}
My guess is that when you say
layout(location = 2) in vec2 vCoordinates;
you really mean to say
layout(location = 1) in vec2 vCoordinates;
considering you never enable vertex attribute 2.

OpenGL GLSL texture function always returning vec4(1,1,1,1), white triangle

I'm trying to work on a texture mapping 2D to a triangle. But currently, I can only get a triangle that has a gradient colour without any texture on it. Which means, my texture function in glsl always return vec4(1,1,1,1) and my textCoords is working. How should I fix it? Any suggestions would be helpful to try!
By the way, have been working on this for 3 days.
in texture class:
constructor:
Texture::Texture(const std::string& fileName){
int width, height, numComponents;
//float* imageData = stbi_loadf(fileName.c_str(), &width, &height, &numComponents, 4);
unsigned char* imageData = stbi_load(fileName.c_str(), &width, &height, &numComponents, 4);
if(imageData == NULL){
cerr << "Texture loading failed for "<<fileName<< endl;
}
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
}
Texture binding function:
void Texture::Bind(){
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_texture);
}
In my main.cpp:
m_shader.generateProgramObject();
m_shader.attachVertexShader( getAssetFilePath("VertexShader.vs").c_str() );
m_shader.attachFragmentShader( getAssetFilePath("FragmentShader.fs").c_str() );
m_shader.link();
// texture created here
texture = Texture("Assets/bricks.jpg");
// enable vertex attribute indices
glGenVertexArrays(1, &m_vao_triangle);
glBindVertexArray(m_vao_triangle);
// Enable the attribute index location for "position" when rendering.
GLint positionAttribLocation = m_shader.getAttribLocation( "position" );
glEnableVertexAttribArray(positionAttribLocation);
GLint textCoordLocation = m_shader.getAttribLocation( "atextCoord" );
glEnableVertexAttribArray(textCoordLocation);
// Restore defaults
glBindVertexArray(0);
CHECK_GL_ERRORS;
uploade triangle data to buffer
vec3 triangleVertices[] = {
// Construct equalaterial triangle
vec3(0.0f, 0.0f, 0.0f),
vec3(0.25f, 1.0f, 0.0),
vec3(0.5f, 0.0f, 0.0f)
};
vec2 textCoords[] = {
vec2(1.0f, 0.0f),
vec2(0.25f, 1.0f),
vec2(0.5f, 0.0f)};
// Generate a vertex buffer object to hold the triangle's vertex data.
glGenBuffers(1, &m_vbo_triangle);
//-- Upload triangle vertex data to the vertex buffer:
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_triangle);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices,
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
CHECK_GL_ERRORS;
//====generate buffer for holding texture coordinates====
glGenBuffers(1, &m_uv_triangle);
glBindBuffer(GL_ARRAY_BUFFER, m_uv_triangle);
glBufferData(GL_ARRAY_BUFFER, sizeof(textCoords), textCoords,
GL_STATIC_DRAW);
// Unbind the target GL_ARRAY_BUFFER, now that we are finished using it.
glBindBuffer(GL_ARRAY_BUFFER, 0);
CHECK_GL_ERRORS;
map buffer data to shader
glBindVertexArray(m_vao_triangle);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_triangle);
GLint positionAttribLocation = m_shader.getAttribLocation( "position" );
glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, m_uv_triangle);
GLint textCoordLocation = m_shader.getAttribLocation( "atextCoord" );
glVertexAttribPointer(textCoordLocation,2, GL_FLOAT, GL_FALSE, 0, nullptr);
//-- Unbind target, and restore default values:
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
CHECK_GL_ERRORS;
upload uniform to shader
m_shader.enable();
...
GLint uniformLocation_diffuse = m_shader.getUniformLocation("diffuse");
glUniform1i(uniformLocation_diffuse, 0);
CHECK_GL_ERRORS;
m_shader.disable();
CHECK_GL_ERRORS;
And in my draw function:
glBindVertexArray(m_vao_triangle);
// below I tried, but didn't work
// glClear(GL_STENCIL_BUFFER_BIT);
// glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// glEnable(GL_DEPTH_TEST);
texture.Bind();
// do these below:
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, texture.m_texture);
m_shader.enable();
glDrawArrays(GL_TRIANGLES, 0, 3);
m_shader.disable();
// Restore defaults
glBindVertexArray(0);
CHECK_GL_ERRORS;
Here I will also attach my shaders
vertex shader:
#version 330
in vec3 position;
in vec2 atextCoord;
uniform mat4 transform;
out vec2 textCoord;
void main() {
gl_Position = transform * vec4(position, 1.0);
textCoord = atextCoord;
}
And my fragment shader:
#version 330
uniform sampler2D diffuse;
out vec4 fragColor;
in vec2 textCoord;
void main() {
fragColor = vec4(texture(diffuse, textCoord).rgb,1.0) * vec4(textCoord,0.0,1.0);
// texture(...) shows vec4(1,1,1,1)
// radiant colour can only prove my textCoord is working
// fragColor = texture(diffuse, textCoord); <- only shows a default texture
}
here is the running result
Here is the texture image
I found one way to make it work.
I copy every lines in Texture constructor and paste it to draw(), instead calling texture.Bind().
Looks like I make a texture just before it's ready to draw a geometry and this way is working.
But I still have to know why it happens like that. For coding style, I still have to put my code in Texture class. Would you mind to provide a solution that what happened before?
it looks like this right now

Multiple [in] attributes in shader - OpenGL

I'm to learn OpenGL 4 and now I working with textures. I would like to apply a texture to a sphere, and my vertex shader looks like this:
#version 410
in vec4 vPosition;
in vec2 texCoord;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
smooth out vec2 uvCoord;
void main (void)
{
uvCoord = texCoord;
vec3 vNormal = vPosition.xyz / vPosition.w;
vVaryingNormal = normalMatrix * vNormal;
vec4 vPosition4 = mvMatrix * vPosition;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
vVaryingLightDir = normalize(vLightPosition - vPosition3);
gl_Position = mvpMatrix * vPosition;
}
After defining the coordinates and triangulation indexes of a sphere, I build a VAO with the following code:
void SphereShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _sphereCoordinates.size() * sizeof(float), &_sphereCoordinates[0], GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _sphereIndexes.size() * sizeof(unsigned int), &_sphereIndexes[0], GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("ball.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
GLuint ProgramManager::LoadTexture(const char* imagepath)
{
unsigned int width, height;
unsigned char * data = LoadBMP(imagepath, &width, &height);
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
To load the attributes, I did the following (before using texture):
void SphereShaderProgram::LoadAttributeVariables()
{
// Vertex Attributes
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
Now, however, I have an array (_sphereTexCoords) which contains the texture coordinates and I don't really know how to pass it to the vertex shader as the vertex coordinates are passed. Do I have to create another VBO? I though of doing something like this:
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
But I don't really know how to specify that this is related to the _sphereTexCoords array.
EDIT
I tried this, but it didn't work.
void SphereShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(2, _vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glBufferData(GL_ARRAY_BUFFER, _sphereCoordinates.size() * sizeof(float), &_sphereCoordinates[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glBufferData(GL_ARRAY_BUFFER, _textureCoordinates.size() * sizeof(float), &_textureCoordinates[0], GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _sphereIndexes.size() * sizeof(unsigned int), &_sphereIndexes[0], GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("ball.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
void SphereShaderProgram::LoadAttributeVariables()
{
// Vertex Attributes
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
}
I get an error when binding the program.
You're very close. The only thing I see missing is that you do not bind the correct buffer before calling glVertexAttribPointer(). When you call glVertexAttribPointer(), you specify that the data for the attribute will be pulled from the buffer that is currently bound to GL_ARRAY_BUFFER.
Your LoadAttributeVariables() method should therefore be:
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);

Opengl Textures without Texture image Units

recently i found an Opengl example that applies a single texture without specifying texture image unit and without sending the corresponding unit integer uniform into the shader, is it possible to apply textures without using texture units?? or it simply uses a default value for both active texture unit and its shader sampler value.
my code block (texture related):
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint TextureID = 0;
SDL_Surface* Surface = IMG_Load("Abrams_Tank.jpg");
glGenTextures(1, &TextureID);
glBindTexture(GL_TEXTURE_2D, TextureID);
int Mode = GL_RGB;
if(Surface->format->BytesPerPixel == 4) {
Mode = GL_RGBA;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Surface->w, Surface->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, Surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLuint vbo;
GLuint vbo_Text;
GLuint vao;
glGenBuffers(1, &vbo);
glGenBuffers(1, &vbo_Text);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData) * 30,vertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(float) * 18));
glDrawArrays(GL_TRIANGLES, 0,6);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(0, vbo);
my fragment shader:
#version 410
in vec2 texCoordout;
uniform sampler2D mysampler;
out vec4 Fcolor;
void main()
{
Fcolor = texture (mysampler, texCoordout);
}
This will work, and is within specs:
The default texture unit is GL_TEXTURE0, so there is no need to ever call glActiveTexture() if only texture unit 0 is used.
Uniforms have a default value of 0, which is the correct value for a sampler that references texture unit 0.
I would still always set the uniform values just to make it explicit. If you don't set the uniform in this case, it is also much more likely that you will miss to set it if you ever use a texture unit other than 0.

How to store an array into a texture and sampler the texture in vertex shader correctly?

I'm a new learner about OpenGL and GLSL. I'm coding a program in which i wanna store a group of datas in a texture and get the data by sampling the texture in vertex shader. Then i want to set the datas as the y coodinates of terrain positions. But i get a trouble that it's failed and i can't get a correct value___all the y coodinates are 0.
The main code is below:
GLuint terrainShader; // The perspective demonstration shader
GLint locMVP,locTex; // The location of the uniform in vertex shader
GLuint vao; // The VAO
GLuint vertexBuffer;
GLuint elementBuffer;
GLuint vertexTexture;
const int n=127;
float verteces[n*n*2];// vertex array
GLuint vIndexFine[(n-1)*2*n];//index array
GLsizei countFine[n-1];
GLvoid* offsetFine[n-1];
float *data=new float[n*n];
terrainShader = gltLoadShaderPairWithAttributes("terrain.vp", "terrain.fp", 1,
GLT_ATTRIBUTE_VERTEX, "vVertex");
locMVP = glGetUniformLocation(terrainShader, "mvpMatrix");
locTex = glGetUniformLocation(terrainShader, "vertexTexture");
//creat a terrain with size of n*n
for(int i=0;i<n;i++)
{
int sum=i*n;
for(int j=0;j<n;j++)
{
verteces[(sum+j)*2]=float(j);
verteces[(sum+j)*2+1]=float(i);
}
}
//initialize the index array
for(int i=0;i<n-1;i++)
{
if(i==0) //the first line
{
for(int j=0;j<n;j++)
{
vIndexFine[2*j]=j;
vIndexFine[2*j+1]=j+n;
}
}
else
{ //if it's not the first line,then just add n to get the indexes of new line
for(int k=0;k<2*n;k++)
{
vIndexFine[i*2*n+k]=vIndexFine[(i-1)*2*n+k]+n;
}
}
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(verteces), verteces, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vIndexFine), vIndexFine, GL_STATIC_DRAW);
//initialize data array with random integers between 1 and 100
for(int i=0;i<n*n;i++)
data[i]=float(rand()%100)/100.0;
//creat a texture and store data
glGenTextures(1, &vertexTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, vertexTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, n,n, 0,GL_RED, GL_FLOAT, data);
//compute every trianglestrip's indexcount and offset
int temp=n*2*sizeof(GLuint);
for(int i=0;i<n-1;i++)
{
offsetFine[i]=(void*)(temp*i);
countFine[i]=GLsizei(n*2);
}
glUseProgram(terrainShader);
glUniform1i(locTex, 0);
modelViewMatrix.PushMatrix(viewFrame);
modelViewMatrix.Translate(-n/2.0, -10.0f, -n/2.0);
glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
glMultiDrawElements(GL_TRIANGLE_STRIP,countFine,GL_UNSIGNED_INT, (const GLvoid**)offsetFine,n-1);
modelViewMatrix.PopMatrix();
the vertex shader:
#version 410
uniform mat4 mvpMatrix;
uniform sampler2D vertexTexture;
in vec2 vVertex;
void main(void)
{
vec2 vTexCoords=vVertex/127.0;
float height = texture2DLod(vertexTexture, vTexCoords,0.0).x*100.0;
vec4 position=vec4(vVertex.x,height,vVertex.y,1.0);
gl_Position = mvpMatrix * position;
}
i think the mistake must be the part of storing datas in application or the part of fetching datas from the texture in vertex shader. can sombody point it out for me?
It's solved now.the answer is here
Try setting the texture's minification filter to GL_NEAREST or GL_LINEAR after glTexImage2D():
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
The OpenGL default is to use mipmaps and you didn't send any which makes the texture incomplete and will disable that texture image unit.
Then you can use texture(vertexTexture, vTexCoords) inside the shader instead of the deprecated texture2DLOD() version with the explicit LOD access.