PDA

View Full Version : How to draw multiple things(objects) in OpenGL v. 4,3



Sarda Karda
09-18-2014, 12:30 PM
Hello,

i statred to learn opengl, from superbible 6th edition(version 4.3), and, i have a troubles with a drawing things. I am learning from opengl tutorials on internet, too. lets say, i have a very simple vertex shader, :
#version 430 core
in vec4 position;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 model_matrix;
void main(void)
{
gl_Position = proj_matrix * mv_matrix * model_matrix * position;
}
and in my render func. :
vmath::mat4 model_matrix = vmath::translate(0.0f, 0.0f, -0.3f);
vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -6.0f) *
vmath::translate( r, 0.0f, 0.0f);
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);
glDrawArrays(GL_TRIANGLES, 0, 36);
(here i am not using a lookat matrix, but it doesnt matter)now, i can draw only one cube. My question is, how to draw more cubes, with that i will can set their position by model matrix. will i need more shaders? or what? Probably it is a very easy thing, but i cant find the solution(remember, pls, that i want to set their position, because i can draw more cubes if i will call my render func more times, but how to set their position?).

Ruggero Visitnin
09-18-2014, 10:10 PM
you have to call the draw function for each object you want to draw, let's say that you have 10 cube stored in a VAO:
this is like pseudocode and should be adapted to work correctly


displayFunction()
{
...
glUseProgramFunction();
for(model_VAO_size)
{
send_uniforms_to_shader();
drawModel(model_vao_index); //*
}
glUseProgram(NULL);

}

//*
drawFunction(model_vao_index)
{
glBindVertexArrayFunction(vao_vector[model_vao_index]);
if(glDrawElements)
glDrawElementsFunction(..., ibo_vector[model_vao_index].size()...);
else
glDrawArray(..., vao_vector[model_vao_index], vao_vector[model_vao_index].size());

}

this is about what you have to do.
i hope you will understand because i'm going to school and i could not answer again for a while

Sarda Karda
09-19-2014, 05:12 AM
Ah! Yes. :D Thats nice help. :D Thank you very much!. Now im getting troubles with a color, or texture of that cube, i dont know, how to make that first one will be red, second one will be blue. I tried to use a uniform, but it takes care only of first sent value to shader.

Sarda Karda
09-20-2014, 10:39 AM
So, can anybody help me, how do i can draw more cubes with a diffrent color or texture? Iam sending a color from a vertex shader to fragment, and in my render func. i am setting that color for vertex shader(by a uniform) but, it doesnt work(the color is the same every time.).

Ruggero Visitnin
09-20-2014, 10:56 AM
hi it's me again,
for color things are very simple, they are for texture too but texture is a bit more complicated than color.
Think that you have a model, this model should have some attributes like material_color, a texture attached or a pointer to a texture or the index to find te right texture in your textures array:


struct MyModel
{
Mesh //(vbos and stuff like that)
Material { Texture, Color, Ambient_albedo, Diffuse_albedo, Specular_albedo, Shininess }
}

// when you draw
displayFunction()
{
...
glUseProgramFunction();
for(model_vector_size)
{
send_uniforms_to_shader(); //*
drawModel(model_vao_index);
}
glUseProgram(NULL);

}

//*
send_uniform_to_shader()
{
sendMaterialColor(model_index);
sendMaterialAmbientAlbedo(model_index)

//and so on, this for each model you want to draw
}


i hope the explanation is easily understandable ;)

ah, i saw that last time i made a terrible mistake: in the for loop in the display function you should iterate for the number of the models and not for the size of the VAO, i'm so sorry, what a newbie mistake

Sarda Karda
09-20-2014, 11:56 AM
For me, it is hard to understand :D maybe i will need an example, how it look because i think, you explained the same thing what doesnt work for me. My soucre of vertex_shader looks a bit like that:

#version 410 core
in vec4 position;
out VS_OUT
{
vec4 color;
} vs_out;
uniform vec4 pica;
void main(void)
{
gl_Position = proj_matrix * mv_matrix * model_matrix * position;
vs_out.color = position * 2.0 + pica;
}
fragment_shader:
#version 410 core

out vec4 color;

in VS_OUT
{
vec4 color;
} fs_in;

void main(void)
{
color = fs_in.color;
}
then in render func.
vmath::vec4 pica = vmath::vec4(0.5, 0.5, 0.5, 0.0);
vmath::mat4 model_matrix = vmath::translate(0.0f, 0.0f, -0.3f);
vmath::mat4 mv_matrix =

