0

Multitexturing used to be easy and straightforward. You bind your textures, you call glBegin, and then you do your rendering, except instead of glTexCoord you call glMultiTexCoord for each texture. Then all of that got deprecated.

I'm looking around trying to figure out the Right Way to do it now, but all the tutorials I find, both from official Khronos Group sources and on blogs, all assume that you want to use the same set of texture coordinates for all of your textures, which is a highly simplistic assumption that does not hold true for my use case.

Let's say I have texture A and texture B, and I want to render the colors from texture B, in the rect rB, using the alpha values in texture A, in the rect rA, (which has the same height and width as rB, for simplicity's sake, but not the same Left and Top values), using OpenGL 3, without any deprecated functionality. What would be the correct way to do this?

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • First find a tutorial that uses shaders, VBOs and VAO then it should be clearer. `glBegin` and friends is deprecated. – ratchet freak Aug 11 '15 at 11:36
  • @ratchetfreak: Yes, I know it's deprecated. That's why I'm asking. All of the shader tutorials I've found so far have been useless, because they all assume you want the same rect for both textures. – Mason Wheeler Aug 11 '15 at 11:38
  • Well all you do is add another vertex attribute, another input stream to the shader and make use of those coordinates. They're treated just the same as the first set. – Robinson Aug 11 '15 at 11:48
  • Multi-texturing is easier and more straightforward now, in my opinion. You don't need a separate set of texture coordinates per-texture unit (though you can still do that if you want and clearly you do in this case). You don't need to setup faux-programmable combiners, etc. Just sample the textures using whatever variable you want for the coordinates and using whatever operations you want to combine the results. Maybe _easy_ isn't the right word, but it's very straightforward. – Andon M. Coleman Aug 11 '15 at 16:58
  • @AndonM.Coleman: Perhaps, but sometimes it just feels like Yet Another Case of the Khronos folks not understanding what "deprecate" means. It's supposed to mean "there's a more-or-less equivalent (but better) way to do this now, so switch to that," whereas all too much old-school OpenGL functionality has simply been *abandoned.* For example, I have yet to see any satisfactory replacement for `GL_QUADS`. (And before anyone says "just use triangles", any "solution" requiring you to pass 6 vertices per quad is not a satisfactory replacement for `GL_QUADS`, which required you to pass 4 per quad.) – Mason Wheeler Aug 11 '15 at 17:36
  • Triangle strips / fans have the same number of required vertices to draw a single quad, incidentally (fewer once you string multiple quads together) ;) These are preferred topologies on modern hardware anyway, because they maximize vertex re-use. Quads aren't completely deprecated (geometry shaders and tessellation still operate on them), they just aren't supported at the draw command level. Nothing's really been lost in the API, everything just got massively programmable and deprecation is a nice guiding hand that keeps you from doing non-hardware friendly things. – Andon M. Coleman Aug 11 '15 at 18:05
  • In the case of quads, I think the real reason they were deprecated is because no behavior was ever defined for drawing them when the 4 points didn't all exist in the same plane. Coming up with a standard behavior for this would very likely hurt performance. In parts of the pipeline where all 4 points are co-planar (GL can guarantee this when it's the thing creating the points), quads still exist. Anyway, the point is that deprecated stuff either simplified the API or sped things up on modern hardware. – Andon M. Coleman Aug 11 '15 at 18:12
  • @AndonM.Coleman: They're not "fewer once you string multiple quads together" because that would only work if each quad were adjacent to the previous one. But if you're drawing a large batch of quads, you're most likely working with 2D graphics, with stuff like sprites and tile maps, where that sort of adjacency doesn't exist and there's (AFAIK) no solution that doesn't require 6 vertices per quad on "up-to-date" OpenGL programming. – Mason Wheeler Aug 11 '15 at 18:14
  • 2
    Primitive restart indices will let you do that. In a strip/fan, you can insert a special number (e.g. -1) and the rasterizer will stop connecting the primitives and start a new primitive on the next index. It's not straightforward for sure, but if you're trying to hack something like that together it works. You're probably better off using a geometry shader though -- cut the number of points from 6 down to 1 :) – Andon M. Coleman Aug 11 '15 at 18:16

1 Answers1

1

In the shaders you simply declare (and use) an extra set of texture coordinates and a second sampler.

vec4 sample1 = texture(texture1, texCoord1);
vec4 sample2 = texture(texture2, texCoord2);

When specifying the model you add the second set of texCoords to the attributes:

glVertexAttribPointer(tex1Loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(texCoord1, Vertex));
glVertexAttribPointer(tex2LOC, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(texCoord2, Vertex));
ratchet freak
  • 47,288
  • 5
  • 68
  • 106