opengl drawing multipe objects from one vao - c++

i have a single vao that contains a character set of a font.
Each character is drawn with a set of indices belonging to it.
The idea was to write a couple of chars and bind the vao only one time.
Everything works fine - except the positioning of the glyphs.
The loop is like
glGetUniformLocations()
glBindVertexArray( vao )
for( i=0; i< lg; i++ )
{
glUniforMatrix4fV(); // send translation matrix to shader
glDrawElements( part of the indexbuffer );
trans_mx = glm::translate(); // compute the translation matrix
}
Vertexshader is:
#version 450 core
layout( location = 0 ) in vec3 vx; // the vertex_buffer in modelspace
layout( location = 1 ) in vec4 vx_col; // color of each vertex
out vec4 fragment_color;
uniform mat4 mvp_mx;
uniform mat4 trans_mx;
void main()
{
gl_Position = mvp_mx * vec4( trans_mx * vec4( vx, 1.0f ) );
fragment_color = vx_col;
}
The translation works - but not between the draw calls.
All chars are drawn at the same position. which is translated.
For me it seems as if the translation matrix will not be updated.
??????
this is the code from the function that draws the chars
lg = strlen( str );
vao = sfs->vao;
_sys.mvp_mx = _sys.proj_mx * _sys.view_mx * vao->model_mx; // compute global mvp
sh_s = &__sh_list[ vao->shd_ind ]; // pointer to our shader_struct
sh_s->get_uniform_loc(); // get uniform locations for this shader
glBindVertexArray( vao->id ); // bind vao
glUseProgram( sh_s->prg_id ); // use the shader
for( c1 = 0; c1 < lg; c1++ )
{
sh_s->send_uniform(); // send uniforms to the shader
i_seg = &vao->ind_b->seg[ str[ c1 ] ]; // segment for this character
glDrawElements( i_seg->prim, i_seg->count, i_seg->type, ( void* )i_seg->offset );
_sys.trans_mx = glm::translate( glm::mat4( 1.0f ), glm::vec3( 10.0f, 0.0f, 0.0f ) );
}
glBindVertexArray( 0 ); // unbind vao
glUseProgram( 0 ); // unbind shader

The expression
for( c1 = 0; c1 < lg; c1++ )
{
.....
_sys.trans_mx = glm::translate(glm::mat4(1.0f), glm::vec3(10.0f, 0.0f, 0.0f));
}
will ongoing calculate the same matrix.
If you want to calculate a continuously changing matrix in the loop, then you have to continually change the matrix based on its current value:
for( c1 = 0; c1 < lg; c1++ )
{
.....
_sys.trans_mx = glm::translate(_sys.trans_mx, glm::vec3(10.0f, 0.0f, 0.0f));
}
Or you calculate the matrix dependent on the control variable of the loop
for( c1 = 0; c1 < lg; c1++ )
{
.....
_sys.trans_mx = glm::translate(glm::mat4(1.0f), glm::vec3(10.0f * c1, 0.0f, 0.0f));
}

Related

OpenGL line width/thickness [duplicate]

