PDA

View Full Version : Help Using TexSubImage2d



angelonc
04-10-2013, 04:11 PM
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!

Dark Photon
04-10-2013, 06:34 PM
...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});


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).

angelonc
04-11-2013, 09:21 AM
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!

Dark Photon
04-11-2013, 08:29 PM
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.