vmath::translate(0.0f, 0.0f, -6.0f) *
vmath::translate( r, 0.0f, p);


//glUniformMatrix4fv(cam_location, 1, GL_FALSE, cam_matrix);
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);
glUniformMatrix4fv(pica_location, 1, GL_FALSE, pica);
glDrawArrays(GL_TRIANGLES, 0, 36);

But the color doesnt change when i am changing a value of pica. What could be a problem?

Ruggero Visitnin
09-20-2014, 01:13 PM
the rgba values of the colors must be in the range between 0 and 1, values greater than 1 will be considered like they are 1 and value less than 0 will be considered 0.
try something like this:

vertex shader:



in vec4 position;

void main(void)
{
gl_Position = proj_matrix * mv_matrix * model_matrix * position;
}



fragment shader:



out vec4 frag_color;

void main()
{
frag_color = vec4(1.0, 0.0, 0.0, 1.0);
}



the result should be red, otherwise there is something else wrong but is not in the code above

Sarda Karda
09-21-2014, 12:27 AM
Ah, im idiot. :D The problem was in the render func. i was using :
vmath::vec4 pica = vmath::vec4(0.5, 0.5, 0.5, 0.0);
glUniformMatrix4fv(pica_location, 1, GL_FALSE, pica);
the right way is :
glUniform4f(pica_location, 1.0f, 0.0f, 0.0f, 1.0f);

So, thank you very much. ;)
So, now i want to set their texture, can you help me again?:D Look, my fragment shader:

#version 410 core

out vec4 color;
uniform sampler2D s;
void main(void)
{
color = texture(s, gl_FragCoord.xy / textureSize(s, 0));
}
and in my startup function(the function where i am loading my shaders)
i have
glGenTextures(1, &texture);
sb6::ktx::file::load("media/textures/brick.ktx", texture);
glBindTexture(GL_TEXTURE_2D, texture);
so, now, the texture of my cubes are bricks. but if i want to draw more cubes, i will need to set a new texture in a new draw function in a render function. it should looks like this :
glGenTextures(1, &texture);
sb6::ktx::file::load("media/textures/brick.ktx", texture);
glBindTexture(GL_TEXTURE_2D, texture);

vmath::mat4 model_matrix = vmath::translate(1.0f, 1.0f, -0.3f);
glUniform4f(pica_location, 1.0f, 1.0f, 0.0f, 1.0f);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);

glDrawArrays(GL_TRIANGLES, 0, 36);

int i;
for (i = 0; i < 1; i++)
{
glGenTextures(1, &texturee);
sb6::ktx::file::load("media/textures/floor.ktx", texturee);
glBindTexture(GL_TEXTURE_2D, texturee);

vmath::mat4 model_matrix = vmath::translate(0.0f, 0.0f, -0.3f);
vmath::mat4 mv_matrix =vmath::translate(0.0f, 0.0f, -6.0f) *
vmath::translate( r, 0.0f, p);
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);
glUniform4f(pica_location, 1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
now, i have 2 cubes with a diffrent textures, but it makes a bit laggs. my camera movment is a lot of slower, because my render function is repeating all the time, it is like a while cyclus. So, i would need to set the texture only one time. For this, i can do something like
if (GetAsyncKeyState(VK_F2))
{
glGenTextures(1, &texture);
sb6::ktx::file::load("media/textures/brick.ktx", texture);
glBindTexture(GL_TEXTURE_2D, texture);
}
vmath::mat4 model_matrix = vmath::translate(1.0f, 1.0f, -0.3f);
glUniform4f(pica_location, 1.0f, 1.0f, 0.0f, 1.0f);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);

glDrawArrays(GL_TRIANGLES, 0, 36);

int i;
for (i = 0; i < 1; i++)
{
if (GetAsyncKeyState(VK_F1))
{
glGenTextures(1, &texturee);
sb6::ktx::file::load("media/textures/floor.ktx", texturee);
glBindTexture(GL_TEXTURE_2D, texturee);
}
vmath::mat4 model_matrix = vmath::translate(0.0f, 0.0f, -0.3f);
vmath::mat4 mv_matrix =vmath::translate(0.0f, 0.0f, -6.0f) *
vmath::translate( r, 0.0f, p);
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);
glUniform4f(pica_location, 1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 0, 36); so now, i have to click F1 and F2 and then, textures have been sucessfuly set. Camera works without lags. But, i think, it is not the right way, so i will need a normal reason for my if cyclus. (the reason would be something that user of that program will not need to click f1 or f2, it will be "automatically")
can you help me with that reason? or, another way how to do that?

