View Full Version : Is the profiler lying/can GL use previous binds/will...
Jones
2006.09.21, 09:01 PM
Sorry for creating so many new topics recently... But I'm combining several topics in one this time. ;)
I'm trying to add (what I think is) a cool feature to my terrain (as in heightmaps/mountains/etc...) class. This is a feature all game engines/3d basics should have if they use terrains. I say this because when I used to use Dark Basic the lack of said feature drove me crazy.
It basically works like this. The user can pass several texture units (another class, in this case) to the terrain along with a list of heights the length of the amount of textures. The terrain then uses 3D OpenGL textures to blend all those texture units into one and uses different depths in that texture as it renders the terrain. This creates a smooth blend between the grass and rock on the mountainside, etc...
This brings me to my questions.
a) Can the OpenGL profiler lie?
b) If OpenGL receives a corrupt/broken texture at glBindTexture, will it use the previously bound texture?
c) What *might* be the problem if OpenGL is only using one layer of a 3D texture?
I ask 'a' because in the profiler I see my 3D texture perfectly fine, but OpenGL is only using the last layer loaded.
This brings me to 'b' and more explaining. Here's what the coder might do:
TEXTURE grass_and_rock[2];
TERRAIN mountains;
float where_to_put_textures[2] = {0.0, 4.0};
grass_and_rock[0].Load("grass.tga");
grass_and_rock[1].Load("rock.tga");
mountains.LoadHeightmap("map.tga");
mountains.ApplyTextures(grass_and_rock, where_to_put_textures, 2);
// Pass the arrays with texture data, the heights to use textures, and a number
// that represents the number of textures.
Now, in it's current state, my code will draw the terrain using only the last loaded texture. (So in the example, "rock.tga".) The order I place them in the array has no effect, however if OpenGL was only using depth 0 then whichever was *first in the array* would be drawn.
If I've confused you by explaining poorly I'll try to clarify a bit here...
I could inverse the 0 & 1 in the above code (in the array) and the rock texture would still be drawn, despite the fact that 'ApplyTextures' would add the rock data to the final image data *last*.
Anyways, this leads me to believe that the rock is being drawn (or grass, if it is called last) because the GL texture unit for those two textures was the last valid one called. Meaning that the internal GL-tex for the terrain is being rejected for being smurfy or something, and the last bound is being taken. Make sense?
Thirdly, 'c'. If 'b' is a no (in other words OpenGL is *not* behaving that way...) then what *might* be wrong. This (meaning one layer in a 3D tex being used) has happened to me before, and I fixed it. I just can't remember how. Has this kind of thing happened to you before? How did *you* fix it? (Slap my brain until I remember... :p)
Thanks greatly for your posts! :D
OneSadCookie
2006.09.21, 09:08 PM
Well, that was totally confusing :p
Yes, the OpenGL profiler can lie, however it sounds like it's not in this case. The last successful call to glBindTexture will always win. If you think something is failing, use the OpenGL profiler's "break on error" feature to catch OpenGL errors as you make them.
Jones
2006.09.21, 09:48 PM
Well, that was totally confusing :p
Hehe, wait till I write the documentation for this stuff... :p
Yes, the OpenGL profiler can lie, however it sounds like it's not in this case. The last successful call to glBindTexture will always win. If you think something is failing, use the OpenGL profiler's "break on error" feature to catch OpenGL errors as you make them.
Thanks, I'll try that. :)
EDIT: Where might I find this "break on error" feature? I can't seem to find it...
EDIT 2: Found it. :)
Jones
2006.09.21, 10:09 PM
I'm not sure if that helped. But I did notice one thing, thanks to the profiler.
In my draw loop, glBindTexture is receiving '0' as the texture. That can't be right, and I'm not sure why it's listing it as such.
arekkusu
2006.09.21, 11:09 PM
for a) I think that Profiler is (more or less) doing glGetTexImage on your texture and then drawing it as a bunch of 2D quads. So it will show whatever data is there, regardless of the "completeness" state. Note that this is different than runtime OpenGL. Also, there is no reason why Profiler should work like runtime OpenGL. It is a tool, and the ability to see your texture data is useful. A "texture is incomplete!" warning might be a nice feature to add, though.
for b), what is supposed to happen is that if you bind an incomplete texture to a unit:
* in fixed function, texturing "acts as if it is disabled" for that unit.
* in programs/shaders, you should get black (0,0,0,1) for that unit.
So depending on how you are texturing you could see "the previous bound texture", if that means "the texture bound to the previous unit". But you shouldn't get the last "complete" texture you bound the current unit-- glBindTexture does not no-op if the texture is incomplete ("completeness" can't be known until you actually try to draw.)
Yes, this is confusing.
Jones
2006.09.22, 02:02 AM
As far as I can tell, it *looks* complete in OpenGL profiler, if that counts for anything. (No solid grey blocks of missing pixels...)
I'm going to force drawing on the second layer.
...
No effect.
Alrighty then... it's the binding going wrong. When I glGenTextures'd the unit in question, I passed it a real pointer to a GLuint rather than the address of a real GLuint, could that be the problem?
Thanks!
arekkusu
2006.09.22, 02:56 AM
Show the code you're using to load each layer into a slice of your 3D texture.
Frogblast
2006.09.22, 02:58 AM
Definitly check to see if any of the currently bound textures are Incomplete.
Also, passing a texture name of 0 into glBindTexture is perfectly OK, as long as that is what you intended to do. There is a default (and non-deletable) texture at name 0. This oddity is an ancient artifact from OpenGL 1.0, when texture objects didn't exist. There was no glGenTextures/glBindTexture. If you wanted to change which texture you were drawing with, you called glTexImage2D.
I'm not sure what you meant in your last post. The pointer you pass to glGenTextures must already point to valid memory. OpenGL will not allocate it for you.
Jones
2006.09.22, 10:58 AM
Show the code you're using to load each layer into a slice of your 3D texture.
It's pretty long, so I'll snip it down to the area that I think is causing the trouble.
// Returns a 3D OpenGL texture unit based on TEXTURE arrays.
TEX_RESULT_COMP3D Construct3DTexture( GLuint *target, GLsizei depth,
TEXTURE *texs ) {
/* SNIP */
// Tell GL to make some room for this texture.
glGenTextures(1, target);
glBindTexture(GL_TEXTURE_3D, (GLuint)target);
// Mipmap it?
if (t_filt > 1) {
// These are fixed.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); // Clamp is neccessary
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); // for 3d texturing,
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); // over repeat.
// These are variable.
// The second is not, because it has a limit of detail.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[t_filt]);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[1]);
// Use GLU to send the data to GL.
gluBuild3DMipmaps( GL_TEXTURE_3D, t1_components, t1_width, t1_height,
numberToUse, t1_format, t1_type,
tex_dat );
}
// Don't mipmap it?
else {
// These are fixed.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); // See above for note on
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); // usage of GL_CLAMP.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// These are variable.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[t_filt]);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[t_filt]);
// Send the data to GL directly.
glTexImage3D( GL_TEXTURE_3D, 0, t1_components, t1_width, t1_height, depth, 0,
t1_format, t1_type, tex_dat );
}
/* SNIP! */
}
akb825
2006.09.22, 02:37 PM
When you bind the texture, don't cast the pointer to GLuint, you need to dereference it. (with *) Just FYI, whenever you have a pointer, and a function takes the type it's pointing to, you always dereference it. I have yet to see an instance where you need to cast a pointer into the type it's pointing to. The closest you will ever get is casting a pointer to a long to hold it in an integer for a while, where you'd then cast it back into the pointer in order to get that pointer back. (why you'd ever do that I don't know, but at least it's valid)
BTW, is target actually pointing to anything? Do you pass in the address to a GLuint that you stored somewhere else when calling that function, or did you just declare a pointer and pass that in? That, too, could cause a problem, but I know for a fact your call to glBindTexture is causing a major problem.
Jones
2006.09.22, 06:06 PM
No it was an actual GLuint, not a pointer. Thanks for the tip on the de-referencing though. I'll try that.
...
Ok, deref'd the pointer. The program still loads and displays with one texture. When I run it through OpenGL profiler *all* the glBindTexture calls seem to receive 0 as the target, and it will always crash when run in the profiler.
I'm still not sure what's happening here. It's not my texture depth generation code, I've dropped all the array values into exel and they all line up the way they should. OpenGL just *does not* use the 3D texture.
akb825
2006.09.22, 06:43 PM
I don't know, this looks an awful lot like a pointer to me:
GLuint *target
Regardless, glGenTextures must have a pointer, so regardless one will be wrong, even if you mistyped the function declaration. You will need to pass in a pointer, just to use glGenTextures, but you then need to dereference it for whenever you use something like glBindTexture.
Jones
2006.09.22, 06:47 PM
I do. It's not a pointer when being used to draw, only that once, in the construction of the 3D texture.
*target receives a value like this: &x where x is the texture unit of the terrain (which is *not* a pointer).
A quick test revealed that OpenGL is indeed using the last bound texture, I tested this by binding the grass texture after both had been loaded, and then drawing the terrain. I got grass.
This confirms my worst fear. There is something wrong with the way I'm giving OpenGL the textures. And it's not a memory error, so I'm not sure *how* to debug it. :p
EDIT:
glGetError says that right after the calls to glGenTextures and glBindTexture that there is no error, and none after the call to glTexImage3D.
Curious.
Jones
2006.09.22, 07:34 PM
The two images match in every way so it's not that...
Here, take a peek for yourselves:
256 // widths
256
256 // heights
256
3 // components
3
6407 // format
6407
5121 // type
5121
The values come in sets of identical twos, and they all match up. Next I'm gonna write out all the code for making the 3D texture manually. I've actually done this for the same two textures in a demo project and it worked.
I'm betting it's the pointer stuff. Perhaps instead I shall re-write the function itself to not use pointers.
EDIT: Tried it, seems it's not the pointer stuff.
LongJumper
2006.09.22, 10:29 PM
I'm confused. Are you trying to to bind two textures and then draw them both onto the same geometry?
If that is the case, you will need to use multitexturing, which is not the same as:
glBindTexture(1)
glBindTexture(2)
draw()
Jones
2006.09.22, 11:58 PM
I'm confused. Are you trying to to bind two textures and then draw them both onto the same geometry?
If that is the case, you will need to use multitexturing, which is not the same as:
glBindTexture(1)
glBindTexture(2)
draw()
No, I am using 3D texturing. This means I am stacking the two images and choosing which depth value to use when drawing. In the end it means you can do something like this:
glBindTexture(GL_TEXTURE_3D, myTex);
glBegin(GL_QUADS);
glTexCoord3f(0.0, 0.0, 0.0); // Top left of top texture.
drawVertex();
glTexCoord3f(1.0, 1.0, 1.0); // Bottom right of next texture down.
drawVertex();
glEnd();
The end result would be a blend going from the top left to the bottom right, spanning both textures. It's very cool. :)
However, I'm having some difficult problems with it. Namely: It's not working and I can't track down the problem. :p
EDIT: Got you a pic. Those are my two images, blending properly in my *other* project. I'm trying to get them to work on my terrain.
http://homepage.mac.com/gareth.cross/stuff/3d_tex.png
Frogblast
2006.09.23, 01:27 AM
No, I am using 3D texturing. This means I am stacking the two images and choosing which depth value to use when drawing. In the end it means you can do something like this:
You should _really_ be doing this via multitexturing, and not with 3D textures. Performance is likely to be significantly better, it'll expand to further effects easier, and you won't run into mipmapping issues.
Furthermore, multitexturing is has much wider hardware support than 3D texturing.
Jones
2006.09.23, 02:38 AM
You should _really_ be doing this via multitexturing, and not with 3D textures. Performance is likely to be significantly better, it'll expand to further effects easier, and you won't run into mipmapping issues.
Furthermore, multitexturing is has much wider hardware support than 3D texturing.
Multi-texturing, you say? Hmm. I'll look into it. I've never really done any of it before, but it sounds like it'll be fun to learn. I'll sift through some of the references at NeHe.
Any tips you'd like to give on the subject?
akb825
2006.09.23, 03:30 AM
Multitexturing in this case is only really easy to do with 2 textures, and you can only reliably get up to 3 or 4 if you're creative. (4 max, though, unless you don't want to support any NVidia cards. :p) However, with terrain, you can use 3D textures for almost any number of layers. If you have 8 different terrain layers, for instance, it would be impossible to do with multitexturing on anything but on the Radeon 9600 or later. (and no NVidia cards) However, it would be a simple matter with 3D textures. I can't say anything on performance, though, especially since there doesn't seem to be much information in general on the internet about 3D textures.
OneSadCookie
2006.09.23, 05:07 AM
If you have 8 different terrain layers, for instance, it would be impossible to do with multitexturing on anything but on the Radeon 9600 or later. (and no NVidia cards)
Kinda misleading -- NVidia only exposes four texture units through the fixed-function pipeline, but they support many more via shaders.
Jones
2006.09.23, 12:45 PM
And it would seem that multitexturing is an extension, whereas 3D textures have been in the core since 1.3 (or was it .4? :wacko: ).
I'll stick with that I'm doing for now, but I will investigate Multi-Texturing as it seems it is necessary for bump-mapping. Another 3D feature I've always loved in games.
Jones
2006.09.23, 01:38 PM
No success yet, my Construct3DTexture builds texture units that I can't even get to work on simple 4-vertex quads, let alone my massive terrain.
I'm gonna post the source code here. I hate doing this because it makes me feel like I'm giving up and asking you guys to solve my problems for me (:(), but I'm stumped. Perhaps you can spot something. :\
I'll try to help here by explaining how stuff works. Each 'TEXTURE' item has OpenGL compatible values that could be used at any time to re-bind the texture to another GL unit. The pixels item is a pointer to the array of data. (Which *is* kept around inside the 'TEXTURE'.
The arguments of the function are fairly self-explanatory. Depth is number of textures being passed in. '*target' is the destined GLuint. (For the texture.)
The TEX_RESULT_COMP3D struct has only two items. 'tex_used_count' which is the number of textures that were successfully bound. 'tex_used' is an array of fixed size (128 ints). It works like this:
Joe-Bloe passes in three textures. The middle one is bad, so the struct contents would be sorta like this:
tex_used_count = 2
tex_used = {1, 0, 1, 0, 0, 0, 0, 0, ... etc }
A one indicates that the texture item <place of n> *was* used. I know, they could be shorts or chars to save memory but I stuck with ints, and frankly, it's no important right now.
If you are reading this code and you get to the part where there is an if loop that checks to branch *with* mipmapping or *without* you can ignore the option that confirms mipmapping. It is not being used to test right now. (If you *do* spot something wrong with it though, please, speak out.)
RAYNE_ITL_TEX_FILTER_GL_TRANS is quite simply an array to convert Rayne (which is what I nicknamed the engine) texture filter values to OpenGL ones. I hope the rest is reasonably clear, I commented a lot, but I know some of my comments are less than useful.
I also know the code is not very efficient, but I'll fix that once the rest is actually working. Thanks for any insight you can offer.
// Returns a 3D OpenGL texture unit based on TEXTURE arrays.
TEX_RESULT_COMP3D Construct3DTexture( GLuint *target, GLsizei depth,
TEXTURE *texs ) {
// Result.
TEX_RESULT_COMP3D out_t;
out_t.tex_used_count = 0; // Zero this by default.
for (int zt = 0; zt < 128; zt++) {
out_t.tex_used[zt] = 0;
}
// Check depth.
if (depth == 0) {
out_t.tex_used_count = -1;
return(out_t);
}
// Allocate a list for building the texture.
int numberToUse = 0;
int useThese[128];
for (int z = 0; z < 128; z++) { // Zero this array.
useThese[z] = 0;
}
/*int *useThese;
useThese = (int*)new int[depth];
if (useThese == NULL) {
out_t.tex_used_count = -1;
return(out_t); // Not enough memory.
}*/
// First check if any of the textures are null.
for (int tc = 0; tc < depth; tc++) {
if (texs[tc].pixels == NULL) { // No good.
// Ignore this one.
useThese[tc] = 0;
}
else { // Useful.
useThese[tc] = 1;
numberToUse++; // We have another good one.
}
}
// Any good ones at all?
if (numberToUse == 0) {
//delete useThese;
out_t.tex_used_count = -1;
return(out_t);
}
// Declare some texture properties.
GLsizei t1_width = 0;
GLsizei t1_height = 0;
GLint t1_components = 0;
GLenum t1_format;
GLenum t1_type;
GLubyte *tex_dat;
TexFilter t_filt;
int gotItHere = -1; // Negative one by default.
bool gotOne = FALSE;
// Now get the first valid one in the list.
for (int fc = 0; (fc < depth) || (!gotOne); fc++) {
if (useThese[fc] == 1) { // Good one.
t1_width = texs[fc].width;
t1_height = texs[fc].height;
t1_components = texs[fc].components;
t1_format = texs[fc].format;
t1_type = texs[fc].type;
t_filt = texs[fc].filter_r;
gotItHere = fc;
gotOne = TRUE; // Don't bother getting the next.
}
else {
// Bad, do nothing.
}
}
// Alright, at this point we find out which ones are good.
for (int cc = gotItHere; cc < depth; cc++) {
if ( (texs[cc].width != t1_width) || (texs[cc].height != t1_height) ||
(texs[cc].components != t1_components) || (texs[cc].format != t1_format) ||
(texs[cc].type != t1_type) )
{
// It's not a match, chuck it.
useThese[cc] = 0;
numberToUse--;
}
else {
// It's a keeper, do nothing.
}
}
// At this point we have a list of all the textures which can be combined to form the stack.
// Let's alloc some memory.
tex_dat = (GLubyte*)new GLubyte[numberToUse * t1_width * t1_height * t1_components];
// And check our allocation.
if (tex_dat == NULL) {
out_t.tex_used_count = -1;
//delete useThese;
return(out_t);
}
int imgs_counted = 0; // This will count how many images.
int img_dat_incr = t1_width * t1_height * t1_components; // How many bytes per image?
// Combine all available data.
for (int mc = 0; mc < depth; mc++) {
if (useThese[mc] == 1) { // Yes to process.
// Copy the image into this array.
for (int bc = 0; bc < img_dat_incr; bc++) {
// Each image size * the images counted + the bytes of this image.
tex_dat[(img_dat_incr * imgs_counted) + bc] = texs[mc].pixels[bc];
}
// Update the images counted.
imgs_counted++;
}
else {
// No to process, do nothing.
}
}
// Tell GL to make some room for this texture.
glGenTextures(1, target);
glBindTexture(GL_TEXTURE_3D, *(target));
std::cout << "Construct3DTexture: Asked OpenGL to generate and bind texture unit." << std::cout;
std::cout << "Construct3DTexture: Last OpenGL Error: " << glGetError() << std::endl;
std::cout << "Construct3DTexture: GL Texture unit value: " << target << std::endl;
// These are fixed.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); // Clamp is neccessary
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); // for 3d texturing,
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); // over repeat.
// Mipmap it?
if (t_filt > 1) {
// These are variable.
// The second is not, because it has a limit of detail.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[t_filt]);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[1]);
// Use GLU to send the data to GL.
gluBuild3DMipmaps( GL_TEXTURE_3D, t1_components, t1_width, t1_height,
numberToUse, t1_format, t1_type,
tex_dat );
}
// Don't mipmap it?
else {
// These are variable.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[t_filt]);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, RAYNE_ITL_TEX_FILTER_GL_TRANS[t_filt]);
// Send the data to GL directly.
glTexImage3D( GL_TEXTURE_3D, 0, t1_components, t1_width, t1_height, numberToUse, 0,
t1_format, t1_type, tex_dat );
std::cout << "Construct3DTexture: Asked OpenGL to construct 3D texture." << std::cout;
std::cout << "Construct3DTexture: Last OpenGL Error: " << glGetError() << std::endl;
}
// Sort this out.
// By that I mean make some results for the user.
out_t.tex_used_count = numberToUse;
int o_count = 0;
for (int rc = 0; rc < depth; rc++) {
if (useThese[rc] == 1) {
out_t.tex_used[o_count] = rc;
o_count++;
}
else {
// Nothing.
}
}
// Done.
delete tex_dat;
return(out_t); // Returns how many were valid.
}
EDIT: (Thought I'd add...) The 3D texture looks fine in the profiler, but the app can't use it. I remember TommorowPlusX having some trouble with the profiler showing something working when it wasn't. If I remember correctly it had to do with 3D texturing too. Is something like happening now?
'Jones :)
akb825
2006.09.23, 02:11 PM
Kinda misleading -- NVidia only exposes four texture units through the fixed-function pipeline, but they support many more via shaders.
That is true, but if you were looking for compatibility, you wouldn't want to rely on pixel shaders. ;)
BTW, according to the man page of glTexImage3D, it's available since OpenGL 1.2. Multitexturing was introduced as an extension in as early as 1.1, but then rolled into the core in 1.3.
Edit: oh, and before you consider bump mapping, you're going to have to learn about shaders. :) (it's not just some magical setting you can turn on) As to your current problem, what does it look like when it breaks?
unknown
2006.09.23, 03:14 PM
you dont need shaders to do bump mapping.
arekkusu
2006.09.23, 04:12 PM
However, with terrain, you can use 3D textures for almost any number of layers.
Sure, as long as you don't use mipmapping.
If you have 8 different terrain layers, for instance, it would be impossible to do with multitexturing on anything but on the Radeon 9600 or later.
You can draw an infinite number of layers on any video card. Just break them into (layers/MAX_TEXTURE_UNITS) passes, blending each pass. This is how everybody did it before multitexturing existed.
Jones
2006.09.23, 04:36 PM
Edit: oh, and before you consider bump mapping, you're going to have to learn about shaders. :) (it's not just some magical setting you can turn on) As to your current problem, what does it look like when it breaks?
I know about the difficulties of bump-mapping. Over at NeHe they use something like 6 different texture units to accomplish it. :wacko: Can't wait!
Take a look at this sample code:
glBindTexture(GL_TEXTURE_3D, other);
glBegin(GL_QUADS);
glTexCoord3f(0.0, 0.0, 0.0);
glVertex2i(0, 0);
glTexCoord3f(1.0, 0.0, 5.0);
glVertex2i(256, 0);
glTexCoord3f(1.0, 1.0, 5.0);
glVertex2i(256, 256);
glTexCoord3f(0.0, 1.0, 0.0);
glVertex2i(0, 256);
glEnd();
glFlush();
glutSwapBuffers();
That results in:
http://homepage.mac.com/gareth.cross/stuff/bad_3d_result.png
On the terrain it's the same, but of course, on a terrain. :p
Jones
2006.09.23, 04:52 PM
Um guys... promise me you won't slap me...
You'd be amazed at what forgetting to but glEnable(GL_TEXTURE_3D) can do to a program with 3D textures. :blush: :blush: :blush: <triple-plus-embarrassment>
Sorry guys. :(
It ain't perfect yet though...
http://homepage.mac.com/gareth.cross/stuff/jagged.png
JAGGIES! :p
Jones
2006.09.23, 04:59 PM
Hey wow, I invented a super cool effect :p (Not really.)
http://homepage.mac.com/gareth.cross/stuff/lines_stuff.png
Lines! I remember that that game "Tribes" would do the same thing if you enabled OpenGL acceleration. I see why now. It actually looks pretty sweet, in my opinion. Very 'techno nature'.
You'll notice there is more grass than rock. This is because, like arreksu said, you cannot mipmap 3D textures. It only uses rock if you're close to it. But it's still sweet.
Thanks all for your help!
Jones
2006.09.23, 05:03 PM
Check out this glow effect I get with linear-non-mipmapped filtering.
http://homepage.mac.com/gareth.cross/stuff/more_lines_weird.gif
And I still get lines too, funny. I think I'll need to dynamically switch between GL_REPEAT and GL_CLAMP. :shock:
akb825
2006.09.23, 05:14 PM
Sure, as long as you don't use mipmapping.
What's wrong with mipmapping? I though TomorrowPusX was able to get it working.
Jones
2006.09.23, 05:17 PM
What's wrong with mipmapping? I though TomorrowPusX was able to get it working.
Me too, actually. He didn't use gluBuild3DMipmaps though, I bet. (I'm a wee bit lazy. ;) )
I fixed my problem with the lines. This is actually a useful bit of info for you guys (incase you didn't already know).
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
Is the solution. :)
akb825
2006.09.23, 05:46 PM
You probably could build your own, scaling down the width and height and not depth. I will probably try that whenever I get the chance, since I really don't want to handle interpolating between 6-8 textures. :wacko: (all I have to do, though, is find an algorithm to downscale an image... :sneaky:)
Edit: never mind, you can't do that. You must reduce the r as well. So, TomorrowPlusX, how did you do it? Meanwhile, I'll look up solutions to get massive multitexture interpolation implemented...
Editx2: messing around with the LOD bias might prove useful, too
OneSadCookie
2006.09.23, 07:13 PM
And it would seem that multitexturing is an extension, whereas 3D textures have been in the core since 1.3 (or was it .4? :wacko: ).
Whether it's an extension or not is completely irrelevant. What matters is hardware support. Multitexturing is supported by everything Mac OS X supports; 3D textures are not.
In any case, everything we've discussed was once an extension --
ARB_multitexture and ARB_texture_env_combine, promoted to core in 1.3
EXT_texture_3D, promoted to core in 1.2
ARB_shading_language_100 & friends, promoted to core in 2.0
arekkusu
2006.09.23, 10:16 PM
You probably could build your own, scaling down the width and height and not depth.
No, you can't. All dimensions are halved at each mipmap level, no matter what you want. That is what the spec says. Go read the other thread.
akb825
2006.09.23, 11:47 PM
Read my edit, I corrected myself.
Jones
2006.09.24, 01:10 PM
Yes, I remember TommorowPlusX's thread on the subject.
Well my code works sorta. With 3 textures it throws a 1280 and a 1281 (gl errors) which are the equivalents of GL_INVALID_ENUM and GL_INVALID_VALUE, respectively.
I'm trying to track them down but it's tough, when I call glGetError at various places sometimes I get 0's where they weren't before. Does calling glGetError automatically clear the error value?
arekkusu
2006.09.24, 02:31 PM
Yes, GetError pops one error bit. There can be multiple bits set simultaneously though.
akb825
2006.09.24, 02:58 PM
I suggest declaring a static (or global) variable so that you only cal glGetError once in your drawing function. (aka: only cal glGetError if it's TRUE, and have it originally FALSE and set it to TRUE when you call glGetError) Then, move the call around until you get the exact place (or places) where the error occurs.
OneSadCookie
2006.09.24, 06:04 PM
... or you could just use the OpenGL profiler's "break on error" to go to exactly the call that generated the error, rather than using a tedious, time-consuming and error-prone process like that...
Jones
2006.09.24, 10:54 PM
Well, I tracked that error down, but now I've got more.
It seems that whenever I enable GL_TEXTURE_3D, standard 2D textures stop working. I can't bind them, load data into them or draw them.
Hmm, unpleasant surprise. I'm gonna have to write some methods in that dynamically switch between 2D and 3D so I can use both.
Annoying. :\
EDIT: I've just had a thought. That's not possible, I think. Because I was just loading 2D textures and then making 3D textures... or was I? *runs off to test*
akb825
2006.09.24, 11:05 PM
Were you sure to call glDisable(GL_TEXTURE_3D) after being finished with 3D textures, and call glDisable(GL_TEXTURE_2D) after being finished with 2D textures? (aka: do you ever have more than one enabled at once?) You should only have 1 texture type enabled for each texture unit enabled at 1 time.
OSC: Thanks for the info on OpenGL profiler, I didn't know that. (of course, almost all of my debugging is done through print statements coupled with stack backtraces... :sneaky:)
OneSadCookie
2006.09.24, 11:05 PM
For textures, there is a precedence order for which one "wins" if you have multiple kinds glEnable'd at the same time. TEXTURE_3D is quite high on that hierarchy.
You shouldn't ever care though -- only enable one texture target at once!
Beaten by akb825!
Jones
2006.09.24, 11:15 PM
It sort of works now, but for some reason adding more textures screws up the GL_TEXTURE_2D/3D thing. I guess I'll just keep changing targets. So it might look like this:
glEnable(GL_TEXTURE_2D);
// load 2d tex
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_3D);
// load 3d tex
glDisable(GL_TEXTURE_3D);
glEnable(GL_TEXTURE_2D);
// draw 2d tex...
//etc...
akb825
2006.09.24, 11:54 PM
You don't need to call glEnable with a texture type when you're loading, only drawing.
Jones
2006.09.25, 01:36 AM
You don't need to call glEnable with a texture type when you're loading, only drawing.
Ah, even better. Thanks for the tip.
Jones
2006.09.26, 07:37 PM
Perhaps my understanding of 3D textures is crap, but I don't think this code:
glBegin(GL_QUADS);
glTexCoord3i(0,0,0);
glVertex2i(0,0);
glTexCoord3i(1, 0, 1);
glVertex2i(256,0);
glTexCoord3i(1, 1, 1);
glVertex2i(256, 256);
glTexCoord3i(0, 1, 0);
glVertex2i(0, 256);
glEnd();
Should produce this:
http://homepage.mac.com/gareth.cross/stuff/wtf_tex3d.png
I'm asking for the first two textures which are grass and rock. Brick should not appear, and neither should the random colors. (The random colors are a fourth texture, added to make the depth value a power of two.)
Am I doing something incredibly wrong or something?
Thanks!
akb825
2006.09.26, 07:43 PM
What is the value of depth when creating the texture? It looks like you're specifying 4 rather than 2, which causes those extra textures.
Jones
2006.09.26, 07:46 PM
The depth value is 4. I pass a depth of 3 to my function, but it automatically determines the nearest power of 2 and passes it. The extra space is filled with random pixels. The pixel data in the arrays goes like this:
256 * 256 * 3 bytes of picture one.
" " two.
" " three.
256 * 256 * 3 bytes of random pixel colors.
The '* 3' is for components, not BPP.
akb825
2006.09.26, 07:50 PM
You can't do that. If you want to have the 3 textures in there, you will need to keep a value of 4. In order to then only go between grass and dirt, you will need to go from 0 to 0.5. The r coordinate works the same way as the s and t coordinates, where it goes from 0 to 1 regardless of the dimensions. In order to use layer k out of n layers, you're going to need to use an r coordinate of k/(n - 1).
Edit: and to avoid memory issues, you're going to have to do one of two things: make sure that you have space allocated for 4 layers and pass that into glTexImage3D, or pass in NULL for glTexImage3D and use glTexSubImage3D to put in only the 3 textures. (which would also allow you to input the textures 1 at a time if you wanted)
Jones
2006.09.26, 07:51 PM
You can't do that. If you want to have the 3 textures in there, you will need to keep a value of 4. In order to then only go between grass and dirt, you will need to go from 0 to 0.5. The r coordinate works the same way as the s and t coordinates, where it goes from 0 to 1 regardless of the dimensions. In order to use layer k out of n layers, you're going to need to use an r coordinate of k/(n - 1).
*Stupid stupid stupid stupid me*.
Heh, I should have realized that. Jeeze. :p
Thanks!
akb825
2006.09.26, 07:53 PM
Wow, that was a quick response. Be sure to check my edit.
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.