In my OpenGL app, it won't let me draw a line greater then ten pixels wide. Is there a way to make it draw more than ten pixels?
void OGL_Renderer::drawLine(int x, int y, int x2, int y2, int r, int g, int b, int a, int line_width)
{
glColor4ub(r, g, b, a);
glLineWidth((GLfloat)line_width);
glBegin(GL_LINES);
glVertex2i(x, y);
glVertex2i(x2, y2);
glEnd();
glLineWidth(1.0f);
}
I recommend to use a Shader, which generates triangle primitives along a line strip (or even a line loop).
The task is to generate thick line strip, with as less CPU and GPU overhead as possible. That means to avoid computation of polygons on the CPU as well as geometry shaders (or tessellation shaders).
Each segment of the line consist of a quad represented by 2 triangle primitives respectively 6 vertices.
0 2 5
+-------+ +
| / / |
| / / |
| / / |
+ +-------+
1 3 4
Between the line segments the miter hast to be found and the quads have to be cut to the miter.
+----------------+
| / |
| segment 1 / |
| / |
+--------+ |
| segment 2
| |
| |
+-------+
Create an array with the corners points of the line strip. The first and the last point define the start and end tangents of the line strip. So you need to add 1 point before the line and one point after the line. Of course it would be easy, to identify the first and last element of the array by comparing the index to 0 and the length of the array, but we don't want to do any extra checks in the shader.
If a line loop has to be draw, then the last point has to be add to the array head and the first point to its tail.
The array of points is stored to a Shader Storage Buffer Object. We use the benefit, that the last variable of the SSBO can be an array of variable size. In older versions of OpenGL (or OpenGL ES) a Uniform Buffer Object or even a Texture can be used.
The shader doesn't need any vertex coordinates or attributes. All we have to know is the index of the line segment. The coordinates are stored in the buffer. To find the index we make use of the the index of the vertex currently being processed (gl_VertexID).
To draw a line strip with N points (N-1 segments), 6*(N-1) vertices have tpo be processed.
We have to create an "empty" Vertex Array Object (without any vertex attribute specification):
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
And to draw 2*(N-1) triangle (6*(N-1) vertices):
glDrawArrays(GL_TRIANGLES, 0, 6*(N-1));
For the coordinate array in the SSBO, the data type vec4 is used (Pleas believe me, you don't want to use vec3):
layout(std430, binding = 0) buffer TVertex
{
vec4 vertex[];
};
Compute the index of the line segment, where the vertex coordinate belongs too and the index of the point in the 2 triangles:
int line_i = gl_VertexID / 6;
int tri_i = gl_VertexID % 6;
Since we are drawing N-1 line segments, but the number of elements in the array is N+2, the elements form vertex[line_t] to vertex[line_t+3] can be accessed for each vertex which is processed in the vertex shader.
vertex[line_t+1] and vertex[line_t+2] are the start respectively end coordinate of the line segment. vertex[line_t] and vertex[line_t+3] are required to compute the miter.
The thickness of the line should be set in pixel unit (uniform float u_thickness). The coordinates have to be transformed from model space to window space. For that the resolution of the viewport has to be known (uniform vec2 u_resolution). Don't forget the perspective divide. The drawing of the line will even work at perspective projection.
vec4 va[4];
for (int i=0; i<4; ++i)
{
va[i] = u_mvp * vertex[line_i+i];
va[i].xyz /= va[i].w;
va[i].xy = (va[i].xy + 1.0) * 0.5 * u_resolution;
}
The miter and the start and end tangents are calculated from the vectors between the points. It would be a waste of performance to test the points in the vertex shader for equality or for vectors of zero length. It is up to the vertex setup to take care of a proper list of points.
However the miter calculation even works if the predecessor and successor point of a point are equal. In this case the end of the line is cut normal to the line segemnt or tangent:
vec2 v_line = normalize(va[2].xy - va[1].xy);
vec2 nv_line = vec2(-v_line.y, v_line.x);
vec2 v_pred = normalize(va[1].xy - va[0].xy);
vec2 v_succ = normalize(va[3].xy - va[2].xy);
vec2 v_miter1 = normalize(nv_line + vec2(-v_pred.y, v_pred.x));
vec2 v_miter2 = normalize(nv_line + vec2(-v_succ.y, v_succ.x));
In the final vertex shader we just need to calculate either v_miter1 or v_miter2 dependent on the tri_i. With the miter, the normal vector to the line segment and the line thickness (u_thickness), the vertex coordinate can be computed:
vec4 pos;
if (tri_i == 0 || tri_i == 1 || tri_i == 3)
{
vec2 v_pred = normalize(va[1].xy - va[0].xy);
vec2 v_miter = normalize(nv_line + vec2(-v_pred.y, v_pred.x));
pos = va[1];
pos.xy += v_miter * u_thickness * (tri_i == 1 ? -0.5 : 0.5) / dot(v_miter, nv_line);
}
else
{
vec2 v_succ = normalize(va[3].xy - va[2].xy);
vec2 v_miter = normalize(nv_line + vec2(-v_succ.y, v_succ.x));
pos = va[2];
pos.xy += v_miter * u_thickness * (tri_i == 5 ? 0.5 : -0.5) / dot(v_miter, nv_line);
}
Finally the window coordinates have to be transformed back to clip space coordinates. Transform from window space to normalized device space. The perspective divide has to be reversed:
pos.xy = pos.xy / u_resolution * 2.0 - 1.0;
pos.xyz *= pos.w;
The shader can generate the following polygons (rendered with glPolygonMode(GL_FRONT_AND_BACK, GL_LINE))
(with default mode - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL))
For the following simple demo program I've used the GLFW API for creating a window, GLEW for loading OpenGL and GLM -OpenGL Mathematics for the math. I don't provide the code for the function CreateProgram, which just creates a program object, from the vertex shader and fragment shader source code:
#include <vector>
#include <string>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <gl/gl_glew.h>
#include <GLFW/glfw3.h>
std::string vertShader = R"(
#version 460
layout(std430, binding = 0) buffer TVertex
{
vec4 vertex[];
};
uniform mat4 u_mvp;
uniform vec2 u_resolution;
uniform float u_thickness;
void main()
{
int line_i = gl_VertexID / 6;
int tri_i = gl_VertexID % 6;
vec4 va[4];
for (int i=0; i<4; ++i)
{
va[i] = u_mvp * vertex[line_i+i];
va[i].xyz /= va[i].w;
va[i].xy = (va[i].xy + 1.0) * 0.5 * u_resolution;
}
vec2 v_line = normalize(va[2].xy - va[1].xy);
vec2 nv_line = vec2(-v_line.y, v_line.x);
vec4 pos;
if (tri_i == 0 || tri_i == 1 || tri_i == 3)
{
vec2 v_pred = normalize(va[1].xy - va[0].xy);
vec2 v_miter = normalize(nv_line + vec2(-v_pred.y, v_pred.x));
pos = va[1];
pos.xy += v_miter * u_thickness * (tri_i == 1 ? -0.5 : 0.5) / dot(v_miter, nv_line);
}
else
{
vec2 v_succ = normalize(va[3].xy - va[2].xy);
vec2 v_miter = normalize(nv_line + vec2(-v_succ.y, v_succ.x));
pos = va[2];
pos.xy += v_miter * u_thickness * (tri_i == 5 ? 0.5 : -0.5) / dot(v_miter, nv_line);
}
pos.xy = pos.xy / u_resolution * 2.0 - 1.0;
pos.xyz *= pos.w;
gl_Position = pos;
}
)";
std::string fragShader = R"(
#version 460
out vec4 fragColor;
void main()
{
fragColor = vec4(1.0);
}
)";
GLuint CreateSSBO(std::vector<glm::vec4> &varray)
{
GLuint ssbo;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo );
glBufferData(GL_SHADER_STORAGE_BUFFER, varray.size()*sizeof(*varray.data()), varray.data(), GL_STATIC_DRAW);
return ssbo;
}
int main(void)
{
if ( glfwInit() == 0 )
return 0;
GLFWwindow *window = glfwCreateWindow( 800, 600, "GLFW OGL window", nullptr, nullptr );
if ( window == nullptr )
{
glfwTerminate();
retturn 0;
}
glfwMakeContextCurrent(window);
if ( glewInit() != GLEW_OK )
return 0;
GLuint program = CreateProgram(vertShader, fragShader);
GLint loc_mvp = glGetUniformLocation(program, "u_mvp");
GLint loc_res = glGetUniformLocation(program, "u_resolution");
GLint loc_thi = glGetUniformLocation(program, "u_thickness");
glUseProgram(program);
glUniform1f(loc_thi, 20.0);
GLushort pattern = 0x18ff;
GLfloat factor = 2.0f;
glm::vec4 p0(-1.0f, -1.0f, 0.0f, 1.0f);
glm::vec4 p1(1.0f, -1.0f, 0.0f, 1.0f);
glm::vec4 p2(1.0f, 1.0f, 0.0f, 1.0f);
glm::vec4 p3(-1.0f, 1.0f, 0.0f, 1.0f);
std::vector<glm::vec4> varray1{ p3, p0, p1, p2, p3, p0, p1 };
GLuint ssbo1 = CreateSSBO(varray1);
std::vector<glm::vec4> varray2;
for (int u=-8; u <= 368; u += 8)
{
double a = u*M_PI/180.0;
double c = cos(a), s = sin(a);
varray2.emplace_back(glm::vec4((float)c, (float)s, 0.0f, 1.0f));
}
GLuint ssbo2 = CreateSSBO(varray2);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glm::mat4(project);
int vpSize[2]{0, 0};
while (!glfwWindowShouldClose(window))
{
int w, h;
glfwGetFramebufferSize(window, &w, &h);
if (w != vpSize[0] || h != vpSize[1])
{
vpSize[0] = w; vpSize[1] = h;
glViewport(0, 0, vpSize[0], vpSize[1]);
float aspect = (float)w/(float)h;
project = glm::ortho(-aspect, aspect, -1.0f, 1.0f, -10.0f, 10.0f);
glUniform2f(loc_res, (float)w, (float)h);
}
glClear(GL_COLOR_BUFFER_BIT);
glm::mat4 modelview1( 1.0f );
modelview1 = glm::translate(modelview1, glm::vec3(-0.6f, 0.0f, 0.0f) );
modelview1 = glm::scale(modelview1, glm::vec3(0.5f, 0.5f, 1.0f) );
glm::mat4 mvp1 = project * modelview1;
glUniformMatrix4fv(loc_mvp, 1, GL_FALSE, glm::value_ptr(mvp1));
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo1);
GLsizei N1 = (GLsizei)varray1.size()-2;
glDrawArrays(GL_TRIANGLES, 0, 6*(N1-1));
glm::mat4 modelview2( 1.0f );
modelview2 = glm::translate(modelview2, glm::vec3(0.6f, 0.0f, 0.0f) );
modelview2 = glm::scale(modelview2, glm::vec3(0.5f, 0.5f, 1.0f) );
glm::mat4 mvp2 = project * modelview2;
glUniformMatrix4fv(loc_mvp, 1, GL_FALSE, glm::value_ptr(mvp2));
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo2);
GLsizei N2 = (GLsizei)varray2.size()-2;
glDrawArrays(GL_TRIANGLES, 0, 6*(N2-1));
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
You could try drawing a quad. Make it as wide as you want your line to be long, and tall as the line width you need, then rotate and position it where the line would go.
Ah, now that I understood what you meant:
draw a one by one square.
calc the length and orientation of the line
stretch it to the length in x
translate to startpos and rotate to line_orientation
or:
get vector of line: v :(x2 - x1, y2 - y1)
normalize v: n
3- get orthogonal (normal) of the vector : o (easy in 2d)
add and subtract o from the line's end and start point to get 4 corner points
draw a quad with these points.
It makes sense that you can't. From the glLineWidth reference:
The range of supported widths and the size difference between supported widths within the range can be queried by calling glGet with arguments GL_LINE_WIDTH_RANGE and GL_LINE_WIDTH_GRANULARITY.

