I am trying to map a texture to objects using GLSL version 330
Here is some code that my help you understanding my problem
Fragment Shader:
#version 330
layout(location = 0) in vec3 vertex;
layout(location = 1) in vec3 vertex_normal;
layout(location = 2) in vec2 texCoord;
out vec2 tCoord;
uniform mat4 modelview;
uniform mat4 projection;
void main() {
gl_Position = projection * modelview * vec4(vertex, 1.0);
tCoord = texCoord;
}
Vertex Shader
#version 330
in vec2 tCoord;
uniform sampler2D texture;
out vec4 color;
void main() {
if(tCoord == vec2(0,0))
color = vec4(1.0,0.0,0.0,1.0);
else
color = vec4(0.0,1.0,0.0,1.0);
}
Loading the Mesh and texture to OpenGL
texture coordinates will be boudn using vertexAttribPointer to position 2 (0 is position and 1 is normal)
Creating the MeshObj
void MeshObj::setData(const MeshData &meshData) {
mIndexCount = meshData.indices.size();
// TODO: extend this method to upload texture coordinates as another VBO //
// - texture coordinates are at location 2 within the shader code
// create local storage arrays for vertices, normals and indices //
unsigned int vertexDataSize = meshData.vertex_position.size();
unsigned int vertexNormalSize = meshData.vertex_normal.size();
unsigned int vertexTexcoordSize = meshData.vertex_texcoord.size();
GLfloat *vertex_position = new GLfloat[vertexDataSize]();
std::copy(meshData.vertex_position.begin(), meshData.vertex_position.end(), vertex_position);
GLfloat *vertex_normal = NULL;
if (vertexNormalSize > 0) {
vertex_normal = new GLfloat[vertexNormalSize]();
std::copy(meshData.vertex_normal.begin(), meshData.vertex_normal.end(), vertex_normal);
}
GLfloat *vertex_texcoord = NULL;
if (vertexTexcoordSize > 0) {
vertex_texcoord = new GLfloat[vertexTexcoordSize]();
std::copy(meshData.vertex_texcoord.begin(), meshData.vertex_texcoord.end(), vertex_texcoord);
}
GLuint *indices = new GLuint[mIndexCount]();
std::copy(meshData.indices.begin(), meshData.indices.end(), indices);
// create VAO //
if (mVAO == 0) {
glGenVertexArrays(1, &mVAO);
}
glBindVertexArray(mVAO);
// create and bind VBOs and upload data (one VBO per available vertex attribute -> position, normal) //
if (mVBO_position == 0) {
glGenBuffers(1, &mVBO_position);
}
glBindBuffer(GL_ARRAY_BUFFER, mVBO_position);
glBufferData(GL_ARRAY_BUFFER, vertexDataSize * sizeof(GLfloat), &vertex_position[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
if (vertexNormalSize > 0) {
if (mVBO_normal == 0) {
glGenBuffers(1, &mVBO_normal);
}
glBindBuffer(GL_ARRAY_BUFFER, mVBO_normal);
glBufferData(GL_ARRAY_BUFFER, vertexNormalSize * sizeof(GLfloat), &vertex_normal[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
}
if (vertexTexcoordSize > 0) {
if (mVBO_texcoord == 0) {
glGenBuffers(1, &mVBO_texcoord);
}
std::cout << "Texture stuff set" << std::endl;
glBindBuffer(GL_ARRAY_BUFFER, mVBO_texcoord);
glBufferData(GL_ARRAY_BUFFER, vertexTexcoordSize * sizeof(GLfloat), &vertex_texcoord[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(2);
}
// init and bind a IBO //
if (mIBO == 0) {
glGenBuffers(1, &mIBO);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexCount * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);
// unbind buffers //
glBindVertexArray(0);
// make sure to clean up temporarily allocated data, if neccessary //
delete[] vertex_position;
if (vertexNormalSize > 0) {
delete[] vertex_normal;
}
if (vertexTexcoordSize > 0) {
delete[] vertex_texcoord;
}
delete[] indices;
}
Render the Scene
glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
glActiveTexture(GL_TEXTURE0);
glm_ModelViewMatrix.top() = glm::translate(glm_ModelViewMatrix.top(),0.0f,-13.0f,-10.0f);
glUniformMatrix4fv(uniformLocations["modelview"], 1, false, glm::value_ptr(glm_ModelViewMatrix.top()));
glBindTexture(GL_TEXTURE_2D, objLoader->getMeshObj("trashbin")->getTexttureID());
glUniform1i(glGetUniformLocation(shaderProgram,"texture"), objLoader->getMeshObj("trashbin")->getTexttureID());
objLoader->getMeshObj("trashbin")->render();
glm_ModelViewMatrix.top() = glm::translate(glm_ModelViewMatrix.top(),-9.0f,-13.0f,-10.0f);
glm_ModelViewMatrix.top() = glm::scale(glm_ModelViewMatrix.top(), 1.5f,1.5f,1.5f);
glUniformMatrix4fv(uniformLocations["modelview"], 1, false, glm::value_ptr(glm_ModelViewMatrix.top()));
glBindTexture(GL_TEXTURE_2D, objLoader->getMeshObj("ball")->getTexttureID());
glUniform1i(glGetUniformLocation(shaderProgram,"texture"), objLoader->getMeshObj("ball")->getTexttureID());
objLoader->getMeshObj("ball")->render();
// restore scene graph to previous state //
glm_ModelViewMatrix.pop();
Render the mesh
void MeshObj::render(void) {
// render your VAO //
if (mVAO != 0) {
glBindVertexArray(mVAO);
glDrawElements(GL_TRIANGLES, mIndexCount, GL_UNSIGNED_INT, (void*)0);
glBindVertexArray(0);
}
}
After all this code, now a short description of my problem:
In my shaders I am currently checking if the texCoord is passed correctly to the shader, but it always stays (0,0).
Where is the problem when uploading the texture coordinates? The same technique is working fine for the vertexPosition and the vertex normal...
glUniform1i(glGetUniformLocation(shaderProgram,"texture"), objLoader->getMeshObj("trashbin")->getTexttureID());
Try passing in the texture unit index (texUnit) instead of the texture object ID (texObj, from a glGenTextures() call).
Generally:
unsigned int texUnit = 0;
glActiveTexture( GL_TEXTURE0 + texUnit );
glBindTexture( GL_TEXTURE_2D, texObj );
glUniform1i( ..., texUnit );
In your case:
glActiveTexture( GL_TEXTURE0 );
...
glBindTexture( GL_TEXTURE_2D, objLoader->getMeshObj("trashbin")->getTexttureID() );
glUniform1i( glGetUniformLocation( shaderProgram, "texture" ), 0 );
You don't give the image to OpenGL at any point with glTexImage2D
Add this below your bind texture in order to give OpenGL your texture
//example parameters, substitute with your own.
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
//just parameters for texture(optional)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Reference to glTexImage2D:
http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml
Related
I exported the Blender Box as a Collada file, I am loading it with Assimp, yet it does not draw properly.
Here is how it looks:
I have tried using .fbx and .obj without success.
is this an error in my code, or is the vertex data not correct?
I checked the normals, they all point in the proper direction,
whats leads me to believe that the orientation of the faces is correct.
Here is my Code:
#include<assimp/Importer.hpp>
#include<assimp/postprocess.h>
#include<assimp/scene.h>
#include<vector>
#include<iostream>
#include<GL/glew.h>
#include<glm/glm.hpp>
#include<glm/gtx/quaternion.hpp>
#include<glm/gtc/quaternion.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<SFML/Window.hpp>
#include<SFML/OpenGL.hpp>
#include<SFML/Graphics.hpp>
#include"Shader.h"
#include"vertex.h"
#include"Cam.h"
#include"obj.h"
int main() {
glewExperimental = GL_TRUE;
if (!glewInit()) {
std::cout << "Glew Failed to initialize" << std::endl;
return -5;
}
glEnable(GL_DEPTH_TEST);
////////////////////////////// WINDOW SHADER CAMERA ///////////////////////////
sf::Window window(sf::VideoMode(800, 600), "OpenGL");
window.setActive(true);
Shader Shader1("vss_min.glsl", "fss_min.glsl");
Cam camera(window);
glm::mat4 modelMatrix(1.0);
modelMatrix = glm::scale(modelMatrix, glm::vec3(0.2, 0.2f, 0.2f));
///////////////////////////// MESH /////////////////////////////////////////
std::vector<vertex> vertices;
std::vector<std::uint32_t> indices;
Assimp::Importer importer;
const aiScene* s = importer.ReadFile("c:/meshes/ext/buntekiste.fbx",aiProcess_Debone);
aiMesh* mesh = s->mMeshes[0];
for (std::uint32_t it = 0; it < mesh->mNumVertices;it++) {
vertex v;
if (mesh->HasPositions())v.pos = vec3(mesh->mVertices[it]);
if (mesh->HasNormals())v.normal = vec3(mesh->mNormals[it]);
if (mesh->HasVertexColors(0))v.color = vec4(mesh->mColors[0][it]);
if (mesh->HasTextureCoords(0))v.uv = vec2(mesh->mTextureCoords[0][it]);
vertices.push_back(v);
}
for (std::uint32_t it = 0; it < mesh->mNumFaces; it++) {
indices.push_back(mesh->mFaces[it].mIndices[0]);
indices.push_back(mesh->mFaces[it].mIndices[1]);
indices.push_back(mesh->mFaces[it].mIndices[2]);
}
std::uint32_t VAO, VBO, IBO, TID;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 12 * sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 12 * sizeof(float), (void*)(6*sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 12 * sizeof(float), (void*)(10*sizeof(float)));
glEnableVertexAttribArray(3);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(std::uint32_t), indices.data(), GL_STATIC_DRAW);
/////////////////////////////// TEXTURE //////////////////////////////////////////////////////
sf::Image img;
img.loadFromFile("c:/textures/buntekiste.png");
glGenTextures(1, &TID);
glBindTexture(GL_TEXTURE_2D, TID);
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_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (img.getPixelsPtr()) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.getSize().x, img.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.getPixelsPtr());
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "Failed to load texture" << std::endl;
return -3;
}
////////////////////////////// MAINLOOP ///////////////////////////////////////////////////////
bool running = true;
while (running)
{
// handle events
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
// end the program
running = false;
}
else if (event.type == sf::Event::Resized)
{
// adjust the viewport when the window is resized
glViewport(0, 0, event.size.width, event.size.height);
}
}
///////////////////// DRAWSTUFF /////////////////////////////////////////
camera.update(),
glClearColor(0.3f, 0.0f, 0.8f,0.7f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 mvp = modelMatrix;
Shader1.set4x4("Model", modelMatrix);
Shader1.set4x4("View", camera.getView());
Shader1.set4x4("Projection", camera.getProjection());
glBindVertexArray(VAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, TID);
Shader1.use();
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
window.display();
}
return 0;
}
FragmentShader:
#version 440
out vec4 FragColor;
in vec4 vertexColor;
in vec3 FragPos;
in vec3 normal;
in vec2 uv;
uniform int textureSwitch;
uniform vec3 lightPos;
uniform sampler2D myTexture;
void main(){
FragColor = texture(myTexture,uv);
}
VertexShader:
#version 440
layout(location =0) in vec3 Pos;
layout(location =1) in vec3 Normal;
layout(location =2) in vec4 Color;
layout(location =3) in vec2 TexCoord;
uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;
out vec4 vertexColor;
out vec3 normal;
out vec3 FragPos;
out vec2 uv;
void main(){
mat4 mvp = Projection *View*Model;
gl_Position = mvp * vec4(Pos,1.0f);
normal = Normal;
uv = TexCoord;
vertexColor = Color;
}
I had the same problem and this works for me: add glEnable(GL_DEPTH_TEST);//enable depth buffer glCullFace(GL_FRONT);//for keep front faces and glDisable(GL_CULL_FACE); - if you have enabled GL_CULL_FACE
I did call glEnable(GL_DEPTH_TEST)
before creating the OpenGL Context.
Calling it afterwards solves it.
Ahh finally:
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.
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.
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);
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.