Is there a reason as to why my mesh isn't drawing correctly? I loaded an .OBJ model from a file and tried to draw it but it always comes out deformed. Any help would be appreciated.
Here is my code:
void Renderer::draw_model(const std::vector<Vector3>& vertex_array, const std::vector<unsigned int>& element_array, const std::vector<Vector2>& uv_array, const std::vector<Vector3>& normal_array, double x, double y, double z, double rx, double ry, double rz, double sx, double sy, double sz, const std::vector<Texture *>& texture_array, double red, double green, double blue, double alpha)
{
#ifdef DOKUN_OPENGL // OpenGL is defined
if(get_current_rendering_API() != "OpenGL") // but it is not set as the current rendering API
return;
#ifdef __windows__
if(!wglGetCurrentContext())
{
Logger("Rendering Failed : No OpenGL Context found");
return;
}
#endif
#ifdef __gnu_linux__
#ifdef DOKUN_X11
if(!glXGetCurrentContext())
{
Logger("Rendering failed : No OpenGL Context found");
return;
}
#endif
#endif
if(vertex_array.empty())
{
Logger("Rendering failed : Vertex list is empty!");
return;
}
if(element_array.empty())
{
Logger("Rendering failed : Element list is empty!");
return;
}
const GLchar * vertex_source[] =
{
"#version 400\n"
"layout(location = 0) in vec3 position;\n"
"layout(location = 1) in vec2 tex_coord;\n"
"layout(location = 2) in vec3 normal;\n"
" \n"
" \n"
" \n"
"uniform mat4 proj; // zooming \n"
"uniform mat4 view; // camera pos \n"
"uniform mat4 model; // object \n"
" \n"
" \n"
" \n"
" \n"
"out vec3 Normal ;\n"
"out vec2 Texcoord;\n"
"\n"
"out vec3 frag_position;\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"void main(void) \n"
"{ \n"
"//frag_position = vec3(model * vec4(position, 1));\n"
"Texcoord = tex_coord;\n"
"Normal = mat3(transpose(inverse(model))) * normal;//normal;\n"
"gl_Position = proj * view * model * vec4(position, 1.0);\n"
"} \n"
};
const GLchar * fragment_source[] = // holds all color
{
"#version 400 \n"
" \n"
"out vec4 out_color; \n"
"uniform vec4 color;\n"
"\n"
"\n"
"in vec3 Normal ;\n"
"in vec2 Texcoord;\n"
"\n"
"in vec3 frag_position;\n"
"\n"
"\n"
"\n"
"uniform vec3 light_color ;\n"
"uniform vec3 light_position;\n"
"\n"
"\n"
"\n"
"void main(void) \n"
"{ \n"
"\n"
"vec3 light_direction = normalize(light_position - frag_position);\n"
"vec3 ambient = 0.1f * light_color;\n"
"vec3 diffuse = max(dot(normalize(Normal), light_direction), 0.0) * light_color;\n"
"\n"
"\n"
"out_color = vec4((ambient + diffuse) * color.xyz, 1.0); \n"
"} \n"
};
glEnable(GL_DEPTH_TEST); // enable depth
glEnable(GL_CULL_FACE );
// Set mode
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // GL_POINT, GL_LINE, GL_FILL,
//--------------
// shaders
Shader vertex_shader ;
Shader fragment_shader;
vertex_shader.create(DOKUN_SHADER_VERTEX);
vertex_shader.set_source(vertex_source);
vertex_shader.compile();
fragment_shader.create(DOKUN_SHADER_FRAGMENT);
fragment_shader.set_source(fragment_source);
fragment_shader.compile();
// program
Program program;
program.create();
program.attach(vertex_shader );
program.attach(fragment_shader);
program.link();
// delete shaders after linking them to the program
vertex_shader.destroy ();
fragment_shader.destroy();
// use program
program.use ();
//---------------
// set uniforms
////////////////////////
// light
if(program.get_uniform("light_color" ) != -1) program.set_uniform("light_color", 1.0f, 1.0f, 1.0f);//, (alpha / 255));
if(program.get_uniform("light_position" ) != -1) program.set_uniform("light_position", 1,1,1);//static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));//, (alpha / 255));
////////////////////////
// camera
glm::vec3 eye = glm::vec3(camera->get_position().x, camera->get_position().y, camera->get_position().z);
glm::vec3 center = glm::vec3(camera->get_position().x + camera->get_view().x, camera->get_position().y + camera->get_view().y, camera->get_position().z + camera->get_view().z);
glm::vec3 up = glm::vec3(camera->get_up().x , camera->get_up().y , camera->get_up().z);
////////////////////////
#ifdef use_glm
glm::mat4 model;
model = glm::scale(model, glm::vec3(static_cast<float>(sx),
static_cast<float>(sy),
static_cast<float>(sz)));
model = glm::rotate(model, static_cast<float>(rx), glm::vec3(1, 0, 0));
model = glm::rotate(model, static_cast<float>(ry), glm::vec3(0, 1, 0));
model = glm::rotate(model, static_cast<float>(rz), glm::vec3(0, 0, 1));
model = glm::translate(model, glm::vec3(static_cast<float>(x),
static_cast<float>(y),
static_cast<float>(z)));
glm::mat4 view = glm::lookAt(eye, center, up);
glm::mat4 proj = glm::perspective(67.5f, static_cast<float>(800 / 600), 1.0f, 1024.0f); // average fov = 67.5 45 + 90 = 135 / 2 = 67.5 | znear=1 zfar=1024
glm::mat4 modelview = model * view;
glUniformMatrix4fv(glGetUniformLocation((GLuint)program.get_id(), "model"), 1, false, glm::value_ptr(model) ); // object
glUniformMatrix4fv(glGetUniformLocation((GLuint)program.get_id(), "view"), 1, false, glm::value_ptr(view) ); // camera
glUniformMatrix4fv(glGetUniformLocation((GLuint)program.get_id(), "proj"), 1, false, glm::value_ptr(proj) ); // zoom
#endif
////////////////////////
if(program.get_uniform("color") != -1) program.set_uniform("color", (red / 255), (green / 255), (blue / 255), (alpha / 255));
//program.get_default()->set_uniform("base", static_cast<int>(0)); // bind to texture unit 0
////////////////////////
// texture data
/*
GLuint * texture = new GLuint[8]; // 256 would be ideal
for(unsigned int i = 0; i < texture_array.size(); i++) // for each texture
{
std::cout << "GENERATING TEXTURES...." << std::endl;
glGenTextures(8, texture); // generate 256 textures
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture( GL_TEXTURE_2D, (GLuint)texture[i] );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texture_array[i]->get_width(), texture_array[i]->get_height(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, texture_array[i]->get_data() );
glGenerateMipmap(GL_TEXTURE_2D);
}
*/
///////////////////////
///////////////////////
// vertex array obj
GLuint vertex_array_obj;
glGenVertexArrays(1, &vertex_array_obj);
// vertex buffer obj - for drawing
glBindVertexArray(vertex_array_obj); // bind vertex array obj to vertex attrib ptr
GLuint vertex_buffer_obj;
glGenBuffers(1, & vertex_buffer_obj);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj);
glBufferData(GL_ARRAY_BUFFER, vertex_array.size() , &vertex_array[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_DOUBLE, GL_FALSE, 0, static_cast<void*>(0));
glBindVertexArray(0); // unbind
// tex_coord buffer obj - for texture mapping
GLuint uv_buffer_obj;
if(!uv_array.empty())
{
glBindVertexArray(vertex_array_obj); // bind
glGenBuffers(1, & uv_buffer_obj);
glBindBuffer(GL_ARRAY_BUFFER, uv_buffer_obj);
glBufferData(GL_ARRAY_BUFFER, uv_array.size() , &uv_array[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, 0, static_cast<void*>(0));
glBindVertexArray(0); // unbind
}
// normal buffer - for lighting
GLuint normal_buffer_obj;
if(!normal_array.empty())
{
glBindVertexArray(vertex_array_obj); // bind
glGenBuffers(1, & normal_buffer_obj);
glBindBuffer(GL_ARRAY_BUFFER, normal_buffer_obj);
glBufferData(GL_ARRAY_BUFFER, normal_array.size(), &normal_array[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_DOUBLE, GL_FALSE, 0, static_cast<void*>(0));
glBindVertexArray(0); // unbind
}
// element buffer - specifies order in which vertices are to be drawn
glBindVertexArray(vertex_array_obj); // bind
GLuint index_buffer_obj;
glGenBuffers(1, & index_buffer_obj);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, element_array.size(), &element_array[0], GL_STATIC_DRAW);
glBindVertexArray(0);
// Draw the model !
glBindVertexArray(vertex_array_obj); // bind
glDrawElements(GL_TRIANGLES, element_array.size(), GL_UNSIGNED_INT, 0);//glDrawElements(GL_TRIANGLES, element_array.size(), GL_UNSIGNED_INT, &element_array[0]); // elements - order in which vertices are to be drawn
glBindVertexArray(0); // unbind
////////////////////////
// cleanup
// textures
//if(texture_array.size() > 0)
// glDeleteTextures(8, texture);
// attributes
glDisableVertexAttribArray(0); // drawing
glDisableVertexAttribArray(1); // texture mapping
glDisableVertexAttribArray(2); // lighting
// buffers
glDeleteBuffers(1, & vertex_buffer_obj );
glDeleteBuffers(1, & uv_buffer_obj );
glDeleteBuffers(1, & normal_buffer_obj );
glDeleteBuffers(1, & index_buffer_obj );
// arrays
glDeleteVertexArrays(1, & vertex_array_obj);
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// program
program.disable();
#endif
}
And this is the result of the following code:
The size parameter in all glBufferData calls is wrong. This function expects the amount of data in byte, but are supplied, for example, in this line:
glBufferData(GL_ARRAY_BUFFER, vertex_array.size() , &vertex_array[0], GL_STATIC_DRAW);
as the number of elements. What you actually need is something like this:
glBufferData(GL_ARRAY_BUFFER, vertex_array.size() * sizeof(Vector3), &vertex_array[0], GL_STATIC_DRAW);
(assuming that Vector3 contains exactly 3 doubles).
As a side note: It is rather uncommon to supply vertex information in double precision. So if there is no special reason for doing this, I would recommend using float instead.
Related
I have a simple vertex shader
static const char *vertexShader=
"attribute vec4 vPosition; \n"
"void main(){\n"
"gl_Position = vPosition;\n"
"}";
Also I have a shader which creates a "Billboard" effect on an image.
static const char *fragmentShader=
"uniform float grid;\n"
"uniform float dividerValue;\n"
"uniform float step_x;\n"
"uniform float step_y;\n"
"uniform sampler2D source;\n"
"uniform lowp float qt_Opacity;\n"
"uniform vec2 qt_TexCoord0;\n"
"void main(){\n"
"vec2 uv = qt_TexCoord0.xy;\n"
"float offx = floor(uv.x / (grid * step_x));\n"
"float offy = floor(uv.y / (grid * step_y));\n"
"vec3 res = texture2D(source, vec2(offx * grid * step_x , offy * grid * step_y)).rgb;\n"
"vec2 prc = fract(uv / vec2(grid * step_x, grid * step_y));\n"
"vec2 pw = pow(abs(prc - 0.5), vec2(2.0));\n"
"float rs = pow(0.45, 2.0);\n"
"float gr = smoothstep(rs - 0.1, rs + 0.1, pw.x + pw.y);\n"
"float y = (res.r + res.g + res.b) / 3.0;\n"
"vec3 ra = res / y;\n"
"float ls = 0.3;\n"
"float lb = ceil(y / ls);\n"
"float lf = ls * lb + 0.3;\n"
"res = lf * res;\n"
"vec3 col = mix(res, vec3(0.1, 0.1, 0.1), gr);\n"
"if (uv.x < dividerValue)\n"
"gl_FragColor = qt_Opacity * vec4(col, 1.0);\n"
"else\n"
"gl_FragColor = qt_Opacity * texture2D(source, uv);\n"
"}";
What I'd like to do is to use this shader to apply this effect on an image in QtOpenGlWidget. But I dont get how to set my image as a texture and pass it to a shader and then to return it modified with a shader effect. What is I want to achieve is: https://imgur.com/a/NSY0u But my shader doesn't affect image https://imgur.com/a/dgSfq . My GLWidget class:
GLWidget::GLWidget(Helper *helper, QWidget *parent)
: QOpenGLWidget(parent), helper(helper)
{
QImage img("E:\\pictures\\0151.jpg");
image = img;
image = image.convertToFormat(QImage::Format_RGBA8888);
setFixedSize(512, 512);
setAutoFillBackground(false);
targetWidth = width();
targetHeight = height();
qDebug() << "targetWidth="<<targetWidth;
qDebug() << "targetHeight ="<<targetHeight ;
//this values i am trying to pass to my fragment shader
grid = 5.0;//grid on image
dividerValue = 0.5;
step_x = 0.0015625;
step_y = height() ? (2.5 * step_x * targetWidth / targetHeight) : 0.0;
}
void GLWidget::initializeGL()
{
initializeOpenGLFunctions();
m_program = new QOpenGLShaderProgram;
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShader);//?
m_program->link();
m_program->bind();
m_program->release();
}
//we can use paintEvent to display our image with opengl
void GLWidget::paintEvent(QPaintEvent *event)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_program->bind();
QPainter painter;
painter.begin(this);
painter.drawImage(0,0,image);
QOpenGLTexture texture(image); //I dont know how to setUniformValue(m_program->uniformLocation("source"),texture) to my shader
GLuint m_texture;
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.width(), image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glGenerateMipmap(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D);
//open an image
m_program->setUniformValue("grid", grid);
m_program->setUniformValue("dividerValue",dividerValue);
m_program->setUniformValue("step_x", step_x);
m_program->setUniformValue("step_y", step_y);
m_program->setUniformValue(m_program->uniformLocation("source"),m_texture);
painter.end();
m_program->release();
}
When you bind a texture, it is bound to the currently active texture image unit (See Binding textures to samplers).
The active texture unit can be selected by glActiveTexture. The default texture unit is GL_TEXTURE0.
The value which you have to provide to the texture sampler uniform is not the name of a texture, it is the texture unit (number), where the texture is bound to:
int texture_unit = 0; // <----- e.g. texture unit 0
glActiveTexture( GL_TEXTURE0 + texture_unit );
glBindTexture( GL_TEXTURE_2D, m_texture );
.....
m_program->bind();
m_program->setUniformValue( "source", texture_unit ); // <----- texture unit
For a QOpenGLTexture object the texture unit can be selected by QOpenGLTexture::bind:
int texture_unit = 1; // <----- e.g. texture unit 1
QOpenGLTexture texture(image);
texture.bind( texture_unit );
m_program->bind();
m_program->setUniformValue( "source", texture_unit ); // <----- texture unit
Note, since OpenGL 4.2 the texture unit can be initialized within the shader, by a Binding point:
layout(binding = 0) uniform sampler2D source; // binding = 0 -> texture unit 0
Extension to the answer:
The following code will draw the a image to the entire widget with processing it by your shader. Finally the rendered image is read back from the GPU:
class GLWidget : public QOpenGLWidget
{
.....
QOpenGLShaderProgram * m_program = nullptr;
QOpenGLTexture * m_texture = nullptr;
};
void GLWidget::initializeGL()
{
initializeOpenGLFunctions();
QImage img("E:\\pictures\\0151.jpg");
m_texture = new QOpenGLTexture( img );
m_program = new QOpenGLShaderProgram;
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader);
m_program->bindAttributeLocation("vPosition", 0);
m_program->link();
}
void GLWidget::paintEvent(QPaintEvent *event)
{
// celar the framebuffer
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// bind the texture
uint texture_unit = 1;
m_texture->bind( texture_unit );
// activate the shader
m_program->bind();
m_program->setUniformValue( "source", texture_unit );
m_program->setUniformValue( "grid", grid );
m_program->setUniformValue( "dividerValue", dividerValue );
m_program->setUniformValue( "step_x", step_x );
m_program->setUniformValue( "step_y", step_y );
// draw a quad over the entire widget
GLfloat vertices[]{ -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f };
m_program->enableAttributeArray(0);
m_program->setAttributeArray(0, GL_FLOAT, vertices, 2);
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
m_program->disableAttributeArray(0);
// release the shader
m_program->release();
// read the rendered image
int width = ....;
int height = ....;
unsigned char *pixels = new unsigned char[width * height * 4];
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
QImage *img = new QImage( pixels, width, height, QImage::Format_RGBA8888 );
.....
}
Further you have to do some changes to the vertex shader and fragment shader. In the vertex shader you have to pass the vertex position to the fragment shader:
attribute vec2 vPosition;
varying vec2 v_pos;
void main()
{
v_pos = vPosition.xy;
gl_Position = vec4(vPosition.xy, 0.0, 1.0);
}
In the fragment shader you have to calcualte the texute coordinate fromt the vertex position:
varying vec2 v_pos;
void main()
{
vec2 uv = v_pos.xy * 0.5 + 0.5;
....
}
See also glwidget.cpp Example File.
I've been trying OpenGL recently and are stuck again in an issue.
If in my program I set colors via uniforms, I can draw multiple vertex arrays with any color of my choice. But passing of two buffers to be generated for an vertex array object results in weird coloration, where 0 is for vertex location and 1 is for color.
My main function :
int main(){
Window window(960,540);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Reader read1("src/shaders/test.vert");
Reader read2("src/shaders/test.frag");
char * r1 = read1.getData();
char * r2 = read2.getData();
GLfloat vert[] = {
0, 0, 0,
0, 3, 0,
8, 3, 0,
8, 0, 0
};
GLushort indices[] = {
0,1,2,
2,3,0
};
GLfloat colors[] = {
1, 0, 1, 1,
1, 0, 1, 1,
1, 0, 1, 1,
1, 0, 1, 1,
};
VertexArray vao;
Buffer* vbo = new Buffer(vert, 4 * 4, 3);
vao.addBuffer(vbo, 0);
vao.addBuffer(new Buffer(colors,4 * 4 , 4), 1);
indexBuffer ibo(indices, 6);
Shader shader(r1, r2);
shader.enable();
shader.setUniformMat4("pr_matrix", mat4::orthographic(0.0f, 16.0f, 0.0f, 9.0f, -1.0f, 1.0f));
shader.setUniformMat4("ml_matrix", mat4::translation(vec3(4, 3, 0)));
shader.setUniform2f("light_pos", vec2(8.0f, 4.5f));
shader.setUniform4f("colour", vec4(0.2, 0.3, 0.8, 1));
while (!window.closed()){
window.clear();
double x, y;
x = window.getX();
y = window.getY();
shader.setUniform2f("light_pos", vec2((float)((x)*16.0f / 960.0f), (float)(9 - 9 * (y) / 540.0f)));
vao.bind();
ibo.bind();
shader.setUniform4f("colour", vec4(0.2, 0.3, 0.8, 1));
shader.setUniformMat4("ml_matrix", mat4::translation(vec3(4, 3, 0)));
glDrawElements(GL_TRIANGLES, ibo.getCount(), GL_UNSIGNED_SHORT, 0);
ibo.unbind();
vao.unbind();
window.update();
}
return 0;
}
My vertex shaders :
#version 410 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
uniform mat4 pr_matrix ;
uniform mat4 vw_matrix = mat4(1.0f);
uniform mat4 ml_matrix = mat4(1.0f);
out DATA{
vec4 position;
vec4 color;
} vs_out;
out vec4 pos;
void main(){
gl_Position = pr_matrix * vw_matrix * ml_matrix * vec4(position,1) ;
vs_out.position = ml_matrix * vec4(position,1);
vs_out.color = color;
}
My fragment shaders :
#version 410 core
layout(location = 0) out vec4 color ;
uniform vec4 colour;
uniform vec2 light_pos;
in DATA{
vec4 position;
vec4 color;
} fs_in;
void main(){
float intensity = 1.0f / length(fs_in.position.xy - light_pos);
//color = fs_in.color * intensity;
color = fs_in.color * intensity;
}
My buffer class in case its needed to be corrected:
Buffer::Buffer(GLfloat *data, GLsizei count, GLuint compCountExt) : compCount (compCountExt) {
glGenBuffers(1, &bufferId);
glBindBuffer(GL_ARRAY_BUFFER,bufferId);
glBufferData(GL_ARRAY_BUFFER, count* sizeof(GLfloat), data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Buffer::bind() const {
glBindBuffer(GL_ARRAY_BUFFER, bufferId);
}
void Buffer::unbind() const {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
EDIT:
code of the vertexArray Class:
VertexArray::VertexArray(){
glGenVertexArrays(1,&arrayID);
}
void VertexArray::bind() const{
glBindVertexArray(arrayID);
}
void VertexArray::unbind() const{
glBindVertexArray(0);
}
VertexArray::~VertexArray(){
}
void VertexArray::addBuffer(Buffer* buffer, GLuint index){
bind();
glBindBuffer(GL_ARRAY_BUFFER, arrayID);
glEnableVertexAttribArray(index);
glVertexAttribPointer(index, buffer->getComCount(), GL_FLOAT, GL_FALSE, 0, 0);
buffer->unbind();
unbind();
}
there are calls to vertex attrib pointer in this class.
glVertexAttribPointer refers to the currently bound array buffer. This means you have to bind the array buffer befor you use glVertexAttribPointer:
void VertexArray::addBuffer(Buffer* buffer, GLuint index){
bind();
// glBindBuffer(GL_ARRAY_BUFFER, arrayID); <---- skip
buffer->bind(); // <---- bind the array buffer
glEnableVertexAttribArray(index);
glVertexAttribPointer(index, buffer->getComCount(), GL_FLOAT, GL_FALSE, 0, 0);
buffer->unbind();
unbind();
}
See OpenGL 4.6 Specification - 10.3.9 Vertex Arrays in Buffer Objects:
A buffer object binding point is added to the client state associated with each
vertex array index. The commands that specify the locations and organizations of vertex arrays copy the buffer object name that is bound to ARRAY_BUFFER to
the binding point corresponding to the vertex array index being specified. For example, the VertexAttribPointer command copies the value of ARRAY_BUFFER_BINDING.
I am trying to detect silhouette edges and render some textures (varies based on the diffuse term) on these edges using OpenGL and shaders. I am rendering a quad using the geometry shader and also assign the texture coordinates here. In the fragment shader, i am trying to use the diffuse term calculated in vertex shader to render different textures based on diffTerm's value. There are two issues with my code.
1) The diffuse term should vary from (-1,1) but it seems to be stuck at 0 when i rotate the model and it reaches negative values at certain positions.
2) The textures are always black and I cant seem to find out what is causing this issue.
"MeshViewer.cpp" - The main file
Mesh* mesh;
GLuint* texID = new GLuint[5];
float rotn_x = 0.0, rotn_y = 0.0, fov;
GLuint matrixLoc1, matrixLoc2, matrixLoc3,texLoc1, texLoc2, texLoc3, texLoc4, texLoc5;
float cam_near, cam_far; //Near and far planes of the camera
const float PI = 3.14159265f;
glm::mat4 view; //View and projection matrices
void loadTextures()
{
glGenTextures(5, texID); //Generate 1 texture ID
glActiveTexture(GL_TEXTURE0); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[0]);
loadTGA("Pencil0.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE1); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[1]);
loadTGA("Pencil1.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE2); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[2]);
loadTGA("Pencil2.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE3); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[3]);
loadTGA("Brick.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE4); //Texture unit 0
glBindTexture(GL_TEXTURE_2D, texID[4]);
loadTGA("Brick.tga");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void initialise()
{
// --- Mesh object ---
GLuint lgtLoc;
mesh = new Mesh();
if(!mesh->loadMeshOFF("Camel.off")) cout << "Error reading mesh data file." << endl;
// --- Camera parameters ---
float win_width = (mesh->_xmax - mesh->_xmin) * 1.5f;
float win_height = (mesh->_ymax - mesh->_ymin) * 1.5f;
if(win_width > win_height) win_height = win_width; //Maintain aspect ratio = 1
cam_near = 2*(mesh->_zmax) - mesh->_zmin;
cam_far = 2*(mesh->_zmin) - mesh->_zmax;
float cam_posx = (mesh->_xmax + mesh->_xmin) * 0.5f;
float cam_posy = (mesh->_ymax + mesh->_ymin) * 0.5f;
float cam_posz = cam_near + win_height;
fov = 27.0f; //Approx. atan(0.5)
// --- Uniform locations ---
GLuint program = createShaderProg("MeshViewer.vert", "MeshViewer.frag", "MeshViewer.geom");
matrixLoc1 = glGetUniformLocation(program, "mvMatrix");
matrixLoc2 = glGetUniformLocation(program, "mvpMatrix");
matrixLoc3 = glGetUniformLocation(program, "norMatrix");
lgtLoc = glGetUniformLocation(program, "lightPos");
GLint lineWidth = glGetUniformLocation(program, "HalfWidth");
if (lineWidth > -1)
glUniform1f(lineWidth, 0.005f);
GLint overhangLength = glGetUniformLocation(program, "OverhangLength");
if (overhangLength > -1)
glUniform1f(overhangLength, 0.15f);
texLoc1 = glGetUniformLocation (program, "tex1");
glUniform1i(texLoc1, 0);
texLoc2 = glGetUniformLocation (program, "tex2");
glUniform1i(texLoc2, 1);
texLoc3 = glGetUniformLocation (program, "tex3");
glUniform1i(texLoc3, 2);
texLoc4 = glGetUniformLocation (program, "tex4");
glUniform1i(texLoc4, 3);
texLoc5 = glGetUniformLocation (program, "tex5");
glUniform1i(texLoc5, 4);
view = glm::lookAt(glm::vec3(cam_posx, cam_posy, cam_posz), glm::vec3(cam_posx, cam_posy, 0.0), glm::vec3(0.0, 1.0, 0.0)); //view matrix
glm::vec4 light = glm::vec4(100.0, 50.0, 100.0, 1.0); //Light's position
glm::vec4 lightEye = view*light; //Light position in eye coordinates
glUniform4fv(lgtLoc, 1, &lightEye[0]);
// --- OpenGL ---
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //Wireframe
mesh->setColor(0, 0, 1); //Mesh color = blue.
mesh->createVAO(); //Create buffer objects for the mesh
}
void display()
{
glm::mat4 proj;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 matrix = glm::mat4(1.0);
matrix = glm::rotate(matrix, rotn_x, glm::vec3(1.0, 0.0, 0.0)); //rotation about x
matrix = glm::rotate(matrix, rotn_y, glm::vec3(0.0, 1.0, 0.0)); //rotation about y
glm::mat4 prodMatrix1 = view*matrix; //Model-view matrix
proj = glm::perspective(fov, 1.0f, cam_near, cam_far); //perspective projection matrix
glm::mat4 prodMatrix2 = proj*prodMatrix1; //The model-view-projection transformation
glm::mat4 invMatrix = glm::inverse(prodMatrix1); //Inverse of model-view matrix for normal transformation
glUniformMatrix4fv(matrixLoc1, 1, GL_FALSE, &prodMatrix1[0][0]);
glUniformMatrix4fv(matrixLoc2, 1, GL_FALSE, &prodMatrix2[0][0]);
glUniformMatrix4fv(matrixLoc3, 1, GL_TRUE, &invMatrix[0][0]); //Use transpose matrix here
mesh->render();
glFlush();
}
void specialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_LEFT) rotn_y -= 5.0;
else if(key == GLUT_KEY_RIGHT) rotn_y += 5.0;
else if(key == GLUT_KEY_UP) rotn_x -= 5.0;
else if(key == GLUT_KEY_DOWN) rotn_x += 5.0;
else if(key == GLUT_KEY_PAGE_UP) fov --;
else if(key == GLUT_KEY_PAGE_DOWN) fov ++;
if(fov < 1.0) fov = 1.0;
else if(fov > 80.0) fov = 80.0;
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (600, 600);
glutInitWindowPosition (20, 10);
glutCreateWindow ("Mesh Viewer");
glutInitContextVersion (4, 2);
glutInitContextProfile ( GLUT_CORE_PROFILE );
if(glewInit() == GLEW_OK)
{
cout << "GLEW initialization successful! " << endl;
cout << " Using GLEW version " << glewGetString(GLEW_VERSION) << endl;
}
else
{
cerr << "Unable to initialize GLEW ...exiting." << endl;
exit(EXIT_FAILURE);
}
initialise ();
glutDisplayFunc(display);
glutSpecialFunc(specialKeys);
glutMainLoop();
return 0;
}
Vertex Shader:
#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec3 cols;
layout (location = 3) in vec2 texC;
uniform mat4 mvMatrix;
uniform mat4 mvpMatrix;
uniform mat4 norMatrix;
uniform vec4 lightPos;
out float diffTerm;
out vec4 vColour;
out float viewTerm;
out float silhoutte;
out vec2 TexC;
void main()
{
vec4 grey = vec4(0.2, 0.2, 0.2, 1.0);
vec4 posnEye = mvMatrix * position;
vec4 normalEye = norMatrix * vec4(normal, 0);
vec4 lgtVec = normalize(lightPos - posnEye);
vec4 viewVec = normalize(vec4(-posnEye.xyz, 0));
float viewTerm = max(dot(viewVec, normalEye),0);
vec4 material = vec4(cols, 1.0);
vec4 lgtAmb = grey * material;
diffTerm = max(dot(lgtVec, normalEye), 0);
vec4 lgtDiff = material * diffTerm;
silhoutte = dot(viewVec, normalEye);
gl_Position = mvpMatrix * position;
vColour = vec4(cols, 1);
TexC = texC;
}
Geometry Shader:
#version 430 core
layout(triangles_adjacency) in;
layout(triangle_strip, max_vertices = 6) out;
in vec2 texC[];
out vec2 TexCoord;
in vec4 vColour[];
out vec4 colorv;
in float viewTerm[];
out float viewTermg;
in float diffTerm[];
out float diffTermg;
in vec2 TexC[];
out vec2 TexCg;
uniform float HalfWidth;
uniform float OverhangLength;
out float gDist;
out vec3 gSpine;
bool IsFront(vec3 A, vec3 B, vec3 C)
{
float area = (A.x * B.y - B.x * A.y) + (B.x * C.y - C.x * B.y) + (C.x * A.y - A.x * C.y);
return area > 0;
}
void EmitEdge(vec3 P0, vec3 P1)
{
vec3 E = OverhangLength * vec3(P1.xy - P0.xy, 0);
vec2 V = normalize(E.xy);
vec3 N = vec3(-V.y, V.x, 0) * 0.005;
vec3 S = -N;
float D = HalfWidth;
gSpine = P0;
gl_Position = vec4(P0 + S - E, 1); gDist = +D; TexCoord=vec2(0.0,0.0); colorv = vColour[0]; EmitVertex();
gl_Position = vec4(P0 + N - E, 1); gDist = -D; TexCoord=vec2(1.0,0.0); colorv = vColour[1]; EmitVertex();
gSpine = P1;
gl_Position = vec4(P1 + S + E, 1); gDist = +D; TexCoord=vec2(1.0,1.0); colorv = vColour[0]; EmitVertex();
gl_Position = vec4(P1 + N + E, 1); gDist = -D; ; TexCoord=vec2(0.0,1.0); EmitVertex();
EndPrimitive();
}
void main()
{
vec3 v0 = gl_in[0].gl_Position.xyz / gl_in[0].gl_Position.w;
vec3 v1 = gl_in[1].gl_Position.xyz / gl_in[1].gl_Position.w;
vec3 v2 = gl_in[2].gl_Position.xyz / gl_in[2].gl_Position.w;
vec3 v3 = gl_in[3].gl_Position.xyz / gl_in[3].gl_Position.w;
vec3 v4 = gl_in[4].gl_Position.xyz / gl_in[4].gl_Position.w;
vec3 v5 = gl_in[5].gl_Position.xyz / gl_in[5].gl_Position.w;
if (IsFront(v0, v2, v4)) {
if (!IsFront(v0, v1, v2)) EmitEdge(v0, v2);
//if (!IsFront(v2, v3, v4)) EmitEdge(v2, v4);
//if (!IsFront(v0, v4, v5)) EmitEdge(v4, v0);
}
}
Fragment Shader:
#version 330
in vec4 vColourg;
in float diffTermg;
in float silhoutte;
in vec2 TexCg;
in vec2 TexCoord;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform sampler2D tex3;
uniform sampler2D tex4;
uniform sampler2D tex5;
void main()
{
vec4 texColor1 = texture(tex1, TexCoord);
vec4 texColor2 = texture(tex2, TexCoord);
vec4 texColor3 = texture(tex3, TexCoord);
vec4 texColor4 = texture(tex4, TexCoord);
vec4 texColor5 = texture(tex5, TexCoord);
vec4 blue = vec4(0.0,0.0,1.0,0.0);
vec4 red = vec4(1.0,0.0,0.0,0.0);
vec4 yellow = vec4(1.0,1.0,0.0,0.0);
if (diffTermg<0)
{
gl_FragColor = blue;
}
else if (diffTermg ==0)
{
gl_FragColor = texColor5;
}
else if (diffTermg > 0 && diffTermg < 0.2)
gl_FragColor = yellow;
else if (diffTermg > 100)
gl_FragColor = blue;
}
EDIT:
Shader.h
GLuint loadShader(GLenum shaderType, string filename)
{
ifstream shaderFile(filename.c_str());
if(!shaderFile.good()) cout << "Error opening shader file." << endl;
stringstream shaderData;
shaderData << shaderFile.rdbuf();
shaderFile.close();
string shaderStr = shaderData.str();
const char* shaderTxt = shaderStr.c_str();
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderTxt, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);
const char *strShaderType = NULL;
cerr << "Compile failure in shader: " << strInfoLog << endl;
delete[] strInfoLog;
}
return shader;
}
GLuint createShaderProg(string vertShader, string fragShader, string geomShader)
{
GLuint shaderv = loadShader(GL_VERTEX_SHADER, vertShader);
GLuint shaderf = loadShader(GL_FRAGMENT_SHADER, fragShader);
GLuint shaderg = loadShader(GL_GEOMETRY_SHADER, geomShader);
GLuint program = glCreateProgram();
glAttachShader(program, shaderv);
glAttachShader(program, shaderf);
glAttachShader(program, shaderg);
glLinkProgram(program);
GLint status;
glGetProgramiv (program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
fprintf(stderr, "Linker failure: %s\n", strInfoLog);
delete[] strInfoLog;
program = 0;
}
glUseProgram(program);
return program;
}
loadTGA.h
void loadTGA(string filename)
{
char id, cmap, imgtype, bpp, c_garb;
char* imageData, temp;
short int s_garb, wid, hgt;
int nbytes, size, indx;
ifstream file( filename.c_str(), ios::in | ios::binary);
if(!file)
{
cout << "*** Error opening image file: " << filename.c_str() << endl;
exit(1);
}
file.read (&id, 1);
file.read (&cmap, 1);
file.read (&imgtype, 1);
if(imgtype != 2 && imgtype != 3 ) //2= colour (uncompressed), 3 = greyscale (uncompressed)
{
cout << "*** Incompatible image type: " << (int)imgtype << endl;
exit(1);
}
//Color map specification
file.read ((char*)&s_garb, 2);
file.read ((char*)&s_garb, 2);
file.read (&c_garb, 1);
//Image specification
file.read ((char*)&s_garb, 2); //x origin
file.read ((char*)&s_garb, 2); //y origin
file.read ((char*)&wid, 2); //image width
file.read ((char*)&hgt, 2); //image height
file.read (&bpp, 1); //bits per pixel
file.read (&c_garb, 1); //img descriptor
nbytes = bpp / 8; //No. of bytes per pixels
size = wid * hgt * nbytes; //Total number of bytes to be read
imageData = new char[size];
file.read(imageData, size);
//cout << ">>>" << nbytes << " " << wid << " " << hgt << endl;
if(nbytes > 2) //swap R and B
{
for(int i = 0; i < wid*hgt; i++)
{
indx = i*nbytes;
temp = imageData[indx];
imageData[indx] = imageData[indx+2];
imageData[indx+2] = temp;
}
}
switch (nbytes)
{
case 1:
glTexImage2D(GL_TEXTURE_2D, 0, 1, wid, hgt, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData);
break;
case 3:
glTexImage2D(GL_TEXTURE_2D, 0, 3, wid, hgt, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
break;
case 4:
glTexImage2D(GL_TEXTURE_2D, 0, 4, wid, hgt, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
break;
}
delete imageData;
}
You are requesting a core profile context:
glutInitContextProfile(GLUT_CORE_PROFILE);
But your glTexImage2D() calls are not compatible with the core profile:
glTexImage2D(GL_TEXTURE_2D, 0, 1, wid, hgt, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData);
glTexImage2D(GL_TEXTURE_2D, 0, 3, wid, hgt, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
glTexImage2D(GL_TEXTURE_2D, 0, 4, wid, hgt, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
Using the number of components as the internal format (argument 3) is legacy from OpenGL 1.0, and was finally eliminated when the core profile was introduced. GL_LUMINANCE is also gone. The modern (core profile) equivalent of those calls is:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, wid, hgt, 0, GL_RED, GL_UNSIGNED_BYTE, imageData);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, wid, hgt, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, wid, hgt, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
The post contains a lot of code, and I did not study it in detail to see if there are other problems. I strongly recommend the use of glGetError(), which would have reported these invalid arguments, and should also be helpful to check if there are any additional problems.
My program has been working perfectly so far, but it turns out that I've been lucky. I began doing some cleanup of the shader, because it was full of experimental stuff, and I had the following line at the end of the fragment shader:
gl_FragColor = final_color * (texture2D(tex, gl_TexCoord[0].st)*1.0 + texture2D(tex2, gl_TexCoord[0].st)*1.0);
I attempted to clean it up and I had the following declared at the top:
uniform sampler2D tex, tex2;
Changing these lines to:
gl_FragColor = final_color * texture2D(tex, gl_TexCoord[0].st;
and
uniform sampler2D tex;
actually broke the program (black screen), even though I am doing
GLuint tex_loc = glGetUniformLocation(shader_prog_id_, "tex");
glUniform1i(tex_loc, texture_id_);
in my main code. I'm sure it's a texture issue and not a glsl compiler error, because I can add 1.0 to the output and end up with a white silhouette of my mesh.
The strangeness begins when I change the lines in my shader to:
gl_FragColor = final_color * texture2D(tex2, gl_TexCoord[0].st;
and
uniform sampler2D tex2;
but still retrieve the location for tex. The program works as it always has, even though inspecting the value of tex_loc in the debugger indicates an error. I'm not happy doing this, and now that I'm trying to load multiple textures, it will cause bigger headaches down the line.
I'm using VBOs, in interleaved format, to render the geometry. I'm passing in the vertex position, normal and texcoord this way.
There are other questions with the "black texture" issue, but they're using immediate mode calls and setting the wrong texture state. I tried changing the texture unit before supplying the arrays, with no success.
Here is as much relevant code as possible from the main program:
void MeshWidget::draw() {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -4.0f + zoom_factor_);
glRotatef(rotX, 1.0f, 0.0f, 0.0f);
glRotatef(rotY, 0.0f, 1.0f, 0.0f);
glRotatef(rotZ, 0.0f, 0.0f, 1.0f);
// Auto centre mesh based on vertex bounds.
glTranslatef(-x_mid_, -y_mid_, -z_mid_);
glDrawElements(GL_TRIANGLES, mesh_.num_indices, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); //The starting point of the IBO
}
void MeshWidget::openMesh(const string& filename) {
if (mesh_filename_ != filename) {
clearMeshData(mesh_);
glDeleteBuffersARB(1, &VertexVBOID);
glDeleteBuffersARB(1, &IndexVBOID);
ReadMsh(mesh_, filename);
// Create buffer objects here.
glGenBuffersARB(1, &VertexVBOID);
glBindBufferARB(GL_ARRAY_BUFFER, VertexVBOID);
glBufferDataARB(GL_ARRAY_BUFFER, sizeof(VertexAttributes)*mesh_.num_vertices, &mesh_.vertices[0], GL_STATIC_DRAW);
glGenBuffersARB(1, &IndexVBOID);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint16_t)*mesh_.num_indices, &mesh_.indices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(VertexAttributes), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(VertexAttributes), BUFFER_OFFSET(12)); //The starting point of normals, 12 bytes away
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexAttributes), BUFFER_OFFSET(24)); //The starting point of texcoords, 24 bytes away
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
if (startup_done_) updateGL();
}
}
void MeshWidget::openTexture(const string& filename) {
size_t dot = filename.find_last_of('.');
string ext(filename, dot, filename.size()); // 3rd parameter should be length of new string, but is internally clipped to end.
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glDeleteTextures(1, &texture_id_);
glGenTextures(1, &texture_id_);
glBindTexture(GL_TEXTURE_2D, texture_id_);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (ext == ".dds") {
if (GLEE_EXT_texture_compression_s3tc) {
texture_id_ = SOIL_load_OGL_texture(filename.c_str(), SOIL_LOAD_AUTO, texture_id_, SOIL_FLAG_DDS_LOAD_DIRECT);
// SOIL takes care of calling glTexParams, glTexImage2D, etc.
yflip_texture_ = true;
} else {
//std::cout << "S3TC not supported on this graphics hardware." << std::endl;
// TODO: Error message in status bar?
}
} else {
QImage tex(filename.c_str());
tex = QGLWidget::convertToGLFormat(tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
yflip_texture_ = false;
}
updateUniforms();
if (startup_done_) updateGL();
}
void MeshWidget::updateUniforms() {
GLuint texture_flip_uniform = glGetUniformLocation(shader_prog_id_, "yflip");
glUniform1f(texture_flip_uniform, float(yflip_texture_ * 1.0f));
GLuint tex_loc = glGetUniformLocation(shader_prog_id_, "tex");
glUniform1i(tex_loc, texture_id_);
}
And my shaders (there's still some junk in here because I was experimenting, but nothing that affects the output):
varying vec3 normal, lightDir, eyeVec;
uniform float yflip;
void main()
{
normal = gl_NormalMatrix * gl_Normal;
vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
lightDir = vec3(gl_LightSource[0].position.xyz - vVertex);
eyeVec = -vVertex;
gl_TexCoord[0].x = gl_MultiTexCoord0.x;
gl_TexCoord[1].x = gl_MultiTexCoord1.x;
if (yflip == 1.0) {
gl_TexCoord[0].y = 1 - gl_MultiTexCoord0.y;
gl_TexCoord[1].y = 1 - gl_MultiTexCoord1.y;
} else {
gl_TexCoord[0].y = gl_MultiTexCoord0.y;
gl_TexCoord[1].y = gl_MultiTexCoord1.y;
}
gl_Position = ftransform();
}
fragment shader:
varying vec3 normal, lightDir, eyeVec;
uniform sampler2D tex2;
void main (void)
{
vec4 texel = texture2D(tex2, gl_TexCoord[0].st);
vec4 final_color =
(gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) +
(gl_LightSource[0].ambient * gl_FrontMaterial.ambient);
vec3 N = normalize(normal);
vec3 L = normalize(lightDir);
float lambertTerm = dot(N,L);
if(lambertTerm > 0.0)
{
final_color += gl_LightSource[0].diffuse *
gl_FrontMaterial.diffuse *
lambertTerm;
vec3 E = normalize(eyeVec);
vec3 R = reflect(-L, N);
float specular = pow( max(dot(R, E), 0.0),
gl_FrontMaterial.shininess );
final_color += gl_LightSource[0].specular *
gl_FrontMaterial.specular *
specular;
}
gl_FragColor = final_color * texel;
}
glUniform1i(tex_loc, texture_id_);
The second parameter should specify ID of a texture unit(hint: glActiveTexture sets the currently active texture unit), not ID of particular texture object.
I am working on adding a phong shader to my working program. Basically, after I implemented my new shaders, my code gets a "Segmentation Fault: 11" during:
glDrawArrays(GL_TRIANGLES, 0, mCubes.getArrayNumberOfElements());
I know the number of elements is correct because it worked for my previous, simple shader.
Here is my Vertex Shader:
// vertex shader
attribute vec4 vPosition;
attribute vec3 vNormal;
varying vec4 color; //vertex shader
// light and material properties
uniform vec4 AmbientProduct, DiffuseProduct, SpecularProduct;
uniform mat4 ModelView;
//uniform mat4 Projection;
uniform vec4 LightPosition;
uniform float Shininess;
vec3 L, H, N, pos, E;
vec4 diffuse, specular, ambient;
float Kd, Ks;
void main()
{
// Transform vertex position into eye coordinates
pos = (ModelView * vPosition).xyz;
L = normalize( LightPosition.xyz - pos );
E = normalize( -pos );
H = normalize( L + E );
// Transform vertex normal into eye coordinates
N = normalize( ModelView*vec4(vNormal, 0.0) ).xyz;
// Compute terms in the illumination equation
ambient = AmbientProduct;
Kd = max( dot(L, N), 0.0 );
diffuse = Kd*DiffuseProduct;
Ks = pow( max(dot(N, H), 0.0), Shininess );
specular = Ks * SpecularProduct;
if( dot(L, N) < 0.0 )
specular = vec4(0.0, 0.0, 0.0, 1.0);
gl_Position = ModelView * vPosition;
color = ambient + diffuse + specular;
color.a = 1.0;
}
Here is my display function in which the code ends up getting the fault:
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
vector<float> cell = mCubes.getCell();
mat4 matrix = rot * scale(1.0/cell[0], 1.0/cell[1], 1.0/cell[2]) * translate(-cell[0]/2.0, -cell[1]/2.0, -cell[2]/2.0);
glUniformMatrix4fv(vShaderModelView, 1, GL_TRUE, matrix);
glDrawArrays(GL_TRIANGLES, 0, mCubes.getArrayNumberOfElements());
glutSwapBuffers();
glFlush();
}
And here is my init function that mostly sets up and interacts with the shaders:
void init() {
// Create a vertex array object
GLuint vao;
#ifdef __APPLE__
glGenVertexArraysAPPLE( 1, &vao );
glBindVertexArrayAPPLE( vao );
#else
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
#endif
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData( GL_ARRAY_BUFFER,
mCubes.getDisplayArraySize() + mCubes.getDisplayArraySize()*3, NULL, GL_STATIC_DRAW );
GLintptr offset = 0;
glBufferSubData(GL_ARRAY_BUFFER, offset, mCubes.getDisplayArraySize(), mCubes.getDisplayArray());
offset+= mCubes.getDisplayArraySize();
glBufferSubData(GL_ARRAY_BUFFER, offset, mCubes.getDisplayArraySize(), mCubes.getNormalVector());
// Load shaders and use the resulting shader program
string evname = "PROTCAD3DIR";
string path = PCGeneralIO::getEnvironmentVariable(evname);
path += "/data/shaders/";
#ifdef __APPLE__
string vshadername = path + "kw_vshader1_mac.glsl";
string fshadername = path + "kw_fshader1_mac.glsl";
//#else
// string vshadername = path + "kw_vshader1.glsl";
// string fshadername = path + "kw_fshader1.glsl";
#endif
GLuint program = InitShader( vshadername.c_str(), fshadername.c_str() );
glUseProgram(program);
// Initialize the vertex position attribute from the vertex shader
GLuint vShaderPosition = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(vShaderPosition);
glVertexAttribPointer(vShaderPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
GLuint vShaderNormal = glGetAttribLocation(program, "vNormal");
glEnableVertexAttribArray(vShaderNormal);
//glVertexAttribPointer(vShaderPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); //this was the ORIGINAL PROBLEM, now commented out and below is solution
glVertexAttribPointer(vShaderNormal, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset));
vShaderModelView = glGetUniformLocation(program, "ModelView");
vShaderLightPosition = glGetUniformLocation(program, "LightPosition");
vShaderAmbientProduct = glGetUniformLocation(program, "AmbientProduct");
vShaderDiffuseProduct = glGetUniformLocation(program, "DiffuseProduct");
vShaderSpecularProduct = glGetUniformLocation(program, "SpecularProduct");
vShaderShininess = glGetUniformLocation(program, "SpecularProduct");
glEnable( GL_DEPTH_TEST );
vec4 light = vec4(0.5,1.5,1.0,0.0);
glUniform4fv(vShaderLightPosition, 1, light);
vec4 amb = vec4(1.0f,0.0f,0.20f,1.0f);
glUniform4fv(vShaderAmbientProduct, 1, amb);
vec4 diff = vec4(0.5f,0.5f,0.5f,1.0f);
glUniform4fv(vShaderDiffuseProduct, 1, diff);
vec4 spec = vec4(0.80f,0.80f,0.80f,1.0f);
glUniform4fv(vShaderSpecularProduct, 1, spec);
float shin = 6.0f;
glUniform1f(vShaderShininess,shin);
glClearColor(.2, .2, .2, 1); /* Grey background */
}
If you have any question, feel free to ask and I will elaborate. I feel that either the vertex shader itself has a problem, or the way I interact with the shader is doing something wonky. Any help or suggestions are accepted!
EDIT::: (code edited to reflect solution)The problem was in the second:
glVertexAttribPointer(vShaderPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset));
which should have read:
glVertexAttribPointer(vShaderNormal, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset));
And was a stupid copy/paste mistake. However, the finished product still does not look correct:
![at Rotation 0 it seems to be fully colored][1]
http://i.stack.imgur.com/CKJ3f.png
![Rotation of a little bit reveals some odd behavior][2]
http://i.stack.imgur.com/kyRfI.png
![Even more rotation leads you to pull your hair out][3]
i.stack.imgur.com/lYOzK.png
![Then it whites out and you know i screwed up!!][4]
i.stack.imgur.com/FZcqF.png
So, as you rotate the color gets screwed up and turns white, black, patterned and everything, but this is obviously incorrect.
Edit::: This is my attempt to "Correct" the issue of passing the wrong amount of values with vNormal:
void init() {
// Create a vertex array object
GLuint vao;
#ifdef __APPLE__
glGenVertexArraysAPPLE( 1, &vao );
glBindVertexArrayAPPLE( vao );
#else
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
#endif
// Create and initialize a buffer object
GLuint buffer;
realVec *normArray = new realVec[mCubes.getNormalArraySize()];//vec4 array compared to vec3 array
normArray = mCubes.getNormalVector(); // new array of normals
for(int i=0; i<mCubes.getArrayNumberOfElements();i++){
printf("Normal at %d is %f \n",i,normArray[i][0]); //to print normals
printf("Normal at %d is %f \n",i,normArray[i][1]); //to print normals
printf("Normal at %d is %f \n",i,normArray[i][2]); //to print normals
}
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData( GL_ARRAY_BUFFER,
mCubes.getDisplayArraySize() + mCubes.getNormalArraySize(), NULL, GL_STATIC_DRAW ); //Changed size for vec3 array of normals
GLintptr offset = 0;
glBufferSubData(GL_ARRAY_BUFFER, offset, mCubes.getDisplayArraySize(), mCubes.getDisplayArray());
offset+= mCubes.getDisplayArraySize();
glBufferSubData(GL_ARRAY_BUFFER, offset, mCubes.getNormalArraySize(), normArray);
// Load shaders and use the resulting shader program
string evname = "PROTCAD3DIR";
string path = PCGeneralIO::getEnvironmentVariable(evname);
path += "/data/shaders/";
#ifdef __APPLE__
string vshadername = path + "kw_vshader1_mac.glsl";
string fshadername = path + "kw_fshader1_mac.glsl";
//#else
// string vshadername = path + "kw_vshader1.glsl";
// string fshadername = path + "kw_fshader1.glsl";
#endif
GLuint program = InitShader( vshadername.c_str(), fshadername.c_str() );
glUseProgram(program);
//offset =0;
// Initialize the vertex position attribute from the vertex shader
GLuint vShaderPosition = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(vShaderPosition);
glVertexAttribPointer(vShaderPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
GLuint vShaderNormal = glGetAttribLocation(program, "vNormal");
glEnableVertexAttribArray(vShaderNormal);
glVertexAttribPointer(vShaderNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset));
//vShaderMatrix = glGetUniformLocation(program, "vMatrix");
//vShaderColor = glGetUniformLocation(program, "vColor")
vShaderModelView = glGetUniformLocation(program, "ModelView");
vShaderLightPosition = glGetUniformLocation(program, "LightPosition");
//vShaderProjection = glGetUniformLocation(program, "Projection");
vShaderAmbientProduct = glGetUniformLocation(program, "AmbientProduct");
vShaderDiffuseProduct = glGetUniformLocation(program, "DiffuseProduct");
vShaderSpecularProduct = glGetUniformLocation(program, "SpecularProduct");
vShaderShininess = glGetUniformLocation(program, "SpecularProduct");
glEnable( GL_DEPTH_TEST );
vec4 light = vec4(0.5,1.5,1.0,0.0);
glUniform4fv(vShaderLightPosition, 1, light);
vec4 amb = vec4(1.0f,0.0f,0.20f,1.0f);
glUniform4fv(vShaderAmbientProduct, 1, amb);
vec4 diff = vec4(0.5f,0.5f,0.5f,1.0f);
glUniform4fv(vShaderDiffuseProduct, 1, diff);
vec4 spec = vec4(0.80f,0.80f,0.80f,1.0f);
glUniform4fv(vShaderSpecularProduct, 1, spec);
float shin = 6.0f;
glUniform1f(vShaderShininess,shin);
glClearColor(.2, .2, .2, 1); /* Grey background */
}
Should I maybe change the light, ambient, specular, and diffuse properties? I am not sure what the problem is.
You pass your vNormal attribute data using the following code
glVertexAttribPointer(vShaderNormal, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset));
This indicates that your normal have 4 components, whereas in your vertex shader you declare it as
attribute vec3 vNormal;
This mismatch may be related to your problem if the normals are misinterpreted.