Opengl textures with glDrawElements
-
-
There are a number of ways to do this but glDrawElements is not a magic bullet. It is just like glDrawArrays except that you have an index buffer that tells OpenGL which order to draw the vertices in.
Although the corners of a cube share the vertex positions they do not share normals or texture coordinates so you need to decide if using an index buffer is worth it here.
To get a different texture on each face you could use a 2D array texture and pass in an additional vertex attribute that is an index to which texture layer to use. Then in the fragment shader you use this index to sample from the correct texture for that face.
-
Hello again. This is what I've done so far:
@class Car
{
public:
Car();
...........
void draw(QGLShaderProgram &m_carShader, const QMatrix4x4 &projection, QMatrix4x4 orientation);
................
//car dimensions
qreal width_lower; //largura
qreal width_upper;
qreal length_lower; //comprimento
qreal length_upper;
qreal height; //altura//car construction QVector3D car_geometry[18]; GLint car_geometry_elements[30]; QVector3D car_glass_geometry[8]; QVector3D car_glass_left_lower; QVector3D car_glass_left_upper; QVector3D car_glass_right_lower; QVector3D car_glass_right_upper; QVector3D car_face_right_back_upper; //0 QVector3D car_face_right_back_lower; //1 QVector3D car_face_right_front_upper;//2 QVector3D car_face_right_front_lower;//3 QVector3D car_face_left_front_upper; //4 QVector3D car_face_left_front_lower; //5 QVector3D car_face_left_back_upper; //6 QVector3D car_face_left_back_lower; //7
...................
// texture
GLuint textures[6];
QVector<QVector2D> texCoords;
QList<QString> imageTexList;
};@constructor:
@//car dimensions
width_lower = 0.8; //largura
width_upper = 0.6;
length_lower = 1.8; //comprimento
length_upper = 1.0;
height = 1.2; //altura//car construction car_face_right_back_upper.setX(width_upper);car_face_right_back_upper.setY(-length_lower);car_face_right_back_upper.setZ(height);//0 car_face_right_back_lower.setX(width_lower);car_face_right_back_lower.setY(-length_lower);car_face_right_back_lower.setZ(0); //1 car_face_right_front_upper.setX(width_upper);car_face_right_front_upper.setY(length_upper);car_face_right_front_upper.setZ(height); //2 car_face_right_front_lower.setX(width_lower);car_face_right_front_lower.setY(length_lower); car_face_right_front_lower.setZ(0); //3 car_face_left_front_upper.setX(-width_upper);car_face_left_front_upper.setY(length_upper);car_face_left_front_upper.setZ(height); //4 car_face_left_front_lower.setX(-width_lower);car_face_left_front_lower.setY(length_lower);car_face_left_front_lower.setZ(0);//5 car_face_left_back_upper.setX(-width_upper);car_face_left_back_upper.setY(-length_lower);car_face_left_back_upper.setZ(height); //6 car_face_left_back_lower.setX(-width_lower);car_face_left_back_lower.setY(-length_lower);car_face_left_back_lower.setZ(0); //7 car_geometry[0] = car_face_right_back_upper; car_geometry[1] = car_face_right_back_lower; car_geometry[2] = car_face_right_front_upper; car_geometry[3] = car_face_right_front_lower; car_geometry[4] = car_face_left_front_upper; car_geometry[5] = car_face_left_front_lower; car_geometry[6] = car_face_left_back_upper; car_geometry[7] = car_face_left_back_lower; car_geometry[8] = car_face_right_back_upper; car_geometry[9] = car_face_right_back_lower; //car up car_geometry[10] = car_face_left_back_upper; car_geometry[11] = car_face_right_back_upper; car_geometry[12] = car_face_left_front_upper; car_geometry[13] = car_face_right_front_upper; //car bottom car_geometry[14] = car_face_right_back_lower; car_geometry[15] = car_face_left_back_lower; car_geometry[16] = car_face_right_front_lower; car_geometry[17] = car_face_left_front_lower; car_geometry_elements[ 0] = 0; car_geometry_elements[ 1] = 1; car_geometry_elements[ 2] = 2; car_geometry_elements[ 3] = 3; car_geometry_elements[ 4] = 4; car_geometry_elements[ 5] = 5; car_geometry_elements[ 6] = 6; car_geometry_elements[ 7] = 7; car_geometry_elements[ 8] = 0; car_geometry_elements[ 9] = 1; car_geometry_elements[10] = 0; car_geometry_elements[11] = 0; car_geometry_elements[12] = 6; car_geometry_elements[13] = 2; car_geometry_elements[14] = 4; // car texture images imageTexList.clear(); imageTexList.append(":/images/supercar_right.png"); imageTexList.append(":/images/supercar_front.png"); imageTexList.append(":/images/supercar_left.png"); imageTexList.append(":/images/supercar_back.png"); imageTexList.append(":/images/supercar_up.png"); imageTexList.append(":/images/supercar_down.png"); //car textures for: right, front, left, back, up, bottom for (int i=0;i<6;i++) { texCoords.append(QVector2D(0,1)); texCoords.append(QVector2D(0,0)); texCoords.append(QVector2D(1,1)); texCoords.append(QVector2D(1,0)); }@
-
Drawing the car:
@void Car::draw(QGLShaderProgram &m_carShader, const QMatrix4x4 &projection, QMatrix4x4 orientation)
{
orientation.translate(position);
orientation.rotate(rotation.x(), 1.0f, 0.0f, 0.0f );
orientation.rotate(rotation.y(), 0.0f, 1.0f, 0.0f );
orientation.rotate(rotation.z(), 0.0f, 0.0f, 1.0f );QGLWidget g; for (int j=0; j < 6; ++j) { textures[j] = g.bindTexture(QPixmap(imageTexList.at(j)), GL_TEXTURE_2D); } GLint matrixAttr = m_carShader.uniformLocation("matrix_shader"); GLint projAttr = m_carShader.uniformLocation("projection_shader"); GLint vertexAttr = m_carShader.attributeLocation("vertex_shader"); GLint color = m_carShader.uniformLocation("uColor"); GLint textureCoordAttr = m_carShader.attributeLocation("texCoord");
// GLint texElementAttr = m_carShader.attributeLocation("texElements"); // ????
m_carShader.setUniformValue( projAttr, projection ); m_carShader.setUniformValue( matrixAttr, orientation ); m_carShader.setAttributeArray(vertexAttr, car_geometry, 0); m_carShader.setUniformValue(color,car_color); m_carShader.setAttributeArray(textureCoordAttr, texCoords.constData()); //m_carShader.setAttributeArray(texElementAttr,textures); //error glBindTexture(GL_TEXTURE_2D, textures[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindTexture(GL_TEXTURE_2D, textures[1]); glDrawArrays(GL_TRIANGLE_STRIP, 2, 4); glBindTexture(GL_TEXTURE_2D, textures[2]); glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); glBindTexture(GL_TEXTURE_2D, textures[3]); glDrawArrays(GL_TRIANGLE_STRIP, 6, 4); glBindTexture(GL_TEXTURE_2D, textures[4]); glDrawArrays(GL_TRIANGLE_STRIP, 10, 4); glBindTexture(GL_TEXTURE_2D, textures[5]); glDrawArrays(GL_TRIANGLE_STRIP, 14, 4);
// glDrawElements(GL_TRIANGLE_STRIP, 15, GL_UNSIGNED_INT, car_geometry_elements);@
The shaders:
@attribute highp vec4 vertex_shader;
uniform mediump mat4 matrix_shader;
uniform mediump mat4 projection_shader;//variables for the car texture
//attribute mediump vec4 texElements; // ???
//varying mediump vec4 texElements_v; // ???
attribute mediump vec4 texCoord;
varying mediump vec4 texc;uniform mediump vec4 uColor;
varying highp vec4 Color;void main(void)
{
// texElements_v = texElements; //?????
texc = texCoord; // car texture
Color = uColor;
gl_Position = projection_shader * matrix_shader * vertex_shader;
}
@@//uniform highp vec4 Color;
varying highp vec4 Color;// car texture
//varying mediump vec4 texElements_v; // ???
varying mediump vec4 texc;
uniform sampler2D texture;void main(void)
{
gl_FragColor = texture2D(texture, texc.st);
//gl_FragColor = Color;
}@I tried passing the index textures to the shaders, but in line 27 from draw(), it fails because I cannot bind a GLint[] to a vec4 in the shader.
bq. To get a different texture on each face you could use a 2D array texture and pass in an additional vertex attribute that is an index to which texture layer to use. Then in the fragment shader you use this index to sample from the correct texture for that face.
I don't have clue how to select the texture in the fragment shader.
-
Bump on this. I am trying to accomplish a very similar task. Nor do I have a clue how to select the texture in the fragment shader. Online resources are quite disparate and I get a lot of conflicting data. Let me know if you've figured it out, or I will post my findings here
-
Still havent figured this out.
Only thing I can think of is to use several calls to glBindTexture() and glDrawElements() in a loop, with diferent geometry elements in each call, drawing only one texture per loop, but this would not bring any benefits over glDrawArrays(). Also it would be in client side, not in the shader. -
My thoughs exactly. I posted a similar question relegated to my project. Hopefully something will come out of it. I'm going to dig deeper into the graphics pipeline and let you know if I uncover anything
-
Here is probably the best resource on GLSL I can find:
http://www.lighthouse3d.com/tutorials/glsl-tutorial/pipeline-overview/