Point Sprite Alpha Blending Issue

I'm trying to render a load of stars in 3D space using point sprites. My texture image is definitely 'good' as far as the alpha channel is concerned. It renders perfectly fine as a quad but when I render a lot of point sprites, I can see the square border of the image overwriting some of the images.
The above image shows the star being rendered nicely over the top of my cube. In the bottom right I would expect to see a continuous trail of star images in the 'flower' pattern that they're been drawn in.
What am I doing wrong?
Fragment shader:
#version 140
#extension GL_ARB_explicit_attrib_location : enable
precision mediump float;
uniform sampler2D uTexture;
void main( void )
{
gl_FragColor = texture2D( uTexture, gl_PointCoord );
}
Vertex shader:
#version 140
#extension GL_ARB_explicit_attrib_location : enable
precision mediump float;
layout (location = 0) in float aTheta;
uniform float uK;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main( void )
{
float x = cos( uK * aTheta ) * sin( aTheta );
float y = cos( uK * aTheta ) * cos( aTheta );
gl_Position = projection * view * model * vec4( x, y, 0.0, 1.0 );
gl_PointSize = 64.0;
}
Code:
void CPoint::Render( void )
{
g_PointProgram.UseProgram();
glEnable( GL_PROGRAM_POINT_SIZE );
glEnable( GL_POINT_SPRITE );
// Set the alpha blending function
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glBlendEquation( GL_FUNC_ADD );
glBindBuffer( GL_ARRAY_BUFFER, m_VBO );
glm::mat4 Model = glm::mat4( 1.0 );
Model = glm::translate( Model, glm::vec3( 2.0f, 0.0f, 4.0f ) );
glm::mat4 Projection = g_Camera.GetProjection();
glm::mat4 View = g_Camera.GetView();
g_PointProgram.SetUint( "uTexture", g_ImgStar.m_Texture );
g_PointProgram.SetMatrix4fv( "model", Model );
g_PointProgram.SetMatrix4fv( "view", View );
g_PointProgram.SetMatrix4fv( "projection", Projection );
g_PointProgram.SetFloat( "uK", m_Emitter.k );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, g_ImgStar.m_Texture );
glEnable( GL_TEXTURE_2D );
// Attributes
glVertexAttribPointer( 0, // 1st attribute array (only have 1)
1, // One theta angle per particle
GL_FLOAT, // Data is floating point type
GL_FALSE, // No fixed point scaling
sizeof( Particle ), // No gaps in data
(void*) 0 ); // Start from "theta" offset within bound buffer
glEnableVertexAttribArray( 0 );
glDrawArrays( GL_POINTS, 0, NUM_PARTICLES );
glDisableVertexAttribArray( 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDisable( GL_TEXTURE_2D );
}
Perhaps depth culling is playing tricks on you? Try glDepthMask(false) while rendering the sprites