Ruggero Visitnin
09-21-2014, 02:11 AM
what IDE are you using right now?

Sarda Karda
09-21-2014, 03:31 AM
Microsoft VisualStudio 2010

or wait, what is ide?:D

Ruggero Visitnin
09-21-2014, 05:50 AM
an IDE is an Integrated development environment like in your case visual studio or eclipse and so on.
about your problem of lag it could be the frame rate or it could be the camera that is not properly updated, what you can try to do, is download Nsight from Nvidia and in visual studio launch your application with Nsight, this tool shows the frame rate, frame time and other useful stuff of your application
Nsight (https://developer.nvidia.com/nvidia-nsight-visual-studio-edition)

Sarda Karda
09-21-2014, 08:28 AM
It looks like it doesnt work, because i have AMD Gpu.
Btw. i think my problem is only because it is a for-ever cyclus in my render function(binding a texture), all what i want is a reason for if cyclus, which should be something like a program_start(its value should be 0, when program starts, its value is 1, and then, its value will be 2). So, i will can use if(value == 1){bind texture;} .. the user of a program will not have to click F1 or F2, the textures will appear, and of course it will not make lags.

or no, it is not possible, the cubes must be rendered in the same time, just then they could have a diffrent texture.

Ruggero Visitnin
09-21-2014, 10:05 AM
ok here some basic but very important concepts:
1)the textures have to be generated and initialized outside the main loop otherwise you will continue to generate the same texture again and again
2) this is about code organization, you should have a data structure that represents a model and assign a texture to this model so when you want to draw your model you don't have to find the texture, you just have to bind the texture of your model
3) like said above in the main loop you have to bind a texture then send the uniform of this texture to the shader for every texture you want to draw

here your pseudocode:


initFunc()
{
...
glGenTexture();
glBindTexture();

glTexParametri();
glTexParametri();

...

glTexImage2D();
}


mainLoopFunc()
{
...
for(i < number_of_model)
{
glBindTexture(model[i].material.texture_id);
glActiveTexture(TEXTURE_0);

glGetTextureUniform("yourTextureUniform");
glUniform1i(0);

glDrawElements();
}
}


where model is:


model
{
material
{
texture_id;
shader; // not important for now
}

mesh
{
vao_id;
}
}


i'm sorry but i can understand what are you doing in your code because is very messy, but for what i could understand you are doing a enormous mistake that is generate the texture and load the image file in the main loop, it wastes a lot of frame time:
let's say that frame time is usually around 16ms per frame, file loading require about 1 second or more, it have to be done out of the render cicle, possibly with it's own thread.

Sarda Karda
09-21-2014, 12:22 PM
For what i should use a glActiveTexture? because when i am using that function(so i am using more sampler2D uniforms in my shader, i can not draw them in a diffrent textures) so.. : fragment shader:
#version 410 core

out vec4 color;

uniform sampler 2D s;

void main(void)
{
color = texture(s, gl_FragCoord.xy / textureSize(s, 0));
}

so, my Texture functions. :
void tex()
{
glGenTextures(1, &texturee);
sb6::ktx::file::load("media/textures/floor.ktx", texturee);
// Now bind it to the context using the GL_TEXTURE_2D binding point
glBindTexture(GL_TEXTURE_2D, texturee);
}
void tex2()
{
glGenTextures(1, &texture);
sb6::ktx::file::load("media/textures/brick.ktx", texture);
// Now bind it to the context using the GL_TEXTURE_2D binding point
glBindTexture(GL_TEXTURE_2D, texture);
}
and in render func:
tex();

vmath::mat4 model_matrix = vmath::translate(1.0f, 1.0f, -0.3f);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);

glDrawArrays(GL_TRIANGLES, 0, 36);

int i;
for (i = 0; i < 1; i++)
{
tex2();

vmath::mat4 model_matrix = vmath::translate(0.0f, 0.0f, -0.3f);
vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -6.0f) *
vmath::translate( r, 0.0f, p);

glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glUniformMatrix4fv(model_location, 1, GL_FALSE, model_matrix);
glDrawArrays(GL_TRIANGLES, 0, 36);
}

btw: that sb6::ktx file loader is doing automatically some things for me, so all what i have to do is bind the texture.

Yes, so now, the same problem. It is making a laggs, my camera is slower, and if i increase a speed of camera movment, it is the same.