Help Using TexSubImage2d

Hey guys,

I’m kind of new to openGL programming, but what I have so far is a room I can walk around with some tiled textures on the walls and floor.

What I want to do is to have a painting on the wall, and would prefer to do that by overlapping a texture across the tiled brick, so I can manipulate room size independently from the size of the painting.

I am fairly sure that TexSubImage2D is the function I want to use to achieve this, but I am having trouble finding some usage examples for it. From what I have read, I gather that it is very similar to TexImage2D, in that it will assign a texture image to a texture object that is already bound. I assume that to use TexSubImage I would do the same thing. Here is some code I wrote for texture assignment (note that it is in MATLAB, not C++)

%% TEXTURE MAPPING
% Enable texture mapping
glEnable(GL_TEXTURE_2D);
%glShadeModel(GL_SMOOTH);

% Assign formatted images to image index
imIndex = {permute(uint8(imread('brick.jpeg')), [3 2 1]), ...
    permute(uint8(imread('painting1.jpg')), [3 2 1]), ...
    permute(uint8(imread('painting2.jpg')), [3 2 1]), ...
    permute(uint8(imread('carpet.jpg')), [3 2 1])};

% Generate a texture "object"
texname = glGenTextures(length(imIndex));

% Bind texture object to images from index
for i = 1:length(imIndex)
    glBindTexture(GL_TEXTURE_2D, texname(i));

    %Specify the image texture
    tmp = size(imIndex{i});
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tmp(2), tmp(3), 0, GL_RGB, GL_UNSIGNED_BYTE, imIndex{i});

    % Texture wrapping
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    % Setup filtering
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    % Specify a texture application function (this will control how light
    % reflects off the texture
    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
end

glBindTexture(GL_TEXTURE_2D, texname(2));
glTexSubImage2d(GL_TEXTURE_2D, 0, .5, .5, 25, 25, GL_RGB, GL_UNSIGNED_BYTE,imIndex{2});
    % Texture wrapping
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    % Setup filtering
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    % Specify a texture application function (this will control how light
    % reflects off the texture
    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

If you could let me know if this was done right, that would be great. If it was done right, I am kind of at a loss as to how to implement it onto the wall of the room I am rendering.

If it helps, here is the code which draws the room:

    % Clear buffer and bind texture
    glClear;
    glBindTexture(GL_TEXTURE_2D, texname(1));

    % Draw a sphere
    glPushMatrix;
    glTranslatef(0,0,-5.0);
    mysphere = gluNewQuadric;
    gluQuadricDrawStyle(mysphere, GLU_FILL);
    gluSphere(mysphere, .5,36,18);
    glPopMatrix;
   
    % DRAW A CUBE
    glBegin(GL_QUADS)
    % Vertex Vectors
    A = [-rx -ry rz];
    B = [rx -ry rz];
    C = [-rx -ry -rz];
    D = [rx -ry -rz];
    E = [-rx ry rz];
    F = [rx ry rz];
    G = [-rx ry -rz];
    H = [rx ry -rz];
    
    % Front face
    glNormal3d(0,-1,0);
    glTexCoord2f(tx,ty); glVertex3fv(B); % Top right
    glTexCoord2f(0,ty); glVertex3fv(A); % Top left
    glTexCoord2f(0,0); glVertex3fv(C); % Bottom left
    glTexCoord2f(tx,0); glVertex3fv(D); % Bottom right
    % Rear face
    glNormal3d(0,-1,0);
    glTexCoord2f(0,ty); glVertex3fv(E); % Top left
    glTexCoord2f(tx,ty); glVertex3fv(F); % Top right
    glTexCoord2f(tx,0); glVertex3fv(H); % Bottom right
    glTexCoord2f(0,0); glVertex3fv(G); % Bottom left
    % Ceiling
    glNormal3d(0,0,-1);
    glTexCoord2f(tx,0); glVertex3fv(A); % Bottom right
    glTexCoord2f(0,0); glVertex3fv(B); % Bottom left
    glTexCoord2f(0,ty); glVertex3fv(F); % Top left
    glTexCoord2f(tx,ty); glVertex3fv(E); % Top right
    % Right face
    glNormal3d(1,0,0);
    glTexCoord2f(0,ty); glVertex3fv(F); % Top left
    glTexCoord2f(0,0); glVertex3fv(H); % Bottom left
    glTexCoord2f(tx,0); glVertex3fv(D); % Bottom right
    glTexCoord2f(tx,ty); glVertex3fv(B); % Top right
    % Left face
    glNormal3d(-1,0,0);
    glTexCoord2f(0,0); glVertex3fv(G); % Bottom right
    glTexCoord2f(tx,0); glVertex3fv(C); % Bottom left
    glTexCoord2f(tx,ty); glVertex3fv(A); % Top left
    glTexCoord2f(0,ty); glVertex3fv(E); % Top right
    glEnd;
    % New Texture
    glBindTexture(GL_TEXTURE_2D, texname(4));
    glBegin(GL_QUADS);
    % Floor
    glNormal3d(0,0,1);
    glTexCoord2f(0,0); glVertex3fv(C); % Bottom left
    glTexCoord2f(tx,0); glVertex3fv(D); % Bottom right
    glTexCoord2f(tx,ty); glVertex3fv(H); % Top right
    glTexCoord2f(0,ty); glVertex3fv(G); % Top left
    glEnd;
    
    Screen('EndOpenGL', wPtr);
    Screen('Flip', wPtr);
    Screen('BeginOpenGL',  wPtr);

Thanks!

[QUOTE=angelonc;1249755]…overlapping a texture across the tiled brick…I am fairly sure that TexSubImage2D is the function I want to use to achieve this…gather that it is very similar to TexImage2D, in that it will assign a texture image to a texture object that is already bound.


    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tmp(2), tmp(3), 0, GL_RGB, GL_UNSIGNED_BYTE, imIndex{i});

    glTexSubImage2D(GL_TEXTURE_2D, 0, .5, .5, 25, 25, GL_RGB, GL_UNSIGNED_BYTE,imIndex{2});

[/QUOTE]

glTexImage2D = allocate and populate texels
glTexSubImage2D = populate texels only

glTexImage2D can be made to allocate only by passing a NULL pointer to the pixels argument if you want.

glTexSubImage2D can populate a “sub”-region of a texture – that is, only a portion of a texture MIP level. Thus the xoffset/yoffset parameters

Your glTexImage2D() looks good, though you could be more specific with the 3rd arg and specify which specific internal format you want (e.g. GL_RGB8).

The glTexSubImage2D() is close. However, xoffset and yoffset are integer texel offsets, so 0.5, 0.5 doesn’t make much sense. Also, its assumed you have a texture bound to the active texture unit that’s already been allocated, and your offsets and dimensions fit within the bounds of the allocated MIP level data (MIP level 0 in this case).

Thanks for your response!

So, if I am interpreting what you are saying correctly, this function will replace a sub region of a texture before drawing it, so any tiling processes specified when drawing will be applied to both the “base” texture and the subtexture?If so, this may not be the function I want, as I was looking to apply a single texture on top of a tiled texture (see image)

(for some reason it won’t let me embed my image URL, so here it is: imgur.com/JKpgzSX.jpg)

I suppose what I am most confused about is how to have my “base” texture active and then apply glTexSubImage2D to that texture… would I bind the texture that has already been allocated (glBindTexture) and then call glTexSubImage2D to allocate a subregion of that texture (as I did in the code in my original post)?

Then, from there, would I have a new texture object that has this subtexture applied to it, and I would bind that before I draw whatever polygon that I want it applied to?

Thanks!

would I bind the texture that has already been allocated (glBindTexture) and then call glTexSubImage2D to allocate a subregion of that texture

Like I said glTexImage2D is alloc and fill (think malloc+memcpy). glTex"Sub"Image2D is fill only (think memcpy). So the latter does not allocate. It merely replaces the contents of some/all texels in the existing texture.

To your more general question, if this texture is “wall specific” and your painting aligns with texels in the base wall texture map, then sure, you can use glTexSubImage2D to blast the painting textures on top of the correct region of the wall texture. Then just render the wall with the modified texture.

If not, then you have a number of possibilities for how to deal with it. glPolygonOffset is the classic way that has been used to apply a “layer” on top of another polygon like this. There’s also a projection matrix trick popularized by Eric Lengyel which causes rendering to that same depth value to use a slightly closer depth value in the depth buffer so it appears on top. Another option is to render the wall with the “painting area” stencilled out (masked out), and then render the painting. With this approach, there are no Z contention issues so you don’t have to worry about depth contention/offset issues. There are other techniques, but this should get you going.