OpenGL 4.0 Cubemap issues

Been reading 'OpenGL 4.0 Shading Language Cookbook'. But I've run into a wall with the cubemap tutorial.
The issue is that model I'm drawing appears completely grey. As if it's not getting any data from the samplerCube texture.
All my code seems to be correct. I've looked at other tutorials and it's the same thing.
Don't know if my Intel HD Graphics 4000 is responsible, but I have made certain that I do have the GL_ARB_texture_cube_map extension.
I'm using the DevIL library for loading images from file, which it seems to do just fine, but from what I can tell something is going wrong in transferring the data to OpenGL.
I'm posting the loading where I get the data from the files. All files are loading correctly as well.
I'm also posting the drawing code, where I bind the texture to the pipeline.
And I'm also posting my vertex and fragment shader just in case, but they do appear to be working as they should.
Any ideas?
Loading code
uint TARGETS[6] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
string EXTS[6] =
{
"posx",
"negx",
"posy",
"negy",
"posz",
"negz"
};
// Create & bind cubemap texture
glGenTextures( 1, &cubemap );
glBindTexture( GL_TEXTURE_CUBE_MAP, cubemap );
for( int i = 0; i < 6; i++ )
{
string file = "textures/cubemap_" + EXTS[i] + ".png";
uint image = ilGenImage();
// Load with DevIL
ilBindImage( image );
if( !ilLoadImage( file.c_str() ) )
{
cout << "ERROR: Failed to load image " << endl;
return false;
}
// Fetch info from DevIL
int width = ilGetInteger( IL_IMAGE_WIDTH );
int height = ilGetInteger( IL_IMAGE_HEIGHT );
uint format = ilGetInteger( IL_IMAGE_FORMAT );
uint type = ilGetInteger( IL_IMAGE_TYPE );
// Send data to OpenGL
glTexImage2D(
TARGETS[i],
0,
GL_RGBA,
width,
height,
0,
format,
type,
ilGetData() );
// Error check
if( !ErrorCheck("Failed to bind a side of the cubemap!") )
return false;
// Get rid of DevIL data
ilDeleteImage( image );
}
// Parameters
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
Draw code
// Update
glfwPollEvents();
UpdateTime();
// Clear back buffer for new frame
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Bind shader
shader->Bind();
// Cubemap
shader->SetUniform( "cubemapTexture", 0 );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_CUBE_MAP, cubemap );
// Bind model
if( model->Bind() )
{
static float angle = 0;
angle += 25.0f * deltaTime;
// Matrices
mat4 world =
translate( vec3( 0.0f, 0.0f, 0.0f) ) *
rotateZ( angle * PI / 180 ) *
rotateX( angle * PI / 180 ) *
scale( vec3( 1.0f, 1.0f, 1.0f) );
mat4 view = ViewMatrix(
cameraPosition,
cameraTarget,
vec3( 0.0f, 0.0f, 1.0f) );
mat4 proj = ProjectionMatrix(
fov,
(float)windowX,
(float)windowY,
nearPlane,
farPlane );
// Uniforms
shader->SetUniform( "uWorld", world );
shader->SetUniform( "uView", view );
shader->SetUniform( "uProj", proj );
shader->SetUniform( "materialColor", vec3( 0.5f, 0.5f, 0.5f ) );
shader->SetUniform( "drawSkybox", false );
shader->SetUniform( "world_cameraPosition", cameraPosition );
shader->SetUniform( "reflectFactor", 0.5f );
// Draw
glDrawElements( GL_TRIANGLES, model->GetIndexCount(), GL_UNSIGNED_SHORT, NULL );
}
// Put the new image on the screen
glfwSwapBuffers( window );
Vertex Shader
#version 400
layout(location=0) in vec3 vertex_position;
layout(location=1) in vec3 vertex_normal;
layout(location=2) in vec4 vertex_tangent;
layout(location=3) in vec2 vertex_texCoords;
out vec2 texCoords;
out vec3 reflectDir;
uniform mat4 uWorld;
uniform mat4 uView;
uniform mat4 uProj;
uniform bool drawSkybox;
uniform vec3 world_cameraPosition;
void main()
{
if( drawSkybox )
{
reflectDir = vertex_position;
}
else
{
vec3 world_pos = vec3( uWorld * vec4(vertex_position,1.0) );
vec3 world_norm = vec3( uWorld * vec4(vertex_normal,0.0) );
vec3 world_view = normalize( world_cameraPosition - world_pos );
reflectDir = reflect( -world_view, world_norm );
}
gl_Position = uProj * uView * uWorld * vec4(vertex_position,1.0);
texCoords = vertex_texCoords;
}
Fragment shader
#version 400
out vec4 fragColor;
in vec2 texCoords;
in vec3 reflectDir;
uniform samplerCube cubemapTexture;
uniform vec3 materialColor;
uniform bool drawSkybox;
uniform float reflectFactor;
void main()
{
vec3 color = texture( cubemapTexture, reflectDir ).rgb;
if( drawSkybox )
{
fragColor = vec4( color, 1.0 );
}
else
{
fragColor = vec4( mix( materialColor, color, reflectFactor ), 1.0 );
}
}
Your cube map texture is not texture complete. All 6 sides need to be specified for a cube map texture to be complete. From the specs:
Additionally, a cube map texture is cube complete if the following conditions all hold true: [..] The level_base arrays of each of the six texture images making up the cube map have identical, positive, and square dimensions.
Your code does not specify an image for NEGATIVE_X:
uint TARGETS[6] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
Using this table, the image for NEGATIVE_Y is specified twice, but it's missing NEGATIVE_X. It should be:
uint TARGETS[6] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
Instead of enumerating the 6 targets, you can also use GL_TEXTURE_CUBE_MAP_POSITIVE_X + i for i in the range 0..5 to address the 6 targets.

