Creating textures from separate channels?

Started by
10 comments, last by lwi 19 years, 4 months ago
Hi, I have a problem (duh.. really?) In the application I am building, the images are loaded in separate arrays for each color component (3 arrays for RGB, 4 for RGBA). Now, evidently I want to apply these images as a texture on a polygon in OGL, but glTexImage2D only accepts one array, and I assume it expects this array to be formated like "red byte, green byte; blue byte; red byte.. and so on". Is there a way, strictly in OGL, to create 3 textures, one for each channel, and combine them into one? I know I could butcher the 3 arrays I have to form someting acceptable by glTexImage2D, but I would like, if possible, to use OGL functions only in the hope that it would be hardware-accelerated. thanks in advance, Lwi
Advertisement
I cant think of a way and frankly I dont think it would be sane todo so, just combining them via the CPU seems like the sanest method, however without knowing more about the app I cant say more than that.

Is there some reason the image comes in in three/four channels?
I'm doing a video processing app and I need a preview window. The images need to be stored this way because of video processing api demands this. I am doing this in OGL because it is cross platform.

I just hope that combining the channels via CPU won't slow things down too much so that I could have a decent frame rate (~30fps, like regular video).

The problem with the CPU approach is that if I want to speed up things, I would have to pre-process all the images from the video, and have it stored in memory. But then I'd have the same data in 2 different formats in the memory at the same time. It seems counter-productive to me.

I'm still looking for a way to do this on OGL. What bothered me the most is to find out that using glTexSubImage2D for each channel with format = GL_RED, GL_GREEN and GL_BLUE respectiveley doesn't work because each call overwrites the 2 other channels with 0.0. I just wish there was a way to preserve the original value in the texture, or a way to do texture operations.

Would using multitexturing be overkill and/or inefficient?

Lwi
I guess the only way to test it would be to try it and see.

Multitexturing could work, as long as you can set up the combining properlu
Depending on the hardware you are targeting you might be able to do it with a fragment prorgam or simular
You could probably do something with shaders and have the GPU do the combination - but thats just a guess, I havn't played with shaders yet.

However, doing it with the CPU should be fast enough. In my video app I have to convert from YUV color space to RGB color space, which requires I go through the bitmap frame every time before I blit to a texture, and I still see FPS of around +200fps with a 512x512 size texture. I don't think a channel combining should be any more intensive than the coor space conversion, as long as you can optimise out as many mults/divs per pixel as possible.

This is encouraging, but my channel arrays are... floats! argh! I'm gessing you are dealing with unsigned chars. Those are much smaller ;)

I just tried it on a 1024x1024 image, and it takes 26 miliseconds. It's not completely bad, but too close to the 33ms needed to display 30 fps. I'm going to investigate the pixel shading avenue... though I never used that.

So much trouble for a simple preview window.. sigh...

Lwi
yeah, mine are unsigned chars, definately much faster than using floats :( Plus you have a 1024x1024 size, arg, I'm surprised you get 26ms. That definately cuts it very close to having to drop a bunch of frames to keep up decoding/blitting/other things.

One thing though, if you use the FPU (as in the case with floats) it is plenty fast, unless you are switching back and forth beteen to the CPU (as in other data types) and FPU constantly in a tight loop.

I'm not sure of the neccesary math required to combine channels (I havn't had to do that), but you could also probably use intristics to do multiple operations on multiple floats at one time. Which could cut your combining time down dramatically.

btw - which codec/API are you using? Maybe you should try something else, depending on your requirements. ffmpeg supports many codecs, and has some fast conversion routines. But it also has legality questions as far as patents go.

I currently use ogg theora, and find it pretty good.
There really isn't any math at all, just a shuffling of 3 [1024][1024]arrays to get a [1024][1024][3] float array. This shuffling takes 26ms. If there is a way to speed up the shuffling, I'm all ears, but I doubt intrinsics could help be there.

Speaking if the codec/image format I'm using, there is no alternative since it's the format required by the image processing algorithms.
I'd just multitexture it. Something like:
// texture unit 0glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);// texture unit 1glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);// texture unit 2glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);

for RGB or:
// texture unit 0glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);// texture unit 1glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);// texture unit 2glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);// texture unit 3glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);

for RGBA.

Those are untested, so they're probably not 100% correct.

Enigma
Enigma:

I tried your code, I know it was untested (btw, there is no such thing as GL_ADD_ARB, it's just GL_ADD :) ) but I have a few problems with it.

So here is my code as it is now:

glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);

// texture unit 1
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[1]);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);

// texture unit 2
glActiveTextureARB(GL_TEXTURE2_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[2]);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);

.. it doesn't display as it should.

Just to clarify my problem:

I have 3 textures, each containing a single channel. Each of their pixels are of the form:
R = (r, 0, 0) // texture 0
G = (0, g, 0) // texture 1
B = (0, 0, b) // texture 2

I need to add these 3 textures to get R+G+B = (r, g, b)

The code you supplied seems to make sense, but the colors dont display right. Also, the 'texture unit 2' portion doesn't do anything: I get the same result if I comment it out.

What I get is a strange amalgam of red and green which doesn't correspond a all to what I would get if I turned off the blue channel in Photoshop. It's hard to describe.

I would really appreciate if you helped me sort this out.

Lwi

This topic is closed to new replies.

Advertisement