Sign in to follow this  
Followers 0
Hector San Roman Lanza

OpenGL
How can I use multiple shaders in one mesh?

3 posts in this topic

Hi!
I want to apply multiple shader to one mesh. I get the vertex from OBJ file, I load with VAO, IBO and I draw with glElementsDraw()

class Cube,
class Mesh
[CODE]Mesh::Mesh(){}
Mesh::~Mesh()
{
glDeleteBuffers(2, &BufferIds[1]);
glDeleteVertexArrays(1, &BufferIds[0]);
ExitOnGLError("ERROR: No se pueden destruir los buffer objects");
}
void Mesh::Initialize()
{
// Creamos el VAO
glGenVertexArrays(1, &BufferIds[0]);
ExitOnGLError("ERROR: No se puede generar el VAO");
glBindVertexArray(BufferIds[0]);
ExitOnGLError("ERROR: No se puede bindear el VAO");
// Activamos dos vertex attribute locations
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
ExitOnGLError("ERROR: No se puede activar los vertex attributes");
// Creamos los VBO
glGenBuffers(2, &BufferIds[1]);
ExitOnGLError("ERROR: No se pueden generar los buffer objects");
// Bindeamos el VBO al VAO
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[1]);
glBufferData(GL_ARRAY_BUFFER, vtn.size()*sizeof(VertexTextureNormal), &vtn[0], GL_STATIC_DRAW);
ExitOnGLError("ERROR: No se puede bindear el VBO al VAO");
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vtn[0]) ,0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vtn[0]) , (GLvoid*) sizeof(vtn[0].position));
ExitOnGLError("ERROR: Could not set VAO attributes");
// Creamos el IBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BufferIds[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices.front(), GL_STATIC_DRAW);
ExitOnGLError("ERROR: No se puede bindear el IBO al VAO");
glBindVertexArray(0);
}
void Mesh::Draw()
{
glBindVertexArray(BufferIds[0]);
ExitOnGLError("ERROR: No se puede bindear el VAO para dibujar");
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (GLvoid*)0);
ExitOnGLError("ERROR: No se puede dibujar el mesh");
glBindVertexArray(0);
}
void Mesh::Load(std::string filename)
{
// ifstream: clase para leer archivos que recibe como parametros
//la ruta del archivo y un indicador del tipo de operacion
std::string mesh_source = OpenFile(filename, std::ios::in);
std::istringstream iss(mesh_source);
std::vector<glm::vec4> f_vertices;
std::vector<glm::vec2> f_texcoords;
std::vector<glm::vec3> f_normals;
std::vector<int> f_indices;
// string que representa una linea del archivo
std::string line;
// Avanzamos linea a linea del archivo
while(std::getline(iss, line))
{
// Si es un vertice
if (line.substr(0,2) == "v ")
{
// istringstream: para hacer operaciones de stream sobre una cadena. Recibe como parametro el string
std::istringstream s(line.substr(2));
glm::vec4 t_v;
s >> t_v.x;
s >> t_v.y;
s >> t_v.z;
t_v.w = 1.0f;
f_vertices.push_back(t_v);
}else
if(line.substr(0,2) == "vt") // si es un texcoord
{
// istringstream: para hacer operaciones de stream sobre una cadena. Recibe como parametro el string
std::istringstream s(line.substr(2));
glm::vec2 t_vt;
s >> t_vt.x;
s >> t_vt.y;
f_texcoords.push_back(t_vt);
}else
if(line.substr(0,2) == "vn") // si es un normal
{
// istringstream: para hacer operaciones de stream sobre una cadena. Recibe como parametro el string
std::istringstream s(line.substr(2));
glm::vec3 t_vn;
s >> t_vn.x;
s >> t_vn.y;
s >> t_vn.z;
f_normals.push_back(t_vn);
}else
if(line.substr(0,2) == "f ") // Si son indices
{
std::string s;
int i = 0;
while (i < line.length())
{
s.clear();
while (isdigit(line[i]))
s += line[i++];
if (s.length()>0)
f_indices.push_back(atoi(s.c_str())-1);
i++;
}
}
}
// Asignamos a cada vertice su posicion, texcoord y normal correspondiente
//a partir de su indice
std::vector<VertexTextureNormal> vectorVertex;
int t=0;
for(register int i = 0; i < f_indices.size(); i+=3)
{
// Generamos un vtn temporal
VertexTextureNormal t_vtn;
t_vtn.position = f_vertices[f_indices[i]];
t_vtn.texcoord = f_texcoords[f_indices[i+1]];
vectorVertex.push_back(t_vtn);
std::cout<<f_indices[i]+1<<" ";
t++;
if(t==3)
{
std::cout<<std::endl;
t = 0;
}
}
//ordenamos los vertices y obtenemos los indices
indexVBO(vectorVertex, vtn, indices);
// Inicializamos el mesh en el OpenGL
Initialize();
}
void Mesh::indexVBO(
std::vector<VertexTextureNormal> &in_vtn,
std::vector<VertexTextureNormal> &out_vtn,
std::vector<GLuint> &out_indices
)
{
std::map<VertexTextureNormal,GLuint> VertexToOutIndex;
// Recorremos los vertices
for(register int i = 0; i < in_vtn.size(); i++)
{
VertexTextureNormal temp_vtn = in_vtn[i];
// Buscamos si hay un vertice similar
GLuint index;
bool found = getSimilarVertexIndex(temp_vtn, VertexToOutIndex, index);
if(found){
out_indices.push_back(index);
}else{
out_vtn.push_back( in_vtn[i] );
GLuint newIndex = (GLuint)out_vtn.size() - 1;
out_indices.push_back( newIndex );
VertexToOutIndex[temp_vtn] = newIndex;
}
}
}
// Funcion que busca un vertice igual al enviado en un mapa y devuelve su valor si lo encuentra
bool Mesh::getSimilarVertexIndex(
VertexTextureNormal &packed,
std::map<VertexTextureNormal,GLuint> &VertexToOutIndex,
GLuint &result
){
// Si encuentra el packed, asigna al index(result) el val
std::map<VertexTextureNormal,GLuint>::iterator it= VertexToOutIndex.find(packed);
if ( it == VertexToOutIndex.end() ){
return false;
}else{
result = it->second;
return true;
}
}[/CODE]
0