Use normals as colors in OpenGL using assimp

I exported the suzanne model from blender(Monkey head) as a .obj file and I can only see it when I use the RGB values in the fragment shader. e.g. frag_color = vec4( 1.0, 0.0, 0.0, 1.0 ); to make the model red. But it just looks like a deformed texture unless I rotate it
I want to use the normals as colors so that I can see specific details in the face, etc. I bound the normals to vertex position 1.
if ( mesh -> HasNormals() )
{
normals = ( GLfloat * ) malloc( * pointCount * 3 * sizeof( GLfloat ) );
for ( int i = 0; i < * pointCount; i++ )
{
const aiVector3D * vn = &( mesh -> mNormals[ i ] );
normals[ i * 3 ] = ( GLfloat ) vn -> x;
normals[ i * 3 + 1 ] = ( GLfloat ) vn -> y;
normals[ i * 3 + 2 ] = ( GLfloat ) vn -> z;
}
GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, 3 * * pointCount * sizeof( GLfloat ), normals, GL_STATIC_DRAW );
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, NULL );
glEnableVertexAttribArray( 1 );
free( normals );
}
And I bound 1 to vertex_normal right after attaching the shaders but right before linking.
glAttachShader( program, vertShader );
glAttachShader( program, fragShader );
glBindAttribLocation( program, 0, "vertex_position" );
glBindAttribLocation( program, 1, "vertex_normal" );
glLinkProgram( program );
These are my shaders
vertshader.shader
#version 330
in vec3 vertex_position;
in vec3 vertex_normal;
uniform mat4 proj, view, model;
out vec3 normals;
void main()
{
normals = vertex_normal;
gl_Position = proj * vec4( vec3( view * model * vec4( vertex_position, 1.0 ) ), 1.0 );
}
fragshader.shader
#version 330
in vec3 normals;
out vec4 fragment_color;
void main()
{
fragment_color = vec4( normals, 1.0 );
}
But this only outputs a black screen. I know the model is loading because I can color it red like above. I tried importing vertex_normal directly into the frag shader, that didn't work, I also tried normalizing normals and that didn't change the effect neither.
So how can I use the models normals as colors in the fragment shader?
Ok, I found a fix. Apparently it was blenders fault. There is a side panel on what I want to export with my mesh, and Write normals wasn't checked. Thanks to Reto Koradi, I didn't think it was possible for a mesh to be written without normals.

