Mip Mapping!
by FruitBatInShades · in Torque Game Engine · 12/16/2004 (2:34 pm) · 10 replies
Ok, those of you who have been following my adventures into modelling know I'm pi$*ed off with it at the moment. So I thought I'd do something scary and look into the problem with the MIP Mapping. Doesn't help that I haven't touched C++ for 10 years, but what they hey, I like to learn in a fire :)
Question is "Where does it happen?" The code seems a bit vague so I'm asking if anyone has looked into this yet? If so, where were the routines? At the moment I'm looking at :-
gBitmap::bitmapExtrudeRGB_c()
GBitmap::extrudeMipLevelsDetail()
TextureManager::createMipBitmap()
GBitmap::extrudeMipLevels(bool clearBorders)
but i'm not sure what all the casting is about in this block:-
From what I've gleaned so far, it seems as if the MIPs are just quartered versions of the original, is that correct?
Question is "Where does it happen?" The code seems a bit vague so I'm asking if anyone has looked into this yet? If so, where were the routines? At the moment I'm looking at :-
gBitmap::bitmapExtrudeRGB_c()
GBitmap::extrudeMipLevelsDetail()
TextureManager::createMipBitmap()
GBitmap::extrudeMipLevels(bool clearBorders)
but i'm not sure what all the casting is about in this block:-
void bitmapExtrudeRGBA_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) const U8 *src = (const U8 *) srcMip; U8 *dst = (U8 *) mip; U32 stride = srcHeight != 1 ? (srcWidth) * 4 : 0;can anyone spare me 5 to explain the casting going on here, or the aim of the format? :o)
From what I've gleaned so far, it seems as if the MIPs are just quartered versions of the original, is that correct?
#2
Marrion
12/17/2004 (3:01 am)
@FruitBatInShades If you don't mind me asking, what are your problems with modeling? I must have missed your adventures.Marrion
#4
Knowing that it then makes sense that the src and dst pointers are byte pointers. An addition of stride to src moves the pointer from it's current row to the next row same column.
Looking at bitmapExtrudeRGBA_c(...) function myself it's doing a simple bilinear flitered mipmap operation.
This is averaging 4 pixels from the src texture. First it adds two adjacent pixels on the current then the two adjacent pixels in the row below it. It then it adds 2... i'll get to this in a moment. The right shift by 2 an optimization for integer division by 4... so when you see '>> 2' think '/ 4'.
So adding the pixel values and dividing by 4 makes sense... simple average. Well what is the +2? If you divide 2 by 4 you get a fraction 0.5. In essence what the + 2 does is round up the pixel value.
In closing this is simple mipmap generation... nothing weird. I've seen filters that round and others that don't, so just for kicks remove the +2 and see how that effects things. Other than that it means switching to other filtering techniques which are much more CPU intensive. In my experience the most effective way to tweak your mipmaps is to allow the artist to supply them for "trouble spots". I hope to see DXTn adopted by Torque to do just that.
12/17/2004 (3:33 am)
Well.... i usually break it down into an example. Lets say srcHeight and srcWidth are both 1024. This means srcHeight != 1 and stride is 'srcWidth * 4' or 4096. What is 4096? 4096 is the number of bytes to skip to get from the first row of pixels in the source image to the next row.Knowing that it then makes sense that the src and dst pointers are byte pointers. An addition of stride to src moves the pointer from it's current row to the next row same column.
Looking at bitmapExtrudeRGBA_c(...) function myself it's doing a simple bilinear flitered mipmap operation.
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
This is averaging 4 pixels from the src texture. First it adds two adjacent pixels on the current then the two adjacent pixels in the row below it. It then it adds 2... i'll get to this in a moment. The right shift by 2 an optimization for integer division by 4... so when you see '>> 2' think '/ 4'.
So adding the pixel values and dividing by 4 makes sense... simple average. Well what is the +2? If you divide 2 by 4 you get a fraction 0.5. In essence what the + 2 does is round up the pixel value.
In closing this is simple mipmap generation... nothing weird. I've seen filters that round and others that don't, so just for kicks remove the +2 and see how that effects things. Other than that it means switching to other filtering techniques which are much more CPU intensive. In my experience the most effective way to tweak your mipmaps is to allow the artist to supply them for "trouble spots". I hope to see DXTn adopted by Torque to do just that.
#5
I am hoping to do something similar to DDS, that is have the textures pre-mipped so the artist can draw the levels and get them right, I'm not sure whether it is the MIP or rendering that causes such a blur effect but it does look awful.
I'm still unsure where the mip is stored! Do we end up with the mip level being drawn back to the original image that has been resized or are they stored as seperate bitmaps?
12/17/2004 (3:41 am)
What a fantastic explanation Tom :) Thanks very much.I am hoping to do something similar to DDS, that is have the textures pre-mipped so the artist can draw the levels and get them right, I'm not sure whether it is the MIP or rendering that causes such a blur effect but it does look awful.
I'm still unsure where the mip is stored! Do we end up with the mip level being drawn back to the original image that has been resized or are they stored as seperate bitmaps?
#6
Looking further at the code it does use auto mipmapping on the hardware if available ( at least in TSE )... so depending on your card that filtering on the CPU may not be occurring.
12/17/2004 (3:58 am)
I've noticed the mipmap issue myself and found it really distracting... more so that other engines so i suppose there is some sort of issue. Looking further at the code it does use auto mipmapping on the hardware if available ( at least in TSE )... so depending on your card that filtering on the CPU may not be occurring.
#7
12/20/2004 (2:22 pm)
We are going to be adding support for loading DDS in TSE, so these sort of mipmap issues will get addressed... As is you could pretty easily write a wrapper around the PNG format that adds some extra header data specifying filtering modes and the like. TSE also supports annotating texture allocations with the sort of mipmapping you want performed on the image data.
#8
12/20/2004 (2:33 pm)
You might be able to write a wrapper Ben, I could not :(
#9
12/23/2004 (6:13 am)
Any idea on a practicaly way to help with this... even with a performance hit... as Tom said it is quite distracting... probably the only visual aspect I dislike in TGE
#10
Matthew - if you just have to have it, I'd hack up the mip generation stuff to look for files under some sort of naming convention (like appending _mip0, _mip1 to the filename), and then load those rather than generating things. Have you tried looking at your shape under the Torque Show Tool Pro? It's got some very powerful tools for visualizing mips and how they affect your model.
12/23/2004 (7:20 pm)
FBIS - it's a very trivial change. I realize that there are many levels of coder in this community, but this is really the sort of change that would take a newbie a few days to do, and an experienced Torque developer maybe 15 minutes.Matthew - if you just have to have it, I'd hack up the mip generation stuff to look for files under some sort of naming convention (like appending _mip0, _mip1 to the filename), and then load those rather than generating things. Have you tried looking at your shape under the Torque Show Tool Pro? It's got some very powerful tools for visualizing mips and how they affect your model.
Torque Owner Dracola