Share this post


Link to post
Share on other sites

My understanding, although I have never done it personally, is that you can have as many shaders as you like, but only one main function.

 

So, you could have:

 

//shader1.fs <- Separate files
SomeShaderFunc1()
{
}

//shader2.fs <- Separate files

SomeShaderFunc2()
{
}

//shader3.fs <- Separate files

SomeShaderFunc3()
{
}

//shader4.fs <- Separate files

main()
{
SomeShaderFunc1();
SomeShaderFunc2();
SomeShaderFunc3();
}

 

But not:

 

//shader1.fs <- Separate files

SomeShaderFunc1()
{
}

main()
{
SomeShaderFunc1();
}
 
//shader2.fs <- Separate files

SomeShaderFunc2()
{
}

main()
{
SomeShaderFunc2();
}
 
//shader3.fs <- Separate files

SomeShaderFunc3()
{
}
 
main()
{
SomeShaderFunc3();
}

 

 

And that is one main function in your fragment shader(s) and one in your vertex shader(s).

Edited by MarkS
0

Share this post


Link to post
Share on other sites

If you mean to combine the results of multiple shader programs into one, I think you will have to render the mesh to a texture with each shader program, and then blend the results together (probably using another shader program).

0

Share this post


Link to post
Share on other sites
Did you mean you want parts of your mesh to use one shader and parts of your mesh to use a different one? If that's the problem, then your only real solution is to organise your data in such a way that you can setup the first shader, then draw the required verts. Then setup the second shader and do another draw call.
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0