OpenGL Vertex Buffer incorrect render

I'm having a bit of an odd problem. I'm trying to render some data with OpenGL on my Windows system. I found a set of tutorials at opengl-tutorial.org which were written for OpenGL 3.3. As my laptop (where I do a great deal of developing) only supports OpenGL 2.1, I proceeded to download the OpenGL 2.1 port of the tutorial. I messed around with it a bit, adding features and refactoring it for scalability, but noticed something odd. Whenever I rendered my data with Vertex Buffer Objects, I got a rather incorrect representation of my data. This is shown below.
http://www.majhost.com/gallery/DagonEcelstraun/Others/HelpNeeded/badrender.png
However, when I specify my data using glVertex3fv and such, I get a much nicer result, again shown below.
http://www.majhost.com/gallery/DagonEcelstraun/Others/HelpNeeded/goodrender.png
The problem occurs both on my Windows 8.1 laptop with Intel i3 integrated graphics and on my Windows 7 desktop with its nVidia GTX 660, so it's not a hardware problem. Does anyone know what may be the issue here?
Loading mesh data:
const aiScene *scene = aiImportFile( sName.c_str(),
aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_FlipUVs );
const aiMesh *mesh = scene->mMeshes[0];
for( int i = 0; i < mesh->mNumVertices; i++ ) {
meshData.push_back( mesh->mVertices[i][0] );
meshData.push_back( mesh->mVertices[i][1] );
meshData.push_back( mesh->mVertices[i][2] );
meshData.push_back( mesh->mNormals[i][0] );
meshData.push_back( mesh->mNormals[i][1] );
meshData.push_back( mesh->mNormals[i][2] );
meshData.push_back( mesh->mTextureCoords[0][i][0] );
meshData.push_back( mesh->mTextureCoords[0][i][1] );
meshData.push_back( 0 );
meshData.push_back( mesh->mTangents[i][0] );
meshData.push_back( mesh->mTangents[i][1] );
meshData.push_back( mesh->mTangents[i][2] );
}
for( int i = 0; i < mesh->mNumFaces; i++ ) {
for( int j = 0; j < 3; j++ ) {
indices.push_back( mesh->mFaces[i].mIndices[j] );
}
}
Sending data to the graphics card for the first time (called right after previous code):
glGenBuffers( 1, &glVertData );
glBindBuffer( GL_ARRAY_BUFFER, glVertData );
glBufferData( GL_ARRAY_BUFFER, meshData.size() * sizeof( GLfloat ), &meshData[0], GL_STATIC_DRAW );
// Generate a buffer for the indices as well
glGenBuffers( 1, &glIndexes );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, glIndexes );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW );
Rendering the mesh:
//Tell the shader to use our data
//bindVerts, bindUvs, bindNorms, and bindTangents refer to attribute variables in my shader
//vertexPosition_modelspace, vertexUV, vertexNormal_modelspace, and vertexTangent_modelspace, respectively.
this->verts = bindVerts;
this->uvs = bindUvs;
this->norms = bindNorms;
this->tangents = bindTangents;
glEnableVertexAttribArray( verts );
glEnableVertexAttribArray( uvs );
glEnableVertexAttribArray( norms );
glEnableVertexAttribArray( tangents );
//Specify how the graphics card should decode our data
// 1rst attribute buffer : vertices
glBindBuffer( GL_ARRAY_BUFFER, glVertData );
glVertexAttribPointer( verts, 3, GL_FLOAT, GL_FALSE, 12, (void*) 0 );
// 2nd attribute buffer : normals
glVertexAttribPointer( norms, 3, GL_FLOAT, GL_FALSE, 12, (void*) 3 );
//3rd attribute buffer : UVs
glVertexAttribPointer( uvs, 3, GL_FLOAT, GL_FALSE, 12, (void*) 6 );
//4th attribute buffer: tangents
glVertexAttribPointer( tangents, 3, GL_FLOAT, GL_FALSE, 12, (void*) 9 );
// Index buffer
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, glIndexes );
//rendering the mesh with VBOs:
glDrawElements( GL_LINES, indices.size(), GL_UNSIGNED_SHORT, (void*) 0 );
//specifying the vertex data individually:
glBegin( GL_TRIANGLES );
int ind;
for( int i = 0; i < indices.size(); i++ ) {
ind = indices[i] * 12;
glNormal3fv( &meshData[ind + 3] );
glTexCoord2fv( &meshData[ind + 6] );
glVertex3fv( &meshData[ind] );
}
glEnd();
//clean up after the render
glDisableVertexAttribArray( verts );
glDisableVertexAttribArray( uvs );
glDisableVertexAttribArray( norms );
glDisableVertexAttribArray( tangents );
My vertex shader:
#version 130
// Input vertex data, different for all executions of this shader.
//it doesn't work, so we'll just get rid of it
attribute vec3 vertexPosition_modelspace;
attribute vec3 vertexUV;
attribute vec3 vertexNormal_modelspace;
attribute vec3 vertexTangent_modelspace;
// Output data ; will be interpolated for each fragment.
out vec2 UV;
out vec3 Position_worldspace;
out vec3 Normal_cameraspace;
out vec3 EyeDirection_cameraspace;
out vec3 LightDirection_cameraspace;
out vec4 ShadowCoord;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
uniform vec3 LightInvDirection_worldspace;
uniform mat4 DepthBiasMVP;
uniform sampler2D normalMap;
attribute vec3 vTangent;
void main() {
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4( vertexPosition_modelspace, 1 );
ShadowCoord = DepthBiasMVP * vec4( vertexPosition_modelspace, 0 );
// Position of the vertex, in worldspace : M * position
Position_worldspace = ( M * vec4( vertexPosition_modelspace, 0 ) ).xyz;
// Vector that goes from the vertex to the camera, in camera space.
// In camera space, the camera is at the origin (0,0,0).
EyeDirection_cameraspace = vec3( 0, 0, 0 ) - ( V * M * vec4( vertexPosition_modelspace, 0 ) ).xyz;
// Vector that goes from the vertex to the light, in camera space
LightDirection_cameraspace = ( V * vec4( LightInvDirection_worldspace, 0 ) ).xyz;
// UV of the vertex. No special space for this one.
UV = vertexUV.st;
// Normal of the the vertex, in camera space
// Only correct if ModelMatrix does not scale the model ! Use its inverse transpose if not.
Normal_cameraspace = ( V * M * vec4( vertexNormal_modelspace.xyz, 0 ) ).xyz;
}
Fragment shader:
#version 130
// Interpolated values from the vertex shaders
in vec2 UV;
in vec3 Position_worldspace;
in vec3 Normal_cameraspace;
in vec3 EyeDirection_cameraspace;
in vec3 LightDirection_cameraspace;
in vec4 ShadowCoord;
out vec4 fragColor;
// Values that stay constant for the whole mesh.
uniform sampler2D diffuse;
uniform mat4 MV;
uniform vec3 LightPosition_worldspace;
uniform sampler2D shadowMap;
//uniform int shadowLevel; //0 is no shadow, 1 is hard shadows, 2 is soft shadows, 3 is PCSS
// Returns a random number based on a vec3 and an int.
float random( vec3 seed, int i ) {
vec4 seed4 = vec4( seed, i );
float dot_product = dot( seed4, vec4( 12.9898, 78.233, 45.164, 94.673 ) );
return fract( sin( dot_product ) * 43758.5453 );
}
int mod( int a, int b ) {
return a - (a / b);
}
void main() {
int shadowLevel = 1; //let's just do hard shadows
// Light emission properties
vec3 LightColor = vec3( 1, 1, 1 );
float LightPower = 1.0f;
// Material properties
vec3 MaterialDiffuseColor = texture( diffuse, UV ).rgb;
vec3 MaterialAmbientColor = vec3( 0.1, 0.1, 0.1 ) * MaterialDiffuseColor;
vec3 MaterialSpecularColor = vec3( 0.3, 0.3, 0.3 );
vec3 n = normalize( Normal_cameraspace );
vec3 l = normalize( LightDirection_cameraspace );
float cosTheta = clamp( dot( n, l ), 0.2, 1 );
// Eye vector (towards the camera)
vec3 E = normalize( EyeDirection_cameraspace );
// Direction in which the triangle reflects the light
vec3 R = reflect( -l, n );
// Cosine of the angle between the Eye vector and the Reflect vector,
// clamped to 0
// - Looking into the reflection -> 1
// - Looking elsewhere -> < 1
float cosAlpha = clamp( dot( E, R ), 0, 1 );
float visibility = 1.0;
//variable bias
float bias = 0.005 * tan( acos( cosTheta ) );
bias = clamp( bias, 0, 0.01 );
// dFragment to the light
float dFragment = ( ShadowCoord.z-bias ) / ShadowCoord.w;
float dBlocker = 0;
float penumbra = 1;
float wLight = 5.0;
if( shadowLevel == 3 ) {
// Sample the shadow map 8 times
float count = 0;
float temp;
float centerBlocker = texture( shadowMap, ShadowCoord.xy).r;
float scale = (wLight * (dFragment - centerBlocker)) / dFragment;
for( int i = 0; i < 16; i++ ) {
temp = texture( shadowMap, ShadowCoord.xy + (scale * poissonDisk( i ) / 50.0) ).r;
if( temp < dFragment ) {
dBlocker += temp;
count += 1;
}
}
if( count > 0 ) {
dBlocker /= count;
penumbra = wLight * (dFragment - dBlocker) / dFragment;
}
}
if( shadowLevel == 1 ) {
if( texture( shadowMap, ShadowCoord.xy).r < dFragment ) {
visibility -= 0.8;
}
} else if( shadowLevel > 1 ) {
float iterations = 32;
float sub = 0.8f / iterations;
for( int i = 0; i < iterations; i++ ) {
int index = mod( int( 32.0 * random( gl_FragCoord.xyy, i ) ), 32 );
if( texture( shadowMap, ShadowCoord.xy + (penumbra * poissonDisk( index ) / 250.0) ).r < dFragment ) {
visibility -= sub;
}
}
}
visibility = min( visibility, cosTheta );
//MaterialDiffuseColor = vec3( 0.8, 0.8, 0.8 );
fragColor.rgb = MaterialAmbientColor +
visibility * MaterialDiffuseColor * LightColor * LightPower +
visibility * MaterialSpecularColor * LightColor * LightPower * pow( cosAlpha, 5 );
}
Note that poissonDisk( int ind ) returns a vec2 with a magnitude of no more than 1 which is in a poisson disk distribution. Even though I'm using shader version 130, I used a function and not an array because the array runs rather slowly on my laptop.
I do bind that shader before I do any rendering. I also make sure to upload the correct variables to all of my uniforms, but I didn't show that to save space since I know it's working correctly.
Does anyone know what's causing this incorrect render?
Well, first of all, stop drawing the VBO using GL_LINES. Use the same primitive mode for immediate mode and VBO drawing.
Also, since when is 3*4 = 3? The address (offset) in your VBO vertex pointers should be the number of elements multiplied by the size of the data type when using an interleaved data structure. GL_FLOAT is 4 bytes, if you have a 3-component vertex position this means that the offset to the next field in your VBO is 3*4 = (void *)12, not (void *)3. This process must continue for each additional vertex array pointer, they all use incorrect offsets.
Likewise, the stride of your VBO should be 12 * sizeof (GLfloat) = 48, not 12.