I have been trying to include multiple textures within my triangle strip, however, it seems to me that all calls to glBindTexture must be outside the glBegin(GL_TRIANGLE_STRIP) and glEnd().
Perhaps I could use a texture atlas, but I’d need help getting the new texture co-ordinates.
Here is my code and an image of the “desired” effect.
if (j % 2 == 0) // Second triangle
GL11.glTexCoord3f(0, 1, 0);
else
GL11.glTexCoord3f(0, 0, 0);
GL11.glVertex3f(j - xOffset, data[i][j] - yOffset, i - zOffset);
texture2.bind(); // This doesn't work, but out side the GL11.glBegin(GL11.GL_TRIANGLE_STRIP), it does :\
// We need to render the next strip to "link up" the two strips
if (j % 2 == 0)
GL11.glTexCoord3f(1, 0, 1);
else
GL11.glTexCoord3f(1, 1, 1);
GL11.glVertex3f(j - xOffset, data[i + 1][j] - yOffset, (i + 1) - zOffset);
Indeed, this doesn’t work that way. You can only bind a texture before any draw call.
The simplest solution to this is using a texture atlas and give appropriate texture coords for each vertex so that separate image appear on each primitive.
The more complicated one would be to use VBOs and use multiple sampler2D uniforms within the shader code - each vertex would then have to have an attribute indicating the texture unit it should use.
Otherwise you can search yourself, use keywords like: GLSL, VBO (Vertex Buffer Object), uniform, attribute, varying, programmable pipeline.
Keep in mind also that not every tutorial will work with every OpenGL version, so probably you will have to figure out what features to use depending on your target OpenGL version.
I’ve been quite busy recently, but unfortunately, my code isn’t working, here is my code and my shader:
Texture texture1 = new Texture(Terrain.class.getResourceAsStream("/resources/textures/grass.jpg"));
GL13.glActiveTexture(0);
texture1.bind();
Texture texture2 = new Texture(Terrain.class.getResourceAsStream("/resources/textures/stone.jpg"));
GL13.glActiveTexture(1);
texture2.bind();
Init.glFill();
useShader();
for (int i = 0; i < data.length - 1; i++) {
GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
for (int j = 0; j < data[i].length; j++) {
if (j % 2 == 0) // Second triangle
GL11.glTexCoord3f(0, 1, 0);
else
GL11.glTexCoord3f(0, 0, 0);
GL11.glVertex3f(j - xOffset, data[i][j] - yOffset, i - zOffset);
// We need to render the next strip to "link up" the two strips.
// If this is commented out, you would just have a load of strips
// that aren't connected.
if (j % 2 == 0)
GL11.glTexCoord3f(1, 0, 1);
else
GL11.glTexCoord3f(1, 1, 1);
GL11.glVertex3f(j - xOffset, data[i + 1][j] - yOffset, (i + 1) - zOffset);
}
GL11.glEnd();
}
stopShader();
Init.glLine();
texture1.unbind();
GL11.glEndList();
@dentmaged: What do you mean “doesn’t work”. No geometry on screen, not textured? I can tell you right now that you shouldn’t be loading the shader every frame.
You just need to convert everything to the pipeline way of doing things
Some comments
move
int shaderID = ShaderLoader.loadShaderPair("/resources/shaders/terrain.vs", "/resources/shaders/terrain.fs");
Texture texture1 = new Texture(Terrain.class.getResourceAsStream("/resources/textures/grass.jpg"));
Texture texture2 = new Texture(Terrain.class.getResourceAsStream("/resources/textures/stone.jpg"));
to your initialisation method
move
for (int i = 0; i < data.length - 1; i++) {
GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
for (int j = 0; j < data[i].length; j++) {
if (j % 2 == 0) // Second triangle
GL11.glTexCoord3f(0, 1, 0);
else
GL11.glTexCoord3f(0, 0, 0);
GL11.glVertex3f(j - xOffset, data[i][j] - yOffset, i - zOffset);
// We need to render the next strip to "link up" the two strips.
// If this is commented out, you would just have a load of strips
// that aren't connected.
if (j % 2 == 0)
GL11.glTexCoord3f(1, 0, 1);
else
GL11.glTexCoord3f(1, 1, 1);
GL11.glVertex3f(j - xOffset, data[i + 1][j] - yOffset, (i + 1) - zOffset);
}
GL11.glEnd();
}
in to 2 byte buffers, one containing the vertex data and one containing the texture coordinate data. Then create 2 VBO’s and pass these to your vertex shader
There is an excellent tutorial post from @riven describing different ways to do this
You then need to integrate these VBO’s in to your shaders so you can pass in the vertex/texture data to be drawn. You can do this in different ways depending on the shader version you want to use. I use the below way
layout(location = 0) in vec3 vertexData;
layout(location = 1) in vec2 textureData;
You can tell opengl to use the vertexData you pass (assuming no other manipulation of the data)
gl_Position = vertexData;
You then need to pass the texture data from the vertex shader to the texture shader and use that in the texture2D method you have. If you use a variable called theTextureData to pass this then you can extract the correct fragment by doing
texture(texture_number, theTextureData);
This should be enough to give you a very basic understanding of what to do, you can easily google to find the more detailed information